Merge tag '0.5.2+dfsg'
Upstream version 0.5.2+dfsg
This commit is contained in:
commit
7509079965
222 changed files with 108963 additions and 71711 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -2,7 +2,7 @@ Makefile
|
|||
|
||||
.waf-*
|
||||
.lock-wscript
|
||||
_build_
|
||||
_build
|
||||
|
||||
po/.intltool-merge-cache
|
||||
po/LINGUAS
|
||||
|
|
255
ChangeLog
255
ChangeLog
|
@ -1,5 +1,260 @@
|
|||
This file is licensed under the terms of the expat license, see the file EXPAT.
|
||||
|
||||
v0.5.2:
|
||||
Re-release with a proper version number and changelog
|
||||
|
||||
v0.5.1:
|
||||
Fix mouse gesture regression breaking context menu
|
||||
Fix --run command line switch by midori_paths_init
|
||||
Fix bug in size calculation for the history list popup
|
||||
Handle diagnostic dialog argument in running instance
|
||||
Fix feed panel default value crash
|
||||
Ensure existence of the applications directory
|
||||
Fix download tooltip crash and extend test case
|
||||
Integrate user interaction exploit demo in about:
|
||||
Don't convey loading or progress on special pages
|
||||
Address missing NULL checks and dead code found by clang
|
||||
No security window for blank pages, but a search icon
|
||||
Introduce UI for created apps/ launchers: Web App Manager
|
||||
Add custom-title setting to override browser title
|
||||
Add a Gtk.Entry to --plain mode for entering URLs
|
||||
Deprecate middle_click_opens_selection in favour of gtk-enable-primary-paste
|
||||
|
||||
Webkit2:
|
||||
Require 1.11.91 aka 2.0.0 for WebKit2
|
||||
Delayed load, clear favicons, clear HTTP cache, tab favicons
|
||||
Navigation policy, mouse buttons, security details
|
||||
basic cookies, download dialog, res://, stock://, print
|
||||
Zoom, default-charset, view-source, spell-check, prefetch
|
||||
Back/ forward, enable-java, plugin listing, web inspector
|
||||
v0.5.0:
|
||||
Store --execute arguments in string array
|
||||
Prevent overlay frame from being caught by show_all
|
||||
Unconditionally show Toolbar Style preference
|
||||
Duplicate current URI when reloading Midori.View
|
||||
Update tabs being closable on setting change in Granite
|
||||
Check default_search before setting SearchAction default
|
||||
Populate application chooser button in idle
|
||||
Bail out of completion resizing if cell height is 0
|
||||
Pass proxy to bookmark dialog when editing via menu
|
||||
Tweak bookmark dialog, button to buttons, toggles side by side
|
||||
Move 'Flash windows' option into History List
|
||||
Use light window for Clear Private Data with Granite
|
||||
Use GtkFontButton with filter func with GTK+ 3.2
|
||||
Implement 'Run in debugger' button in diagnostic dialog
|
||||
Add Win32 work-around to History List for modifiers
|
||||
Make toolbar drag/ drop work in GTK+3
|
||||
Check if active form element is input before getting search text
|
||||
Implement direction-based mouse gesture configuration
|
||||
Implement mouse movement, load-failed, crashed, search in WebKit2
|
||||
Add 'Show last crash log' button to diagnostic dialog
|
||||
Make invalid actions fail; exit on error in new process only
|
||||
Accept setting=value and extension=true/ false in --execute
|
||||
Merged cookie permissions as of 2013-03-08
|
||||
Gray out webGL preference if context is unavailable
|
||||
Use browser API to Close Other in view menu item
|
||||
Fix periods to ellipsis in Custom/ Customize Shortcuts
|
||||
Support Colorful Tabs in History List
|
||||
Add Midori.Tab.fg/ bg_color and Midori.View.set_colors
|
||||
Fix word-wrap, #decription and #message in about.css
|
||||
Set view scroll policy to Never to avoid flickering
|
||||
Use XDG_RUNTIME_DIR for temporary files
|
||||
Build Vala and C parts of core separately
|
||||
Don't provide default value for enable-scripts
|
||||
Respect Open new pages: window for Web Search and Open Image
|
||||
enable-javascript in WebKit1/ 2, macro for (Web)Settings
|
||||
Fix MIDORI_*_VERSION to be integers
|
||||
Fix .desktop file validation unit test and fix errors
|
||||
'New tab behavior' preference: about:dial/ new/ search/ home alias URLs
|
||||
Use stripped down XBEL variant for session and trash
|
||||
Allow any proxies supported by libproxy; list supported types in preferences
|
||||
|
||||
v0.4.9:
|
||||
Let non-Granite security window behave like a window
|
||||
Disable Contractor support in Granite for now
|
||||
Use cache_dir_for_reading in about:paths
|
||||
Strip LRE to prevent it from begin saved to disk
|
||||
Enable stripping 'referer' by default
|
||||
Fix crash on closing Adlock preferences dialog
|
||||
Bail on unset title in completion, fixing strchr urlbar crash
|
||||
Manage cookies accept policy per domain - not installed by default
|
||||
Don't store/ load stock:// icons for special pages
|
||||
Drop KatzeScrolled in favour of GTK+ 3.4 touchscreen support
|
||||
Write XBEL safely to prevent loss on eg. full disk
|
||||
Omit nspluginwrapper Netscape plugins from extensions
|
||||
Add --debug/ -g switch to run Midori in gdb
|
||||
List versions from about:version in --version
|
||||
Work in progress --enable-webkit2 option enabling WebKit2/ GTK+3
|
||||
Rename menu _Window to _Tabs
|
||||
Update Easylist subscription URL for Adblock
|
||||
Stop redundant tab numbering when adding
|
||||
Allow feed panel webview widget to shrink.
|
||||
Don't search for place holder text on cookie list rebuild
|
||||
Add 'Google Translate (gt)' as a search engine
|
||||
Default external Download Manager to "fetch" on FreeBSD
|
||||
Drop GCC-version specific -Wno-unused-but-set-variable
|
||||
Change X-Ayatana-Desktop-Shortcuts to Actions
|
||||
|
||||
v0.4.8:
|
||||
Fix un-delaying of tabs
|
||||
Support downloads with FlashGet on Win32
|
||||
Fix compilation with GLib 2.30
|
||||
Fix error handling in extensions
|
||||
Retain selection in urlbar when switching tabs
|
||||
Fix missing right-click menu on NextForward button
|
||||
Hide error page button if buttons have no images
|
||||
Rework URL completion: suggest open tabs
|
||||
Always highlight matches in inline search
|
||||
Pantheon: Only show private launcher in search
|
||||
Granite: Fix notebook, require 0.2, drop _about_dialog_new
|
||||
Don't include http(s), file or www. in page title
|
||||
Autodetect Twitter RSS feeds
|
||||
Adblock: Improve date parsing
|
||||
Unit test rework: backtraces, regardless of debugging, wine
|
||||
More accurate version numbers in about:version
|
||||
Drop obsolete --log-file command line switch
|
||||
Emit inspector attach-window with correct signature
|
||||
Fix Netscape plugins opening download dialogs
|
||||
Rework path handling and setup in different modes (fix segfaults)
|
||||
Manage Netscape plugins are individual extensions
|
||||
Address gtk_icon_set_render_icon_pixbuf assertions
|
||||
Fix renaming in speed dial with spaces in title
|
||||
Render completion title/ URL side by side with Granite
|
||||
Transparently use Favicon-/ IconDatabase/ file store per WebKit
|
||||
Add TabMoveFirst/ Last hotkeys (without defaults)
|
||||
Drop Hildon support
|
||||
Show URI in 'not responding' dialog
|
||||
Query search engine icons when loading, rather than stupid guesses
|
||||
|
||||
v0.4.7:
|
||||
Unify download behavior: link fingerprints, space check, clearing, tooltips
|
||||
GIO-based check for enough space and permissions, GIO-based themed icons
|
||||
Show opener/ tab domain in download dialog:
|
||||
http://lcamtuf.coredump.cx/fldl/ http://lcamtuf.coredump.cx/switch/
|
||||
Extension to download with a specific command line
|
||||
Size in download dialog and fallback filename heuristic
|
||||
|
||||
Windows: GTK+3, Faenza icons, gdb helper, Netscape plugins,
|
||||
ship CA bundle, fix View source, --portable/ -P on Windows
|
||||
Granite (Beta): about dialog, static notebook, no "New Tab" in toolbar, Print → Share
|
||||
Support building with Wayland-enabled GTK+3
|
||||
Theming: content view, secondary toolbar class, drop old icon names, bigger error icon
|
||||
Introduce --plain mode equivalent to GtkLauncher, lazy URLs for --snapshot/ -s
|
||||
Log bookmarks, history and downloads to zeitgeist
|
||||
|
||||
Show security details and export certificates with GCR, error out instead of colored urlbar
|
||||
Only allow data: URLs in urlbar for images
|
||||
Recognize and cache HSTS, system-wide /etc/xdg/midori/hsts
|
||||
Strip HTTP Host to outsmart some filter proxies
|
||||
|
||||
Completion: Fix PageUp/Down, Shift+Tab and wrap: This is consistent with GTK+ (excluding Tab) and Firefox
|
||||
Change Focus Current Tab to Ctrl+Alt+Home
|
||||
Fix Shift+Space for scrolling upwards
|
||||
Control+Alt+R: Readable mode
|
||||
Handle access key in link hints
|
||||
Drop speed dial keyboard access in favour of "." link hints
|
||||
|
||||
No Open, Bookmark bar, Customize toolbar, Inspect page in app menu; split panel menu
|
||||
Use ellipsises instead of period thresomes
|
||||
Hinted text in bookmarks, history and cookie manager
|
||||
Ellipsize panels (except for Transfers)
|
||||
Add icon to bookmark dialog and remove labels
|
||||
Validate proxy server IP and render invalid URLs in GTK+3
|
||||
Rename "Toplevel" folder to "Bookmarks"
|
||||
|
||||
Chrome identification option; "Automatic" user agent is Chrome-based
|
||||
Search: Create engines from search forms, remove "icon" field
|
||||
Copy Image s/Address// always copy both URL and data
|
||||
Rework debugging by introducing MIDORI_DEBUG; about:paths
|
||||
Adblock: Refresh filters based on file time and meta data, abp: links
|
||||
Optionally save website including resources
|
||||
Merged NextForward akin to StopReload
|
||||
PanedAction, Viewable, SpeedDial, (most of) Settings, Paths in Vala
|
||||
Improved database: requires sqlite 3.6.19 and 0.2.6 in import dialog
|
||||
|
||||
Confirm Caret Browsing before enabling it
|
||||
Support for custom items in Statusbar Features (see FAQ)
|
||||
Draggable favicon as URL or text, URL icon for URL entries
|
||||
Remember if inspector was attached
|
||||
Open tabs in the background by default
|
||||
RTL support in special/ error pages
|
||||
Fix progressbar text with GTK+3
|
||||
Build fix: More robust GTK+2 version check
|
||||
Ensure progress in urlbar and tab match
|
||||
Zoom text and images by default
|
||||
Don't mixup tokens starting with the same letters
|
||||
Seemless running out of build folder
|
||||
No speed dial in --app/ --private, fix layout with many tiles
|
||||
Add X-GNOME-Fullname to .desktop and translate desktop shortcuts
|
||||
Delayed Load extension
|
||||
|
||||
v0.4.6:
|
||||
+ Fix crasher in geolocation infobar
|
||||
+ Fix crasher in about:version on some systems
|
||||
+ Fix crasher opening bookmarks from Unity global menu
|
||||
+ Use WebKitFaviconDatabase as of WebKit 1.8.0
|
||||
+ Use midori-prefixed temp folder in midori_view_save_source
|
||||
+ Fix cancelling downloads with SteadyFlow or Aria2
|
||||
+ Fix crash dialog instead of opening tab in a running window
|
||||
+ Fix page icons in multi-frame sites (gmail, tumbler)
|
||||
+ Distinguish Simplified and Traditional Chinese
|
||||
+ Support go-jump-symbolic
|
||||
+ Handle empty tabs due to download links with a target
|
||||
+ Handle frame load interrupted in the unholy trinity
|
||||
+ Fix libsoup version check and wrong SSL status in location
|
||||
|
||||
v0.4.5:
|
||||
+ Work around black border around widgets on Win32
|
||||
+ Whitelist direct/ re-directed navigation requests in adblock
|
||||
+ Require Vala 0.14
|
||||
+ Provide geolocation diagnostics in about:geolocation
|
||||
+ List available about: URLs and app instance name in about:version
|
||||
+ Replace illegal characters in download filenames
|
||||
+ Tweak app options on Win32 and use ShellExecuteEx in sokoke_show_uri
|
||||
+ Use sokoke_show_uri in midori_browser_download_status_cb
|
||||
+ External Download manager Steadyflow and Aria2 (with cookies)
|
||||
+ Ensure adblock config folder when blocking images
|
||||
+ Use sqlite WAL mode for history if available
|
||||
+ Allow relative -c/ --config path
|
||||
+ Context menus on Back and Forward toolbar items
|
||||
+ Always show the tabbar by default
|
||||
+ Use ubuntu-bug if it exists
|
||||
+ Show inline find while typing and statusbar text in overlay with GTK+ 3.2
|
||||
+ Esc/ closing "downloads still active" should cancel, not continue
|
||||
+ Optional Granite support for notebook and bookmark dialog as pop-over
|
||||
+ Ctrl+j to toggle statusbar aka downloads
|
||||
+ Show at most 3 search engines in completion
|
||||
+ Don't replace existing onclick/ blur with autosuggest
|
||||
+ Implement low_memory_profile for FreeBSD and Win32
|
||||
+ Use var in internal javascript, to fix Google apps
|
||||
+ Handle download requests in frames
|
||||
|
||||
v0.4.4:
|
||||
+ Disable page cache with < 352 MB RAM
|
||||
+ Display filename in download dialog
|
||||
+ Fix box packing in GTK+3 (in most cases)
|
||||
+ Enable experimental HTML5 fullscreen API
|
||||
+ Harden IPv6 address recognition in location
|
||||
+ Experimental site data policy support (see FAQ)
|
||||
+ Close tabs by middle clicking close button
|
||||
+ Merge cookies and other data in Clear Private Data
|
||||
+ Improve KatzeArrayAction for Unity menuproxy compatibility
|
||||
+ Use GDateTime for history to avoid broken C runtimes
|
||||
+ Add Midori tag to DuckDuckGo default URI
|
||||
+ Rewrite completion popup resizing
|
||||
+ Streamline page icon loading stages and fallbacks
|
||||
+ Disable clipboard work-around for WebKit >= 1.4.3
|
||||
+ Re-word .desktop entry as an action
|
||||
+ Display informative text in private browsing
|
||||
+ Consistent clear icons in entries
|
||||
+ Revised download filename generation
|
||||
+ Add 'Open in Image Viewer' menu item
|
||||
+ Formhistory 2.0 with GDOM support
|
||||
+ Handle javascript: and mailto: links better
|
||||
+ Handle = key in Ukrainian layout better
|
||||
+ Fix bookmark export and deletion of bookmark folders
|
||||
+ Speed dial shortcut re-reordering by DND
|
||||
|
||||
v0.4.3:
|
||||
+ Implement about:widgets to test rendering
|
||||
+ Fix resizing of inspector by applying a minimum size
|
||||
|
|
38
INSTALL
38
INSTALL
|
@ -14,10 +14,10 @@ Run './waf build'
|
|||
|
||||
You can now run Midori from the build folder like so
|
||||
|
||||
'./waf build --run'
|
||||
'_build/default/midori/midori'
|
||||
|
||||
Using --run as shown above will make sure extensions as well as
|
||||
localizations are used from the build folder.
|
||||
Midori will pick up extensions and resources from the build folder;
|
||||
it will NOT use localizations.
|
||||
|
||||
You can install it with './waf install'
|
||||
|
||||
|
@ -29,15 +29,16 @@ For further options run './waf --help'
|
|||
|
||||
+++ Debugging Midori +++
|
||||
|
||||
Run './waf configure -d full' from the Midori folder.
|
||||
Midori is by default built with debugging symbols, make sure you have
|
||||
installed 'gdb', the GNU Debugger.
|
||||
|
||||
Run './waf build'
|
||||
It's a good idea to execute all unit test cases and see that they pass.
|
||||
|
||||
Midori is now built with debugging symbols.
|
||||
'xvfb-run ./waf check'
|
||||
|
||||
Make sure you have installed 'gdb', the GNU Debugger.
|
||||
In this example, Xvfb is used to avoid relying on the local user setup.
|
||||
|
||||
Run Midori as 'gdb _build_/default/midori/midori'.
|
||||
You can also run Midori proper as 'gdb _build/default/midori/midori'.
|
||||
|
||||
Inside gdb, type 'run'.
|
||||
|
||||
|
@ -49,27 +50,32 @@ function names and line numbers.
|
|||
|
||||
If the problem is a warning and not a crash, try this:
|
||||
|
||||
'G_DEBUG=all gdb _build_/default/midori/midori'
|
||||
'G_DEBUG=all gdb _build/default/midori/midori'
|
||||
|
||||
If you are interested in HTTP communication, try this:
|
||||
|
||||
'MIDORI_SOUP_DEBUG=2 _build_/default/midori/midori'
|
||||
'MIDORI_DEBUG=headers _build/default/midori/midori'
|
||||
|
||||
Where '2' can be a level between 0 and 3.
|
||||
Where 'headers' can be replaced with 'body' to get full message contents.
|
||||
|
||||
If you are interested in (non-) touchscreen behaviour, try this:
|
||||
|
||||
'MIDORI_TOUCHSCREEN=1 _build_/default/midori/midori', or
|
||||
'MIDORI_TOUCHSCREEN=1 _build/default/midori/midori', or
|
||||
|
||||
'MIDORI_TOUCHSCREEN=0 _build_/default/midori/midori'
|
||||
'MIDORI_TOUCHSCREEN=0 _build/default/midori/midori'
|
||||
|
||||
If you want to "dry run" without WebKitGTK+ rendering, try this:
|
||||
|
||||
'MIDORI_UNARMED=1 _build_/default/midori/midori'
|
||||
'MIDORI_DEBUG=unarmed _build/default/midori/midori'
|
||||
|
||||
To debug extensions you can specify the path:
|
||||
If you want to test bookmarks, you can enable database tracing:
|
||||
|
||||
'export MIDORI_EXTENSION_PATH=_build_/default/extensions'
|
||||
'MIDORI_DEBUG=bookmarks _build/default/midori/midori'
|
||||
|
||||
To disable Netscape plugins, use MOZ_PLUGIN_PATH=/.
|
||||
|
||||
When running from the build folder, extensions will also be located
|
||||
in the build folder (setting MIDORI_EXTENSION_PATH is no longer needed).
|
||||
|
||||
For further information a tutorial for gdb and
|
||||
reading up on how you can install debugging
|
||||
|
|
16
README
16
README
|
@ -2,19 +2,19 @@ This file is licensed under the terms of the expat license, see the file EXPAT.
|
|||
|
||||
Midori is a lightweight web browser.
|
||||
|
||||
* Full integration with GTK+2.
|
||||
* Fast rendering with WebKit.
|
||||
* Full integration with GTK+2 and GTK+3.
|
||||
* Fast rendering with WebKit and HTML5 video with GStreamer.
|
||||
* Tabs, windows and session management.
|
||||
* Flexibly configurable Web Search.
|
||||
* History completion and configurable Web Search.
|
||||
* User scripts and user styles support.
|
||||
* Adblock Plus compatible, external download manager support.
|
||||
* Straightforward bookmark management.
|
||||
* Customizable and extensible interface.
|
||||
* Extensions written in C.
|
||||
* Customizable interface, extensions written in C and Vala.
|
||||
|
||||
Requirements: GLib 2.22, GTK+ 2.10, WebkitGTK+ 1.1.17, libXML2,
|
||||
libsoup 2.27.90, sqlite 3.0, Vala 0.10
|
||||
Requirements: GLib 2.22, GTK+ 2.16, WebkitGTK+ 1.1.17, libXML2,
|
||||
libsoup 2.27.90, sqlite 3.0, Vala 0.14
|
||||
|
||||
Optional: GTK+ 3.0, Unique 0.9, libnotify
|
||||
Optional: GTK+ 3.0, Unique 0.9, libnotify, gcr, Granite 0.2, WebKit2GTK+ 1.11.91/ 2.0.0
|
||||
|
||||
For installation instructions read INSTALL.
|
||||
|
||||
|
|
2
configure
vendored
2
configure
vendored
|
@ -130,7 +130,7 @@ clean:
|
|||
|
||||
distclean:
|
||||
@$WAF distclean
|
||||
@-rm -rf _build_
|
||||
@-rm -rf _build
|
||||
@-rm -f Makefile
|
||||
|
||||
check:
|
||||
|
|
71
data/about.css
Normal file
71
data/about.css
Normal file
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
about: page style template for Midori.
|
||||
This file is licensed under the terms of the expat license, see the file EXPAT.
|
||||
*/
|
||||
body {
|
||||
background-color: #eee;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#container {
|
||||
background: #f6fff3;
|
||||
min-width: 70%;
|
||||
max-width: 70%;
|
||||
margin: 2em auto 1em;
|
||||
padding: 1em;
|
||||
border: 0.2em solid #9acb7f;
|
||||
-webkit-border-radius: 1em;
|
||||
}
|
||||
|
||||
#icon {
|
||||
float: left;
|
||||
padding-left: 1%;
|
||||
padding-top: 1%;
|
||||
}
|
||||
|
||||
html[dir="rtl"] #icon {
|
||||
float: right;
|
||||
padding-right: 1%;
|
||||
}
|
||||
|
||||
#main {
|
||||
float: right;
|
||||
width: 75%;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 1.4em;
|
||||
font-weight: bold;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
#logo {
|
||||
position: absolute; bottom: 15px;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
html[dir="ltr"] #logo {
|
||||
right: 15px;
|
||||
}
|
||||
|
||||
html[dir="rtl"] #logo {
|
||||
left: 15px;
|
||||
}
|
||||
|
||||
button span,
|
||||
button img {
|
||||
vertical-align: middle;
|
||||
padding: 2px 1px;
|
||||
}
|
||||
|
||||
#message {
|
||||
font-size: 1.1em;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
#description {
|
||||
font-size: 1em;
|
||||
}
|
|
@ -186,10 +186,10 @@ AutoSuggestControl.prototype.init = function () {
|
|||
};
|
||||
|
||||
//assign onblur event handler (hides suggestions)
|
||||
this.textbox.onblur =
|
||||
this.textbox.onclick = function () {
|
||||
oThis.hideSuggestions();
|
||||
};
|
||||
if (!this.textbox.onblur)
|
||||
this.textbox.onblur = function () { oThis.hideSuggestions(); };
|
||||
if (!this.textbox.onclick)
|
||||
this.textbox.onclick = function () { oThis.hideSuggestions(); };
|
||||
|
||||
//create the suggestions dropdown
|
||||
this.createDropDown();
|
||||
|
@ -299,7 +299,7 @@ function initSuggestions () {
|
|||
if (inputs.length == 0)
|
||||
return false;
|
||||
|
||||
for (i=0;i<inputs.length;i++)
|
||||
for (var i=0;i<inputs.length;i++)
|
||||
{
|
||||
var ename = inputs[i].getAttribute("name");
|
||||
var eid = inputs[i].getAttribute("id");
|
||||
|
|
|
@ -2,67 +2,11 @@
|
|||
Error page template for Midori.
|
||||
This file is licensed under the terms of the expat license, see the file EXPAT.
|
||||
-->
|
||||
|
||||
<html>
|
||||
<html dir="{dir}">
|
||||
<head>
|
||||
<title>{title}</title>
|
||||
<link rel="shortcut icon" href="{icon}" />
|
||||
<style type="text/css">
|
||||
body {
|
||||
background-color: #eee;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#container {
|
||||
background: #f6fff3;
|
||||
min-width: 70%;
|
||||
max-width: 70%;
|
||||
margin: 2em auto 1em;
|
||||
padding: 1em;
|
||||
border: 0.2em solid #9acb7f;
|
||||
-webkit-border-radius: 1em;
|
||||
}
|
||||
|
||||
icon {
|
||||
float: left;
|
||||
padding-left: 1%;
|
||||
padding-top: 1%;
|
||||
}
|
||||
|
||||
#main {
|
||||
float: right;
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 1.4em;
|
||||
font-weight: bold;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
#logo {
|
||||
position: absolute; right: 15px; bottom: 15px;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
button span,
|
||||
button img {
|
||||
vertical-align: middle;
|
||||
padding: 2px 1px;
|
||||
}
|
||||
|
||||
message {
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
description {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
</style>
|
||||
{favicon}
|
||||
<link rel="stylesheet" type="text/css" href="res://about.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="container">
|
||||
|
@ -74,7 +18,7 @@ description {
|
|||
<p id="description">{description}</p>
|
||||
<form method="GET" action="{uri}">
|
||||
<button type="submit" onclick="location.reload(); return false;">
|
||||
<img src="stock://gtk-refresh"/>
|
||||
<img style="{hide-button-images}" src="stock://gtk-refresh"/>
|
||||
<span>{tryagain}</span>
|
||||
</button>
|
||||
</form>
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
[settings]
|
||||
filters=http://adblockplus.mozdev.org/easylist/easylist.txt;https://easylist-downloads.adblockplus.org/easyprivacy.txt
|
||||
filters=https://easylist-downloads.adblockplus.org/easylist.txt;https://easylist-downloads.adblockplus.org/easyprivacy.txt
|
||||
|
|
61
data/faq.css
61
data/faq.css
|
@ -8,29 +8,64 @@ Stylesheet for Midori's documentation based on a version of Enrico Troeger.
|
|||
|
||||
@media screen {
|
||||
|
||||
body {
|
||||
background-color: #f6fff3;
|
||||
color: #404040;
|
||||
margin-left: 0.4em;
|
||||
width: 60em;
|
||||
font-size: 90%;
|
||||
html, body {
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #013100;
|
||||
* {
|
||||
background: #f6fff3 !important;
|
||||
color: #404040 !important;
|
||||
font-size: 14pt !important;
|
||||
font-family: serif !important;
|
||||
text-align: justify !important;
|
||||
line-height: 1.4em !important;
|
||||
word-spacing: 0.4mm !important;
|
||||
letter-spacing: 0.2mm !important;
|
||||
-webkit-column-count: auto !important;
|
||||
-webkit-column-width: auto !important;
|
||||
-webkit-box-shadow: none !important;
|
||||
width: auto !important;
|
||||
word-wrap: break-word !important;
|
||||
}
|
||||
|
||||
a:visited {
|
||||
color: #7E558E;
|
||||
div, p {
|
||||
padding: 5pt !important;
|
||||
}
|
||||
|
||||
li {
|
||||
padding-left: 5pt !important;
|
||||
}
|
||||
|
||||
img, *[accesskey], form *, form, iframe,
|
||||
*[id^=navigation], *[id$=navigation], *[id*=navigation], .collapsed, .expanded {
|
||||
display: none !important
|
||||
}
|
||||
|
||||
/* FIXME: we want "images bigger than 50px here" */
|
||||
img[width] {
|
||||
display: inline !important
|
||||
}
|
||||
|
||||
:link, :link * {
|
||||
color: #013100 !important;
|
||||
text-decoration: underline !important;
|
||||
}
|
||||
|
||||
:visited, :visited * {
|
||||
color: #7E558E !important;
|
||||
text-decoration: underline !important;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: none;
|
||||
text-decoration: none !important;
|
||||
}
|
||||
|
||||
h1, h2, h3 {
|
||||
font-family: sans-serif;
|
||||
color: #002a00;
|
||||
font-family: serif !important;
|
||||
color: #002a00 !important;
|
||||
}
|
||||
|
||||
h1 {
|
||||
|
|
674
data/faq.html
674
data/faq.html
File diff suppressed because it is too large
Load diff
28
data/gtk3.css
Normal file
28
data/gtk3.css
Normal file
|
@ -0,0 +1,28 @@
|
|||
.notebook tab .button {
|
||||
-GtkButton-default-border: 0;
|
||||
-GtkButton-default-outside-border: 0;
|
||||
-GtkButton-inner-border: 0;
|
||||
-GtkWidget-focus-line-width: 0;
|
||||
-GtkWidget-focus-padding: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
GtkOverlay > * {
|
||||
padding: 4px;
|
||||
border-style: solid;
|
||||
border-radius: 0 5px 0 0;
|
||||
border-width: 1px 1px 0 0;
|
||||
}
|
||||
|
||||
GtkOverlay MidoriFindbar {
|
||||
border-radius: 0 0 0 5px;
|
||||
border-width: 0 0 1px 1px; /* top right bottom left */
|
||||
}
|
||||
|
||||
/* Kill grey backround on inactive buttons */
|
||||
GtkDrawingArea,
|
||||
GtkImage,
|
||||
GtkImage:insensitive,
|
||||
GtkImage:selected {
|
||||
background-color: @transparent;
|
||||
}
|
|
@ -9,6 +9,7 @@ Exec=midori --private %U
|
|||
Icon=midori
|
||||
Terminal=false
|
||||
StartupNotify=true
|
||||
NotShowIn=Pantheon;
|
||||
X-Osso-Type=application/x-executable
|
||||
X-Osso-Service=midori
|
||||
|
||||
|
|
|
@ -3,7 +3,8 @@ Version=1.0
|
|||
Type=Application
|
||||
_Name=Midori
|
||||
_GenericName=Web Browser
|
||||
_Comment=Lightweight web browser
|
||||
_X-GNOME-Fullname=Midori Web Browser
|
||||
_Comment=Browse the Web
|
||||
_X-GNOME-Keywords=Internet;WWW;Explorer
|
||||
_X-AppInstall-Keywords=Internet;WWW;Explorer
|
||||
Categories=GTK;Network;WebBrowser;
|
||||
|
@ -14,20 +15,17 @@ Terminal=false
|
|||
StartupNotify=true
|
||||
X-Osso-Type=application/x-executable
|
||||
X-Osso-Service=midori
|
||||
X-Ayatana-Desktop-Shortcuts=TabNew;WindowNew;Private
|
||||
Actions=TabNew;WindowNew;Private;
|
||||
|
||||
[TabNew Shortcut Group]
|
||||
Name=New _Tab
|
||||
[Desktop Action TabNew]
|
||||
_Name=New Tab
|
||||
Exec=midori -e TabNew
|
||||
TargetEnvironment=Unity
|
||||
|
||||
[WindowNew Shortcut Group]
|
||||
Name=New _Window
|
||||
[Desktop Action WindowNew]
|
||||
_Name=New Window
|
||||
Exec=midori -e WindowNew
|
||||
TargetEnvironment=Unity
|
||||
|
||||
[Private Shortcut Group]
|
||||
Name=New P_rivate Browsing Window
|
||||
[Desktop Action Private]
|
||||
_Name=New Private Browsing Window
|
||||
Exec=midori --private
|
||||
TargetEnvironment=Unity
|
||||
|
||||
|
|
BIN
data/midori.swf
Normal file
BIN
data/midori.swf
Normal file
Binary file not shown.
|
@ -27,3 +27,10 @@ name=The Free Dictionary
|
|||
text=Dictionary, Encyclopedia and Thesaurus
|
||||
uri=http://www.thefreedictionary.com/%s
|
||||
token=fd
|
||||
|
||||
[Google Translate]
|
||||
name=Google Translate
|
||||
text=Localize text or URL
|
||||
uri=http://translate.google.com/?q=
|
||||
token=gt
|
||||
|
||||
|
|
|
@ -55,10 +55,7 @@
|
|||
width: 85%;
|
||||
height: 75%;
|
||||
margin: auto;
|
||||
-webkit-box-shadow: 0 4px 18px rgba(0,0,0,.3), 0 0 2px #fff inset;
|
||||
background-image: -webkit-gradient(
|
||||
linear, center top, center bottom,
|
||||
from(#f6f6f6), to(#e3e3e3));
|
||||
-webkit-box-shadow: 0 2px 5px rgba(0,0,0,.3), 0 0 0px #fff inset;
|
||||
border: 1px solid #bcbcbc;
|
||||
border-bottom-color: #a0a0a0;
|
||||
position: relative;
|
||||
|
@ -75,9 +72,15 @@
|
|||
div.shortcut .preview.new .add {
|
||||
display: block;
|
||||
height: 100%;
|
||||
width: 50%;
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
cursor: pointer;
|
||||
-webkit-box-shadow: 0 2px 5px rgba(0,0,0,.3), 0 0 0px #fff inset;
|
||||
background-image: -webkit-gradient(
|
||||
linear, center top, center bottom,
|
||||
from(#f6f6f6), to(#e3e3e3));
|
||||
background-repeat: repeat-x;
|
||||
-webkit-border-radius: 3px;
|
||||
}
|
||||
|
||||
.title {
|
||||
|
@ -111,95 +114,148 @@
|
|||
display:none;
|
||||
}
|
||||
|
||||
div.osd {
|
||||
top: 9px;
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
div.osd span {
|
||||
border: 1px solid #999;
|
||||
background-color: #f5f5f5;
|
||||
padding: 8px;
|
||||
color: #999;
|
||||
-webkit-border-bottom-left-radius: 10px;
|
||||
visibility: hidden;
|
||||
.selected {
|
||||
outline: 1px dotted black;
|
||||
background-color: #eef;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
var getAction = function (id)
|
||||
{
|
||||
var s = document.getElementById(id).childNodes[0];
|
||||
if (s.className == 'preview')
|
||||
return true;
|
||||
function add_tile (ev) {
|
||||
ev.preventDefault();
|
||||
|
||||
var url = prompt ("{enter_shortcut_address}", "http://");
|
||||
if (!url) return false;
|
||||
if (!url)
|
||||
return false;
|
||||
|
||||
if (url.indexOf ("://") == -1)
|
||||
url = "http://" + url;
|
||||
|
||||
console.log ("speed_dial-save-add " + id + " " + url + " ");
|
||||
return false;
|
||||
var id = ev.target.parentNode.parentNode.id;
|
||||
console.log ("speed_dial-save-add " + id + " " + url);
|
||||
}
|
||||
|
||||
var renameShortcut = function (id)
|
||||
{
|
||||
var old_name = document.getElementById(id).childNodes[1].textContent;
|
||||
function rename_tile (ev) {
|
||||
var old_name = ev.target.textContent;
|
||||
|
||||
var name = prompt ("{enter_shortcut_name}", old_name);
|
||||
if (!name) return;
|
||||
if (!name)
|
||||
return;
|
||||
|
||||
var id = ev.target.parentNode.id;
|
||||
console.log ("speed_dial-save-rename " + id + " " + name);
|
||||
}
|
||||
|
||||
var clearShortcut = function (id)
|
||||
{
|
||||
if(!confirm("{are_you_sure}"))
|
||||
function delete_tile (ev) {
|
||||
ev.preventDefault();
|
||||
|
||||
if (!confirm("{are_you_sure}"))
|
||||
return;
|
||||
|
||||
var id = ev.target.parentNode.parentNode.id;
|
||||
console.log ("speed_dial-save-delete " + id);
|
||||
}
|
||||
|
||||
var key_id = 's';
|
||||
var key_timeout;
|
||||
|
||||
document.onkeypress = function ()
|
||||
{
|
||||
key_id = key_id + String.fromCharCode (event.which);
|
||||
var firstNode, secondNode;
|
||||
var cursor;
|
||||
|
||||
clearTimeout (key_timeout);
|
||||
|
||||
document.getElementById('dialing').innerText = key_id.substr(1);
|
||||
document.getElementById('dialing').style.visibility = 'visible';
|
||||
|
||||
var div = document.getElementById(key_id);
|
||||
if (div)
|
||||
{
|
||||
if (key_id.substr(1) > 9)
|
||||
{
|
||||
if (getAction (key_id))
|
||||
document.location = div.childNodes[0].childNodes[1].href;
|
||||
key_id = 's';
|
||||
}
|
||||
else
|
||||
key_timeout = setTimeout ('if (getAction (key_id)) document.location = document.getElementById(key_id).childNodes[0].childNodes[1].href; key_id = \'s\'', 1000);
|
||||
}
|
||||
else
|
||||
key_id = 's';
|
||||
|
||||
if (key_id.length <= 1)
|
||||
document.getElementById('dialing').style.visibility = 'hidden';
|
||||
|
||||
return false;
|
||||
var get_dial_div = function (ele) {
|
||||
var dial_div;
|
||||
if (ele.nodeName == 'IMG')
|
||||
dial_div = ele.parentNode.parentNode.parentNode;
|
||||
if (ele.className == 'title')
|
||||
dial_div = ele.parentNode;
|
||||
if (ele.className.indexOf ('shortcut') != -1)
|
||||
dial_div = ele;
|
||||
return dial_div;
|
||||
}
|
||||
|
||||
function click (ev) {
|
||||
if (ev == undefined)
|
||||
return;
|
||||
|
||||
ev.preventDefault();
|
||||
var ele = ev.target;
|
||||
cursor = ele.style.cursor;
|
||||
ele.style.cursor = 'move';
|
||||
|
||||
var eparent = get_dial_div (ele);
|
||||
if (eparent != undefined) {
|
||||
eparent.className = 'shortcut selected';
|
||||
firstNode = eparent.id;
|
||||
}
|
||||
};
|
||||
|
||||
function up (ev) {
|
||||
if (ev == undefined)
|
||||
return;
|
||||
|
||||
ev.preventDefault();
|
||||
ele = ev.target;
|
||||
var eparent = get_dial_div (ele);
|
||||
|
||||
ele.style.cursor = cursor;
|
||||
secondNode = eparent.id;
|
||||
|
||||
/* ommit just mere clicking the dial */
|
||||
if (firstNode != secondNode && firstNode != undefined)
|
||||
swap();
|
||||
};
|
||||
|
||||
function over (ev) {
|
||||
if (ev == undefined)
|
||||
return;
|
||||
|
||||
ev.preventDefault();
|
||||
var ele = ev.target;
|
||||
var eparent = get_dial_div (ele);
|
||||
|
||||
var dial = document.getElementsByClassName("shortcut");
|
||||
if (firstNode != undefined)
|
||||
{
|
||||
eparent.className = 'shortcut selected';
|
||||
for (var i = 0; i < dial.length; i++) {
|
||||
if (eparent.id != firstNode.id && dial[i].id != eparent.id) {
|
||||
dial[i].className = 'shortcut';
|
||||
}
|
||||
}
|
||||
}
|
||||
ele.style.cursor = cursor;
|
||||
}
|
||||
|
||||
function swap () {
|
||||
console.log ("speed_dial-save-swap " + firstNode + " " + secondNode);
|
||||
};
|
||||
|
||||
function init () {
|
||||
var new_tile = document.getElementsByClassName ("preview new");
|
||||
new_tile[0].addEventListener ('click', add_tile, false);
|
||||
|
||||
var titles = document.getElementsByClassName ("title");
|
||||
var len = titles.length;
|
||||
for (var i = 0; i < len; i++) {
|
||||
if (titles[i].parentNode.childNodes[0].className != "preview new")
|
||||
titles[i].addEventListener ('click', rename_tile, false);
|
||||
}
|
||||
|
||||
var crosses = document.getElementsByClassName ("cross");
|
||||
var len = crosses.length;
|
||||
for (var i = 0; i < len; i++)
|
||||
crosses[i].addEventListener ('click', delete_tile, false);
|
||||
|
||||
var occupied_tiles = document.getElementsByClassName ("shortcut");
|
||||
var len = occupied_tiles.length;
|
||||
for (var i = 0; i < len; i++) {
|
||||
if (occupied_tiles[i].childNodes[0].className != "preview new") {
|
||||
occupied_tiles[i].addEventListener('mousedown', click, false);
|
||||
occupied_tiles[i].addEventListener('mouseover', over, false);
|
||||
occupied_tiles[i].addEventListener('mouseup', up, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="osd" >
|
||||
<span id="dialing"></span>
|
||||
</div>
|
||||
<body onload="init ();">
|
||||
<div id="content">
|
||||
|
|
|
@ -6,18 +6,20 @@ import pproc as subprocess
|
|||
import os
|
||||
import Utils
|
||||
|
||||
blddir = '_build' # recognized by ack
|
||||
|
||||
for module in ('midori', 'katze'):
|
||||
try:
|
||||
if not os.access ('_build_', os.F_OK):
|
||||
Utils.check_dir ('_build_')
|
||||
if not os.access ('_build_/docs', os.F_OK):
|
||||
Utils.check_dir ('_build_/docs')
|
||||
if not os.access ('_build_/docs/api', os.F_OK):
|
||||
Utils.check_dir ('_build_/docs/api')
|
||||
if not os.access (blddir, os.F_OK):
|
||||
Utils.check_dir (blddir)
|
||||
if not os.access (blddir + '/docs', os.F_OK):
|
||||
Utils.check_dir (blddir + '/docs')
|
||||
if not os.access (blddir + '/docs/api', os.F_OK):
|
||||
Utils.check_dir (blddir + '/docs/api')
|
||||
subprocess.call (['gtkdoc-scan', '--module=' + module,
|
||||
'--source-dir=' + module, '--output-dir=_build_/docs/api/' + module,
|
||||
'--source-dir=' + module, '--output-dir=' + blddir + '/docs/api/' + module,
|
||||
'--rebuild-sections', '--rebuild-types'])
|
||||
os.chdir ('_build_/docs/api/' + module)
|
||||
os.chdir (blddir + '/docs/api/' + module)
|
||||
subprocess.call (['gtkdoc-mktmpl', '--module=' + module,
|
||||
'--output-dir=.' + module])
|
||||
subprocess.call (['gtkdoc-mkdb', '--module=' + module,
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -14,6 +14,7 @@
|
|||
/* This extensions add support for user addons: userscripts and userstyles */
|
||||
|
||||
#include <midori/midori.h>
|
||||
#include "midori-core.h"
|
||||
#include <glib/gstdio.h>
|
||||
|
||||
#include "config.h"
|
||||
|
@ -182,8 +183,8 @@ addons_install_response (GtkWidget* infobar,
|
|||
|
||||
if (!filename)
|
||||
filename = g_path_get_basename (uri);
|
||||
folder_path = g_build_path (G_DIR_SEPARATOR_S, g_get_user_data_dir (),
|
||||
PACKAGE_NAME, folder, NULL);
|
||||
folder_path = g_build_path (G_DIR_SEPARATOR_S,
|
||||
midori_paths_get_user_data_dir (), PACKAGE_NAME, folder, NULL);
|
||||
|
||||
if (!g_file_test (folder_path, G_FILE_TEST_EXISTS))
|
||||
katze_mkdir_with_parents (folder_path, 0700);
|
||||
|
@ -242,9 +243,8 @@ addons_notify_load_status_cb (MidoriView* view,
|
|||
MidoriExtension* extension)
|
||||
{
|
||||
const gchar* uri = midori_view_get_display_uri (view);
|
||||
WebKitWebView* web_view = WEBKIT_WEB_VIEW (midori_view_get_web_view (view));
|
||||
|
||||
if (webkit_web_view_get_view_source_mode (web_view))
|
||||
if (midori_tab_get_view_source (MIDORI_TAB (view)))
|
||||
return;
|
||||
|
||||
if (uri && *uri)
|
||||
|
@ -293,13 +293,13 @@ addons_button_add_clicked_cb (GtkToolItem* toolitem,
|
|||
if (addons->kind == ADDONS_USER_SCRIPTS)
|
||||
{
|
||||
addons_type = g_strdup ("userscripts");
|
||||
path = g_build_path (G_DIR_SEPARATOR_S, g_get_user_data_dir (),
|
||||
path = g_build_path (G_DIR_SEPARATOR_S, midori_paths_get_user_data_dir (),
|
||||
PACKAGE_NAME, "scripts", NULL);
|
||||
}
|
||||
else if (addons->kind == ADDONS_USER_STYLES)
|
||||
{
|
||||
addons_type = g_strdup ("userstyles");
|
||||
path = g_build_path (G_DIR_SEPARATOR_S, g_get_user_data_dir (),
|
||||
path = g_build_path (G_DIR_SEPARATOR_S, midori_paths_get_user_data_dir (),
|
||||
PACKAGE_NAME, "styles", NULL);
|
||||
}
|
||||
else
|
||||
|
@ -336,23 +336,13 @@ addons_button_add_clicked_cb (GtkToolItem* toolitem,
|
|||
if (!g_file_test (path, G_FILE_TEST_EXISTS))
|
||||
katze_mkdir_with_parents (path, 0700);
|
||||
|
||||
#if !GTK_CHECK_VERSION (2, 14, 0)
|
||||
files = gtk_file_chooser_get_filenames (GTK_FILE_CHOOSER (dialog));
|
||||
#else
|
||||
files = gtk_file_chooser_get_files (GTK_FILE_CHOOSER (dialog));
|
||||
#endif
|
||||
|
||||
while (files)
|
||||
{
|
||||
GFile* src_file;
|
||||
GError* error = NULL;
|
||||
|
||||
#if !GTK_CHECK_VERSION (2, 14, 0)
|
||||
src_file = g_file_new_for_path (files);
|
||||
#else
|
||||
src_file = files->data;
|
||||
#endif
|
||||
|
||||
if (G_IS_FILE (src_file))
|
||||
{
|
||||
GFile* dest_file;
|
||||
|
@ -491,7 +481,7 @@ addons_open_in_editor_clicked_cb (GtkWidget* toolitem,
|
|||
|
||||
g_object_get (settings, "text-editor", &text_editor, NULL);
|
||||
if (text_editor && *text_editor)
|
||||
sokoke_spawn_program (text_editor, element->fullpath);
|
||||
sokoke_spawn_program (text_editor, TRUE, element->fullpath, TRUE, FALSE);
|
||||
else
|
||||
{
|
||||
gchar* element_uri = g_filename_to_uri (element->fullpath, NULL, NULL);
|
||||
|
@ -522,10 +512,13 @@ addons_open_target_folder_clicked_cb (GtkWidget* toolitem,
|
|||
folder = g_path_get_dirname (element->fullpath);
|
||||
}
|
||||
else
|
||||
folder = g_build_path (G_DIR_SEPARATOR_S, g_get_user_data_dir (),
|
||||
PACKAGE_NAME,
|
||||
addons->kind == ADDONS_USER_SCRIPTS
|
||||
? "scripts" : "styles", NULL);
|
||||
{
|
||||
folder = g_build_path (G_DIR_SEPARATOR_S, midori_paths_get_user_data_dir (),
|
||||
PACKAGE_NAME, addons->kind == ADDONS_USER_SCRIPTS
|
||||
? "scripts" : "styles", NULL);
|
||||
katze_mkdir_with_parents (folder, 0700);
|
||||
}
|
||||
|
||||
folder_uri = g_filename_to_uri (folder, NULL, NULL);
|
||||
g_free (folder);
|
||||
|
||||
|
@ -783,11 +776,10 @@ addons_treeview_render_text_cb (GtkTreeViewColumn* column,
|
|||
|
||||
gtk_tree_model_get (model, iter, 0, &element, -1);
|
||||
|
||||
g_object_set (renderer, "text", element->displayname, NULL);
|
||||
if (!element->enabled)
|
||||
g_object_set (renderer, "sensitive", false, NULL);
|
||||
else
|
||||
g_object_set (renderer, "sensitive", true, NULL);
|
||||
g_object_set (renderer, "text", element->displayname,
|
||||
"sensitive", element->enabled,
|
||||
"ellipsize", PANGO_ELLIPSIZE_END,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -831,19 +823,16 @@ addons_get_directories (AddonsKind kind)
|
|||
else
|
||||
g_assert_not_reached ();
|
||||
|
||||
path = g_build_path (G_DIR_SEPARATOR_S, g_get_user_data_dir (),
|
||||
path = g_build_path (G_DIR_SEPARATOR_S, midori_paths_get_user_data_dir (),
|
||||
PACKAGE_NAME, folder_name, NULL);
|
||||
if (g_access (path, X_OK) == 0)
|
||||
directories = g_slist_prepend (directories, path);
|
||||
else
|
||||
g_free (path);
|
||||
directories = g_slist_prepend (directories, path);
|
||||
|
||||
datadirs = g_get_system_data_dirs ();
|
||||
while (*datadirs)
|
||||
{
|
||||
path = g_build_path (G_DIR_SEPARATOR_S, *datadirs,
|
||||
PACKAGE_NAME, folder_name, NULL);
|
||||
if (g_slist_find (directories, path) == NULL && g_access (path, X_OK) == 0)
|
||||
if (g_slist_find (directories, path) == NULL)
|
||||
directories = g_slist_prepend (directories, path);
|
||||
else
|
||||
g_free (path);
|
||||
|
@ -940,10 +929,16 @@ js_metadata_from_file (const gchar* filename,
|
|||
/* We don't support these, so abort here */
|
||||
g_free (line);
|
||||
g_io_channel_shutdown (channel, false, 0);
|
||||
g_slist_free (*includes);
|
||||
g_slist_free (*excludes);
|
||||
*includes = NULL;
|
||||
*excludes = NULL;
|
||||
if (includes != NULL)
|
||||
{
|
||||
g_slist_free (*includes);
|
||||
*includes = NULL;
|
||||
}
|
||||
if (excludes != NULL)
|
||||
{
|
||||
g_slist_free (*excludes);
|
||||
*excludes = NULL;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
else if (includes && g_str_has_prefix (line, "// @include"))
|
||||
|
@ -1335,8 +1330,9 @@ addons_init (Addons* addons)
|
|||
G_CALLBACK (addons_cell_renderer_toggled_cb), addons);
|
||||
gtk_tree_view_append_column (GTK_TREE_VIEW (addons->treeview), column);
|
||||
column = gtk_tree_view_column_new ();
|
||||
gtk_tree_view_column_set_expand (column, TRUE);
|
||||
renderer_text = gtk_cell_renderer_text_new ();
|
||||
gtk_tree_view_column_pack_start (column, renderer_text, FALSE);
|
||||
gtk_tree_view_column_pack_start (column, renderer_text, TRUE);
|
||||
gtk_tree_view_column_set_cell_data_func (column, renderer_text,
|
||||
(GtkTreeCellDataFunc)addons_treeview_render_text_cb,
|
||||
addons->treeview, NULL);
|
||||
|
@ -1526,30 +1522,19 @@ addons_add_tab_cb (MidoriBrowser* browser,
|
|||
G_CALLBACK (addons_notify_load_status_cb), extension);
|
||||
}
|
||||
|
||||
static void
|
||||
addons_add_tab_foreach_cb (MidoriView* view,
|
||||
MidoriBrowser* browser,
|
||||
MidoriExtension* extension)
|
||||
{
|
||||
addons_add_tab_cb (browser, view, extension);
|
||||
}
|
||||
|
||||
static void
|
||||
addons_deactivate_tabs (MidoriView* view,
|
||||
MidoriExtension* extension)
|
||||
{
|
||||
GtkWidget* web_view = midori_view_get_web_view (view);
|
||||
g_signal_handlers_disconnect_by_func (
|
||||
web_view, addons_context_ready_cb, extension);
|
||||
}
|
||||
|
||||
static void
|
||||
addons_browser_destroy (MidoriBrowser* browser,
|
||||
MidoriExtension* extension)
|
||||
{
|
||||
GtkWidget* scripts, *styles;
|
||||
|
||||
midori_browser_foreach (browser, (GtkCallback)addons_deactivate_tabs, extension);
|
||||
GList* tabs = midori_browser_get_tabs (browser);
|
||||
for (; tabs; tabs = g_list_next (tabs))
|
||||
{
|
||||
GtkWidget* web_view = midori_view_get_web_view (tabs->data);
|
||||
g_signal_handlers_disconnect_by_func (
|
||||
web_view, addons_context_ready_cb, extension);
|
||||
}
|
||||
g_list_free (tabs);
|
||||
g_signal_handlers_disconnect_by_func (browser, addons_add_tab_cb, extension);
|
||||
|
||||
scripts = (GtkWidget*)g_object_get_data (G_OBJECT (browser), "scripts-addons");
|
||||
|
@ -1629,9 +1614,10 @@ addons_app_add_browser_cb (MidoriApp* app,
|
|||
{
|
||||
GtkWidget* panel;
|
||||
GtkWidget* scripts, *styles;
|
||||
|
||||
midori_browser_foreach (browser,
|
||||
(GtkCallback)addons_add_tab_foreach_cb, extension);
|
||||
GList* tabs = midori_browser_get_tabs (browser);
|
||||
for (; tabs; tabs = g_list_next (tabs))
|
||||
addons_add_tab_cb (browser, tabs->data, extension);
|
||||
g_list_free (tabs);
|
||||
g_signal_connect (browser, "add-tab",
|
||||
G_CALLBACK (addons_add_tab_cb), extension);
|
||||
panel = katze_object_get_object (browser, "panel");
|
||||
|
@ -1687,10 +1673,10 @@ addons_save_settings (MidoriApp* app,
|
|||
|
||||
config_dir = midori_extension_get_config_dir (extension);
|
||||
config_file = g_build_filename (config_dir, "addons", NULL);
|
||||
katze_mkdir_with_parents (config_dir, 0700);
|
||||
if (config_dir != NULL)
|
||||
katze_mkdir_with_parents (config_dir, 0700);
|
||||
sokoke_key_file_save_to_file (keyfile, config_file, &error);
|
||||
/* If the folder is /, this is a test run, thus no error */
|
||||
if (error && !g_str_equal (config_dir, "/"))
|
||||
if (error && midori_extension_get_config_dir (extension) != NULL)
|
||||
{
|
||||
g_warning (_("The configuration of the extension '%s' couldn't be saved: %s\n"),
|
||||
_("User addons"), error->message);
|
||||
|
@ -1866,7 +1852,6 @@ addons_activate_cb (MidoriExtension* extension,
|
|||
G_CALLBACK (addons_deactivate_cb), app);
|
||||
}
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
static void
|
||||
test_addons_simple_regexp (void)
|
||||
{
|
||||
|
@ -1905,7 +1890,6 @@ extension_test (void)
|
|||
{
|
||||
g_test_add_func ("/extensions/addons/simple_regexp", test_addons_simple_regexp);
|
||||
}
|
||||
#endif
|
||||
|
||||
MidoriExtension*
|
||||
extension_init (void)
|
||||
|
|
288
extensions/apps.vala
Normal file
288
extensions/apps.vala
Normal file
|
@ -0,0 +1,288 @@
|
|||
/*
|
||||
Copyright (C) 2013 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.
|
||||
*/
|
||||
|
||||
namespace Apps {
|
||||
const string EXEC_PREFIX = PACKAGE_NAME + " -a ";
|
||||
|
||||
private class Launcher : GLib.Object, GLib.Initable {
|
||||
internal GLib.File file;
|
||||
internal string name;
|
||||
internal string icon_name;
|
||||
internal string exec;
|
||||
internal string uri;
|
||||
|
||||
internal static async void create (GLib.File folder, string uri, string title) {
|
||||
/* Strip LRE leading character and / */
|
||||
string filename = title.delimit ("/", ' ') + ".desktop";
|
||||
string exec = EXEC_PREFIX + uri;
|
||||
string name = title;
|
||||
// TODO: Midori.Paths.get_icon save to png
|
||||
string icon_name = Midori.Stock.WEB_BROWSER;
|
||||
string contents = """
|
||||
[Desktop Entry]
|
||||
Version=1.0
|
||||
Type=Application
|
||||
Name=%s
|
||||
Exec=%s
|
||||
TryExec=%s
|
||||
Icon=%s
|
||||
Categories=Network;
|
||||
""".printf (name, exec, PACKAGE_NAME, icon_name);
|
||||
var file = folder.get_child (filename);
|
||||
try {
|
||||
var stream = yield file.replace_async (null, false, GLib.FileCreateFlags.NONE);
|
||||
yield stream.write_async (contents.data);
|
||||
}
|
||||
catch (Error error) {
|
||||
// TODO GUI infobar
|
||||
warning ("Failed to create new launcher: %s", error.message);
|
||||
}
|
||||
}
|
||||
|
||||
internal Launcher (GLib.File file) {
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
bool init (GLib.Cancellable? cancellable) throws GLib.Error {
|
||||
if (!file.get_basename ().has_suffix (".desktop"))
|
||||
return false;
|
||||
|
||||
var keyfile = new GLib.KeyFile ();
|
||||
keyfile.load_from_file (file.get_path (), GLib.KeyFileFlags.NONE);
|
||||
exec = keyfile.get_string ("Desktop Entry", "Exec");
|
||||
if (!exec.has_prefix (EXEC_PREFIX))
|
||||
return false;
|
||||
|
||||
name = keyfile.get_string ("Desktop Entry", "Name");
|
||||
icon_name = keyfile.get_string ("Desktop Entry", "Icon");
|
||||
uri = exec.replace (EXEC_PREFIX, "");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private class Sidebar : Gtk.VBox, Midori.Viewable {
|
||||
Gtk.Toolbar? toolbar = null;
|
||||
Gtk.ListStore store = new Gtk.ListStore (1, typeof (Launcher));
|
||||
Gtk.TreeView treeview;
|
||||
Katze.Array array;
|
||||
|
||||
public unowned string get_stock_id () {
|
||||
return Midori.Stock.WEB_BROWSER;
|
||||
}
|
||||
|
||||
public unowned string get_label () {
|
||||
return _("Applications");
|
||||
}
|
||||
|
||||
public Gtk.Widget get_toolbar () {
|
||||
if (toolbar == null) {
|
||||
toolbar = new Gtk.Toolbar ();
|
||||
toolbar.set_icon_size (Gtk.IconSize.BUTTON);
|
||||
}
|
||||
return toolbar;
|
||||
}
|
||||
|
||||
public Sidebar (Katze.Array array) {
|
||||
Gtk.TreeViewColumn column;
|
||||
|
||||
treeview = new Gtk.TreeView.with_model (store);
|
||||
treeview.headers_visible = false;
|
||||
|
||||
store.set_sort_column_id (0, Gtk.SortType.ASCENDING);
|
||||
store.set_sort_func (0, tree_sort_func);
|
||||
|
||||
column = new Gtk.TreeViewColumn ();
|
||||
Gtk.CellRendererPixbuf renderer_icon = new Gtk.CellRendererPixbuf ();
|
||||
column.pack_start (renderer_icon, false);
|
||||
column.set_cell_data_func (renderer_icon, on_render_icon);
|
||||
treeview.append_column (column);
|
||||
|
||||
column = new Gtk.TreeViewColumn ();
|
||||
column.set_sizing (Gtk.TreeViewColumnSizing.AUTOSIZE);
|
||||
Gtk.CellRendererText renderer_text = new Gtk.CellRendererText ();
|
||||
column.pack_start (renderer_text, true);
|
||||
column.set_expand (true);
|
||||
column.set_cell_data_func (renderer_text, on_render_text);
|
||||
treeview.append_column (column);
|
||||
|
||||
treeview.show ();
|
||||
pack_start (treeview, true, true, 0);
|
||||
|
||||
this.array = array;
|
||||
array.add_item.connect (launcher_added);
|
||||
array.remove_item.connect (launcher_removed);
|
||||
foreach (GLib.Object item in array.get_items ())
|
||||
launcher_added (item);
|
||||
}
|
||||
|
||||
private int tree_sort_func (Gtk.TreeModel model, Gtk.TreeIter a, Gtk.TreeIter b) {
|
||||
Launcher launcher1, launcher2;
|
||||
model.get (a, 0, out launcher1);
|
||||
model.get (b, 0, out launcher2);
|
||||
return strcmp (launcher1.name, launcher2.name);
|
||||
}
|
||||
void launcher_added (GLib.Object item) {
|
||||
var launcher = item as Launcher;
|
||||
Gtk.TreeIter iter;
|
||||
store.append (out iter);
|
||||
store.set (iter, 0, launcher);
|
||||
}
|
||||
|
||||
void launcher_removed (GLib.Object item) {
|
||||
// TODO remove iter
|
||||
}
|
||||
|
||||
private void on_render_icon (Gtk.CellLayout column, Gtk.CellRenderer renderer,
|
||||
Gtk.TreeModel model, Gtk.TreeIter iter) {
|
||||
|
||||
Launcher launcher;
|
||||
model.get (iter, 0, out launcher);
|
||||
if (launcher.icon_name != null)
|
||||
renderer.set ("icon-name", launcher.icon_name);
|
||||
else
|
||||
renderer.set ("stock-id", Gtk.STOCK_FILE);
|
||||
renderer.set ("stock-size", Gtk.IconSize.BUTTON,
|
||||
"xpad", 4);
|
||||
}
|
||||
|
||||
private void on_render_text (Gtk.CellLayout column, Gtk.CellRenderer renderer,
|
||||
Gtk.TreeModel model, Gtk.TreeIter iter) {
|
||||
|
||||
Launcher launcher;
|
||||
model.get (iter, 0, out launcher);
|
||||
renderer.set ("markup",
|
||||
Markup.printf_escaped ("<b>%s</b>\n%s",
|
||||
launcher.name, launcher.uri),
|
||||
"ellipsize", Pango.EllipsizeMode.END);
|
||||
}
|
||||
}
|
||||
|
||||
private class Manager : Midori.Extension {
|
||||
internal Katze.Array array;
|
||||
internal GLib.File app_folder;
|
||||
internal GLib.FileMonitor? monitor;
|
||||
internal GLib.List<Gtk.Widget> widgets;
|
||||
|
||||
void app_changed (GLib.File file, GLib.File? other, GLib.FileMonitorEvent event) {
|
||||
try {
|
||||
switch (event) {
|
||||
case GLib.FileMonitorEvent.DELETED:
|
||||
// TODO array.remove_item ();
|
||||
break;
|
||||
case GLib.FileMonitorEvent.CREATED:
|
||||
var launcher = new Launcher (file);
|
||||
if (launcher.init ())
|
||||
array.add_item (launcher);
|
||||
break;
|
||||
case GLib.FileMonitorEvent.CHANGED:
|
||||
// TODO
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Error error) {
|
||||
warning ("Application changed: %s", error.message);
|
||||
}
|
||||
}
|
||||
|
||||
async void populate_apps () {
|
||||
var data_dir = File.new_for_path (Midori.Paths.get_user_data_dir ());
|
||||
app_folder = data_dir.get_child ("applications");
|
||||
try {
|
||||
try {
|
||||
app_folder.make_directory_with_parents (null);
|
||||
}
|
||||
catch (IOError folder_error) {
|
||||
if (!(folder_error is IOError.EXISTS))
|
||||
throw folder_error;
|
||||
}
|
||||
|
||||
monitor = app_folder.monitor_directory (0, null);
|
||||
monitor.changed.connect (app_changed);
|
||||
|
||||
var enumerator = yield app_folder.enumerate_children_async ("standard::name", 0);
|
||||
while (true) {
|
||||
var files = yield enumerator.next_files_async (10);
|
||||
if (files == null)
|
||||
break;
|
||||
foreach (var info in files) {
|
||||
var desktop_file = app_folder.get_child (info.get_name ());
|
||||
try {
|
||||
var launcher = new Launcher (desktop_file);
|
||||
if (launcher.init ())
|
||||
array.add_item (launcher);
|
||||
}
|
||||
catch (Error error) {
|
||||
warning ("Failed to parse launcher: %s", error.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Error io_error) {
|
||||
monitor = null;
|
||||
warning ("Failed to list .desktop files (%s): %s",
|
||||
app_folder.get_path (), io_error.message);
|
||||
}
|
||||
}
|
||||
|
||||
void tool_menu_populated (Midori.Browser browser, Gtk.Menu menu) {
|
||||
var menuitem = new Gtk.MenuItem.with_mnemonic (_("Create _Launcher"));
|
||||
menuitem.show ();
|
||||
menu.append (menuitem);
|
||||
menuitem.activate.connect (() => {
|
||||
var view = browser.tab as Midori.View;
|
||||
Launcher.create.begin (app_folder,
|
||||
view.get_display_uri (), view.get_display_title ());
|
||||
});
|
||||
}
|
||||
|
||||
void browser_added (Midori.Browser browser) {
|
||||
var viewable = new Sidebar (array);
|
||||
viewable.show ();
|
||||
browser.panel.append_page (viewable);
|
||||
browser.populate_tool_menu.connect (tool_menu_populated);
|
||||
// TODO website context menu
|
||||
widgets.append (viewable);
|
||||
}
|
||||
|
||||
void activated (Midori.App app) {
|
||||
array = new Katze.Array (typeof (Launcher));
|
||||
populate_apps.begin ();
|
||||
widgets = new GLib.List<Gtk.Widget> ();
|
||||
foreach (var browser in app.get_browsers ())
|
||||
browser_added (browser);
|
||||
app.add_browser.connect (browser_added);
|
||||
}
|
||||
|
||||
void deactivated () {
|
||||
var app = get_app ();
|
||||
if (monitor != null)
|
||||
monitor.changed.disconnect (app_changed);
|
||||
app.add_browser.disconnect (browser_added);
|
||||
foreach (var widget in widgets)
|
||||
widget.destroy ();
|
||||
}
|
||||
|
||||
internal Manager () {
|
||||
GLib.Object (name: _("Web App Manager"),
|
||||
description: _("Manage websites installed as applications"),
|
||||
version: "0.1" + Midori.VERSION_SUFFIX,
|
||||
authors: "Christian Dywan <christian@twotoasts.de>");
|
||||
|
||||
this.activate.connect (activated);
|
||||
this.deactivate.connect (deactivated);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Midori.Extension extension_init () {
|
||||
return new Apps.Manager ();
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright (C) 2009 Christian Dywan <christian@twotoasts.de>
|
||||
Copyright (C) 2009-2013 Christian Dywan <christian@twotoasts.de>
|
||||
Copyright (C) 2010 Samuel Creshal <creshal@arcor.de>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
|
@ -12,24 +12,58 @@
|
|||
|
||||
#include <midori/midori.h>
|
||||
|
||||
static void
|
||||
colorful_tabs_modify_fg (GtkWidget* label,
|
||||
GdkColor* color)
|
||||
static GdkColor
|
||||
view_get_bgcolor_for_hostname (MidoriView* view, gchar* hostname)
|
||||
{
|
||||
GtkWidget* box = gtk_bin_get_child (GTK_BIN (label));
|
||||
GList* children = gtk_container_get_children (GTK_CONTAINER (box));
|
||||
for (; children != NULL; children = g_list_next (children))
|
||||
GdkColor color;
|
||||
GdkPixbuf* icon = midori_view_get_icon (view);
|
||||
if (icon != NULL)
|
||||
{
|
||||
if (GTK_IS_LABEL (children->data))
|
||||
{
|
||||
gtk_widget_modify_fg (children->data, GTK_STATE_ACTIVE, color);
|
||||
gtk_widget_modify_fg (children->data, GTK_STATE_NORMAL, color);
|
||||
/* Also modify the label itself, for Tab Panel */
|
||||
gtk_widget_modify_fg (label, GTK_STATE_NORMAL, color);
|
||||
break;
|
||||
}
|
||||
GdkPixbuf* newpix;
|
||||
guchar* pixels;
|
||||
|
||||
newpix = gdk_pixbuf_scale_simple (icon, 1, 1, GDK_INTERP_BILINEAR);
|
||||
pixels = gdk_pixbuf_get_pixels (newpix);
|
||||
color.red = pixels[0] * 255;
|
||||
color.green = pixels[1] * 255;
|
||||
color.blue = pixels[2] * 255;
|
||||
}
|
||||
g_list_free (children);
|
||||
else
|
||||
{
|
||||
gchar* hash, *colorstr;
|
||||
|
||||
hash = g_compute_checksum_for_string (G_CHECKSUM_MD5, hostname, 1);
|
||||
colorstr = g_strndup (hash, 6 + 1);
|
||||
colorstr[0] = '#';
|
||||
gdk_color_parse (colorstr, &color);
|
||||
|
||||
g_free (hash);
|
||||
g_free (colorstr);
|
||||
}
|
||||
|
||||
if ((color.red < 35000)
|
||||
&& (color.green < 35000)
|
||||
&& (color.blue < 35000))
|
||||
{
|
||||
color.red += 20000;
|
||||
color.green += 20000;
|
||||
color.blue += 20000;
|
||||
}
|
||||
|
||||
if (color.red < 10000)
|
||||
color.red = 5000;
|
||||
else
|
||||
color.red -= 5000;
|
||||
if (color.blue < 10000)
|
||||
color.blue = 5000;
|
||||
else
|
||||
color.blue -= 5000;
|
||||
if (color.green < 10000)
|
||||
color.green = 5000;
|
||||
else
|
||||
color.green -= 5000;
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -37,52 +71,16 @@ colorful_tabs_view_notify_uri_cb (MidoriView* view,
|
|||
GParamSpec* pspec,
|
||||
MidoriExtension* extension)
|
||||
{
|
||||
GtkWidget* label;
|
||||
gchar* hostname;
|
||||
gchar* colorstr;
|
||||
GdkColor color;
|
||||
GdkColor fgcolor;
|
||||
GdkPixbuf* icon;
|
||||
|
||||
label = midori_view_get_proxy_tab_label (view);
|
||||
|
||||
if (!midori_uri_is_blank (midori_view_get_display_uri (view))
|
||||
&& (hostname = midori_uri_parse_hostname (midori_view_get_display_uri (view), NULL))
|
||||
&& katze_object_get_enum (view, "load-status") == MIDORI_LOAD_FINISHED)
|
||||
&& midori_view_get_icon_uri (view) != NULL)
|
||||
{
|
||||
icon = midori_view_get_icon (view);
|
||||
|
||||
if (midori_view_get_icon_uri (view) != NULL)
|
||||
{
|
||||
GdkPixbuf* newpix;
|
||||
guchar* pixels;
|
||||
|
||||
newpix = gdk_pixbuf_scale_simple (icon, 1, 1, GDK_INTERP_BILINEAR);
|
||||
g_return_if_fail (gdk_pixbuf_get_bits_per_sample (newpix) == 8);
|
||||
pixels = gdk_pixbuf_get_pixels (newpix);
|
||||
color.red = pixels[0] * 225;
|
||||
color.green = pixels[1] * 225;
|
||||
color.blue = pixels[2] * 225;
|
||||
}
|
||||
else
|
||||
{
|
||||
gchar* hash = g_compute_checksum_for_string (G_CHECKSUM_MD5, hostname, 1);
|
||||
colorstr = g_strndup (hash, 6 + 1);
|
||||
g_free (hash);
|
||||
colorstr[0] = '#';
|
||||
gdk_color_parse (colorstr, &color);
|
||||
}
|
||||
color = view_get_bgcolor_for_hostname (view, hostname);
|
||||
g_free (hostname);
|
||||
|
||||
if ((color.red < 35000)
|
||||
&& (color.green < 35000)
|
||||
&& (color.blue < 35000))
|
||||
{
|
||||
color.red += 20000;
|
||||
color.green += 20000;
|
||||
color.blue += 20000;
|
||||
}
|
||||
|
||||
/* Ensure high contrast by enforcing black/ white text colour. */
|
||||
if ((color.red < 41000)
|
||||
&& (color.green < 41000)
|
||||
|
@ -91,32 +89,10 @@ colorful_tabs_view_notify_uri_cb (MidoriView* view,
|
|||
else
|
||||
gdk_color_parse ("#000", &fgcolor);
|
||||
|
||||
gtk_event_box_set_visible_window (GTK_EVENT_BOX (label), TRUE);
|
||||
|
||||
colorful_tabs_modify_fg (label, &fgcolor);
|
||||
gtk_widget_modify_bg (label, GTK_STATE_NORMAL, &color);
|
||||
|
||||
if (color.red < 10000)
|
||||
color.red = 5000;
|
||||
else
|
||||
color.red -= 5000;
|
||||
if (color.blue < 10000)
|
||||
color.blue = 5000;
|
||||
else
|
||||
color.blue -= 5000;
|
||||
if (color.green < 10000)
|
||||
color.green = 5000;
|
||||
else
|
||||
color.green -= 5000;
|
||||
|
||||
gtk_widget_modify_bg (label, GTK_STATE_ACTIVE, &color);
|
||||
midori_view_set_colors (view, &fgcolor, &color);
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_widget_modify_bg (label, GTK_STATE_NORMAL, NULL);
|
||||
gtk_widget_modify_bg (label, GTK_STATE_ACTIVE, NULL);
|
||||
colorful_tabs_modify_fg (label, NULL);
|
||||
}
|
||||
midori_view_set_colors (view, NULL, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -138,7 +114,7 @@ static void
|
|||
colorful_tabs_deactivate_cb (MidoriExtension* extension,
|
||||
MidoriBrowser* browser)
|
||||
{
|
||||
guint i;
|
||||
GList* children;
|
||||
GtkWidget* view;
|
||||
MidoriApp* app = midori_extension_get_app (extension);
|
||||
|
||||
|
@ -148,17 +124,15 @@ colorful_tabs_deactivate_cb (MidoriExtension* extension,
|
|||
browser, colorful_tabs_browser_add_tab_cb, extension);
|
||||
g_signal_handlers_disconnect_by_func (
|
||||
extension, colorful_tabs_deactivate_cb, browser);
|
||||
i = 0;
|
||||
while ((view = midori_browser_get_nth_tab (browser, i++)))
|
||||
|
||||
children = midori_browser_get_tabs (MIDORI_BROWSER (browser));
|
||||
for (; children; children = g_list_next (children))
|
||||
{
|
||||
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);
|
||||
colorful_tabs_modify_fg (label, NULL);
|
||||
midori_view_set_colors (children->data, NULL, NULL);
|
||||
g_signal_handlers_disconnect_by_func (
|
||||
view, colorful_tabs_view_notify_uri_cb, extension);
|
||||
children->data, colorful_tabs_view_notify_uri_cb, extension);
|
||||
}
|
||||
g_list_free (children);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -166,12 +140,13 @@ colorful_tabs_app_add_browser_cb (MidoriApp* app,
|
|||
MidoriBrowser* browser,
|
||||
MidoriExtension* extension)
|
||||
{
|
||||
guint i;
|
||||
GtkWidget* view;
|
||||
GList* children;
|
||||
|
||||
children = midori_browser_get_tabs (MIDORI_BROWSER (browser));
|
||||
for (; children; children = g_list_next (children))
|
||||
colorful_tabs_browser_add_tab_cb (browser, children->data, extension);
|
||||
g_list_free (children);
|
||||
|
||||
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",
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#include <gdk/gdkkeysyms.h>
|
||||
|
||||
#include <midori/midori.h>
|
||||
#include <webkit/webkit.h>
|
||||
#include "katze/katze.h"
|
||||
#include <time.h>
|
||||
|
||||
#include "cookie-manager.h"
|
||||
|
@ -166,12 +166,15 @@ static void cookie_manager_page_cookies_changed_cb(CookieManager *cm, CookieMana
|
|||
gtk_tree_view_set_model(GTK_TREE_VIEW(priv->treeview), GTK_TREE_MODEL(priv->filter));
|
||||
g_object_unref(priv->filter);
|
||||
|
||||
/* if a filter is set, apply it again */
|
||||
filter_text = gtk_entry_get_text(GTK_ENTRY(priv->filter_entry));
|
||||
if (*filter_text != '\0')
|
||||
/* if a filter is set, apply it again but ignore the place holder text */
|
||||
if (!g_object_get_data (G_OBJECT (priv->filter_entry), "sokoke_has_default"))
|
||||
{
|
||||
cm_filter_tree(cmp, filter_text);
|
||||
gtk_tree_view_expand_all(GTK_TREE_VIEW(priv->treeview));
|
||||
filter_text = gtk_entry_get_text(GTK_ENTRY(priv->filter_entry));
|
||||
if (*filter_text != '\0')
|
||||
{
|
||||
cm_filter_tree(cmp, filter_text);
|
||||
gtk_tree_view_expand_all(GTK_TREE_VIEW(priv->treeview));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -576,11 +579,14 @@ static void cm_button_delete_all_clicked_cb(GtkToolButton *button, CookieManager
|
|||
if (toplevel != NULL)
|
||||
gtk_window_set_icon_name(GTK_WINDOW(dialog), gtk_window_get_icon_name(GTK_WINDOW(toplevel)));
|
||||
|
||||
filter_text = gtk_entry_get_text(GTK_ENTRY(priv->filter_entry));
|
||||
if (*filter_text != '\0')
|
||||
if (!g_object_get_data (G_OBJECT (priv->filter_entry), "sokoke_has_default"))
|
||||
{
|
||||
gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
|
||||
_("Only cookies which match the filter will be deleted."));
|
||||
filter_text = gtk_entry_get_text(GTK_ENTRY(priv->filter_entry));
|
||||
if (*filter_text != '\0')
|
||||
{
|
||||
gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
|
||||
_("Only cookies which match the filter will be deleted."));
|
||||
}
|
||||
}
|
||||
|
||||
if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_YES)
|
||||
|
@ -650,25 +656,28 @@ static void cm_tree_drag_data_get_cb(GtkWidget *widget, GdkDragContext *drag_con
|
|||
|
||||
static gchar *cm_get_cookie_description_text(SoupCookie *cookie)
|
||||
{
|
||||
static gchar date_fmt[512];
|
||||
gchar *expires;
|
||||
gchar *text;
|
||||
time_t expiration_time;
|
||||
const struct tm *tm;
|
||||
|
||||
g_return_val_if_fail(cookie != NULL, NULL);
|
||||
|
||||
if (cookie->expires != NULL)
|
||||
{
|
||||
expiration_time = soup_date_to_time_t(cookie->expires);
|
||||
tm = localtime(&expiration_time);
|
||||
/* even if some gcc versions complain about "%c", there is nothing wrong with and here we
|
||||
* want to use it */
|
||||
time_t expiration_time = soup_date_to_time_t(cookie->expires);
|
||||
#if GLIB_CHECK_VERSION (2, 26, 0)
|
||||
GDateTime* date = g_date_time_new_from_unix_local(expiration_time);
|
||||
expires = g_date_time_format(date, "%c");
|
||||
g_date_time_unref(date);
|
||||
#else
|
||||
static gchar date_fmt[512];
|
||||
const struct tm *tm = localtime(&expiration_time);
|
||||
/* Some GCC versions falsely complain about "%c" */
|
||||
strftime(date_fmt, sizeof(date_fmt), "%c", tm);
|
||||
expires = date_fmt;
|
||||
expires = g_strdup(date_fmt);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
expires = _("At the end of the session");
|
||||
expires = g_strdup(_("At the end of the session"));
|
||||
|
||||
text = g_markup_printf_escaped(
|
||||
_("<b>Host</b>: %s\n<b>Name</b>: %s\n<b>Value</b>: %s\n<b>Path</b>: %s\n"
|
||||
|
@ -677,8 +686,10 @@ static gchar *cm_get_cookie_description_text(SoupCookie *cookie)
|
|||
cookie->name,
|
||||
cookie->value,
|
||||
cookie->path,
|
||||
/* i18n: is this cookie secure (SSL)? yes/ no */
|
||||
cookie->secure ? _("Yes") : _("No"),
|
||||
expires);
|
||||
g_free(expires);
|
||||
|
||||
return text;
|
||||
}
|
||||
|
@ -702,7 +713,6 @@ static gchar *cm_get_domain_description_text(const gchar *domain, gint cookie_co
|
|||
}
|
||||
|
||||
|
||||
#if GTK_CHECK_VERSION(2, 12, 0)
|
||||
static gboolean cm_tree_query_tooltip(GtkWidget *widget, gint x, gint y, gboolean keyboard_mode,
|
||||
GtkTooltip *tooltip, CookieManagerPage *cmp)
|
||||
{
|
||||
|
@ -731,8 +741,6 @@ static gboolean cm_tree_query_tooltip(GtkWidget *widget, gint x, gint y, gboolea
|
|||
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static gboolean cm_filter_match(const gchar *haystack, const gchar *needle)
|
||||
{
|
||||
|
@ -812,25 +820,20 @@ static void cm_filter_entry_changed_cb(GtkEditable *editable, CookieManagerPage
|
|||
if (priv->ignore_changed_filter)
|
||||
return;
|
||||
|
||||
text = gtk_entry_get_text(GTK_ENTRY(editable));
|
||||
if (!g_object_get_data (G_OBJECT (editable), "sokoke_has_default"))
|
||||
text = gtk_entry_get_text(GTK_ENTRY(editable));
|
||||
else
|
||||
text = NULL;
|
||||
cm_filter_tree(cmp, text);
|
||||
|
||||
cookie_manager_update_filter(priv->parent, text);
|
||||
|
||||
if (*text != '\0')
|
||||
gtk_tree_view_expand_all(GTK_TREE_VIEW(priv->treeview));
|
||||
else
|
||||
if (text && *text)
|
||||
gtk_tree_view_collapse_all(GTK_TREE_VIEW(priv->treeview));
|
||||
else
|
||||
gtk_tree_view_expand_all(GTK_TREE_VIEW(priv->treeview));
|
||||
}
|
||||
|
||||
|
||||
static void cm_filter_entry_clear_icon_released_cb(GtkIconEntry *e, gint pos, gint btn, gpointer data)
|
||||
{
|
||||
if (pos == GTK_ICON_ENTRY_SECONDARY)
|
||||
gtk_entry_set_text(GTK_ENTRY(e), "");
|
||||
}
|
||||
|
||||
|
||||
static void cm_tree_selection_changed_cb(GtkTreeSelection *selection, CookieManagerPage *cmp)
|
||||
{
|
||||
GList *rows;
|
||||
|
@ -1002,6 +1005,7 @@ static void cm_tree_render_text_cb(GtkTreeViewColumn *column, GtkCellRenderer *r
|
|||
}
|
||||
else
|
||||
g_object_set(renderer, "text", name, NULL);
|
||||
g_object_set (renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
|
||||
|
||||
g_free(name);
|
||||
}
|
||||
|
@ -1022,6 +1026,7 @@ static GtkWidget *cm_tree_prepare(CookieManagerPage *cmp)
|
|||
renderer = gtk_cell_renderer_text_new();
|
||||
column = gtk_tree_view_column_new_with_attributes(
|
||||
_("Name"), renderer, "text", COOKIE_MANAGER_COL_NAME, NULL);
|
||||
gtk_tree_view_column_set_expand (column, TRUE);
|
||||
gtk_tree_view_column_set_sort_indicator(column, TRUE);
|
||||
gtk_tree_view_column_set_sort_column_id(column, COOKIE_MANAGER_COL_NAME);
|
||||
gtk_tree_view_column_set_resizable(column, TRUE);
|
||||
|
@ -1045,10 +1050,8 @@ static GtkWidget *cm_tree_prepare(CookieManagerPage *cmp)
|
|||
g_signal_connect(treeview, "popup-menu", G_CALLBACK(cm_tree_popup_menu_cb), cmp);
|
||||
|
||||
/* tooltips */
|
||||
#if GTK_CHECK_VERSION(2, 12, 0)
|
||||
gtk_widget_set_has_tooltip(treeview, TRUE);
|
||||
g_signal_connect(treeview, "query-tooltip", G_CALLBACK(cm_tree_query_tooltip), cmp);
|
||||
#endif
|
||||
|
||||
/* drag'n'drop */
|
||||
gtk_tree_view_enable_model_drag_source(
|
||||
|
@ -1100,7 +1103,6 @@ static void cookie_manager_page_init(CookieManagerPage *self)
|
|||
GtkWidget *desc_swin;
|
||||
GtkWidget *paned;
|
||||
GtkWidget *filter_hbox;
|
||||
GtkWidget *filter_label;
|
||||
GtkWidget *treeview;
|
||||
CookieManagerPagePrivate *priv;
|
||||
|
||||
|
@ -1132,29 +1134,15 @@ static void cookie_manager_page_init(CookieManagerPage *self)
|
|||
tree_swin = gtk_scrolled_window_new(NULL, NULL);
|
||||
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(tree_swin),
|
||||
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
|
||||
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(tree_swin), GTK_SHADOW_IN);
|
||||
gtk_container_add(GTK_CONTAINER(tree_swin), treeview);
|
||||
gtk_widget_show(tree_swin);
|
||||
|
||||
filter_label = gtk_label_new(_("Filter:"));
|
||||
gtk_widget_show(filter_label);
|
||||
|
||||
priv->filter_entry = gtk_icon_entry_new();
|
||||
gtk_widget_set_tooltip_text(priv->filter_entry,
|
||||
_("Enter a filter string to show only cookies whose name or domain "
|
||||
"field match the entered filter"));
|
||||
priv->filter_entry = sokoke_search_entry_new (_("Search Cookies by Name or Domain"));
|
||||
gtk_widget_show(priv->filter_entry);
|
||||
gtk_icon_entry_set_icon_from_stock(GTK_ICON_ENTRY(priv->filter_entry),
|
||||
GTK_ICON_ENTRY_SECONDARY, GTK_STOCK_CLEAR);
|
||||
gtk_icon_entry_set_icon_highlight(GTK_ICON_ENTRY (priv->filter_entry),
|
||||
GTK_ICON_ENTRY_SECONDARY, TRUE);
|
||||
g_signal_connect(priv->filter_entry, "icon-release",
|
||||
G_CALLBACK(cm_filter_entry_clear_icon_released_cb), NULL);
|
||||
g_signal_connect(priv->filter_entry, "changed", G_CALLBACK(cm_filter_entry_changed_cb), self);
|
||||
g_signal_connect(priv->filter_entry, "activate", G_CALLBACK(cm_filter_entry_changed_cb), self);
|
||||
|
||||
filter_hbox = gtk_hbox_new(FALSE, 0);
|
||||
gtk_box_pack_start(GTK_BOX(filter_hbox), filter_label, FALSE, FALSE, 3);
|
||||
gtk_box_pack_start(GTK_BOX(filter_hbox), priv->filter_entry, TRUE, TRUE, 3);
|
||||
gtk_widget_show(filter_hbox);
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
#include "config.h"
|
||||
#include <midori/midori.h>
|
||||
#include <webkit/webkit.h>
|
||||
#include "katze/katze.h"
|
||||
|
||||
#include "cookie-manager.h"
|
||||
#include "cookie-manager-page.h"
|
||||
|
@ -234,7 +234,8 @@ static void cookie_manager_jar_changed_cb(SoupCookieJar *jar, SoupCookie *old, S
|
|||
/* We delay these events a little bit to avoid too many rebuilds of the tree.
|
||||
* Some websites (like Flyspray bugtrackers sent a whole bunch of cookies at once. */
|
||||
if (priv->timer_id == 0)
|
||||
priv->timer_id = g_timeout_add_seconds(1, (GSourceFunc) cookie_manager_delayed_refresh, cm);
|
||||
priv->timer_id = midori_timeout_add_seconds(
|
||||
1, (GSourceFunc) cookie_manager_delayed_refresh, cm, NULL);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,805 @@
|
|||
/*
|
||||
Copyright (C) 2013 Stephan Haller <nomad@froevel.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 "cookie-permission-manager-preferences-window.h"
|
||||
|
||||
/* Define this class in GObject system */
|
||||
G_DEFINE_TYPE(CookiePermissionManagerPreferencesWindow,
|
||||
cookie_permission_manager_preferences_window,
|
||||
GTK_TYPE_DIALOG)
|
||||
|
||||
/* Properties */
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
|
||||
PROP_MANAGER,
|
||||
|
||||
PROP_LAST
|
||||
};
|
||||
|
||||
static GParamSpec* CookiePermissionManagerPreferencesWindowProperties[PROP_LAST]={ 0, };
|
||||
|
||||
/* Private structure - access only by public API if needed */
|
||||
#define COOKIE_PERMISSION_MANAGER_PREFERENCES_WINDOW_GET_PRIVATE(obj) \
|
||||
(G_TYPE_INSTANCE_GET_PRIVATE((obj), TYPE_COOKIE_PERMISSION_MANAGER_PREFERENCES_WINDOW, CookiePermissionManagerPreferencesWindowPrivate))
|
||||
|
||||
struct _CookiePermissionManagerPreferencesWindowPrivate
|
||||
{
|
||||
/* Extension related */
|
||||
CookiePermissionManager *manager;
|
||||
sqlite3 *database;
|
||||
|
||||
/* Dialog related */
|
||||
GtkWidget *contentArea;
|
||||
GtkListStore *listStore;
|
||||
GtkWidget *list;
|
||||
GtkTreeSelection *listSelection;
|
||||
GtkWidget *deleteButton;
|
||||
GtkWidget *deleteAllButton;
|
||||
GtkWidget *askForUnknownPolicyCheckbox;
|
||||
GtkWidget *addDomainEntry;
|
||||
GtkWidget *addDomainPolicyCombo;
|
||||
GtkWidget *addDomainButton;
|
||||
|
||||
gint signalManagerChangedDatabaseID;
|
||||
gint signalManagerAskForUnknownPolicyID;
|
||||
gint signalAskForUnknownPolicyID;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
DOMAIN_COLUMN,
|
||||
POLICY_COLUMN,
|
||||
N_COLUMN
|
||||
};
|
||||
|
||||
|
||||
/* IMPLEMENTATION: Private variables and methods */
|
||||
|
||||
/* "Add domain"-button was pressed */
|
||||
static void _cookie_permission_manager_preferences_on_add_domain_clicked(CookiePermissionManagerPreferencesWindow *self,
|
||||
gpointer *inUserData)
|
||||
{
|
||||
CookiePermissionManagerPreferencesWindowPrivate *priv=self->priv;
|
||||
gchar *domain;
|
||||
const gchar *domainStart, *domainEnd;
|
||||
gchar *realDomain;
|
||||
GtkTreeIter policyIter;
|
||||
|
||||
g_return_if_fail(priv->database);
|
||||
|
||||
/* Get domain name entered */
|
||||
domain=g_hostname_to_ascii(gtk_entry_get_text(GTK_ENTRY(priv->addDomainEntry)));
|
||||
|
||||
/* Trim whitespaces from start and end of entered domain name */
|
||||
domainStart=domain;
|
||||
while(*domainStart && g_ascii_isspace(*domainStart)) domainStart++;
|
||||
|
||||
domainEnd=domain+strlen(domain)-1;
|
||||
while(*domainEnd && g_ascii_isspace(*domainEnd)) domainEnd--;
|
||||
if(domainEnd<=domainStart) return;
|
||||
|
||||
/* Seperate domain name from whitespaces */
|
||||
realDomain=g_strndup(domain, domainEnd-domainStart+1);
|
||||
if(!realDomain) return;
|
||||
|
||||
/* Get policy from combo box */
|
||||
if(gtk_combo_box_get_active_iter(GTK_COMBO_BOX(priv->addDomainPolicyCombo), &policyIter))
|
||||
{
|
||||
gchar *sql;
|
||||
gchar *error=NULL;
|
||||
gint success;
|
||||
gint policy;
|
||||
gchar *policyName;
|
||||
|
||||
/* Get policy value to set for domain */
|
||||
gtk_tree_model_get(gtk_combo_box_get_model(GTK_COMBO_BOX(priv->addDomainPolicyCombo)),
|
||||
&policyIter,
|
||||
0, &policy,
|
||||
1, &policyName,
|
||||
-1);
|
||||
|
||||
/* Add domain name and the selected policy to database */
|
||||
sql=sqlite3_mprintf("INSERT OR REPLACE INTO policies (domain, value) VALUES ('%q', %d);",
|
||||
realDomain,
|
||||
policy);
|
||||
success=sqlite3_exec(priv->database, sql, NULL, NULL, &error);
|
||||
|
||||
/* Show error message if any */
|
||||
if(success==SQLITE_OK)
|
||||
{
|
||||
gtk_list_store_append(priv->listStore, &policyIter);
|
||||
gtk_list_store_set(priv->listStore,
|
||||
&policyIter,
|
||||
DOMAIN_COLUMN, realDomain,
|
||||
POLICY_COLUMN, policyName,
|
||||
-1);
|
||||
}
|
||||
else g_warning(_("SQL fails: %s"), error);
|
||||
|
||||
|
||||
if(error) sqlite3_free(error);
|
||||
|
||||
/* Free allocated resources */
|
||||
sqlite3_free(sql);
|
||||
}
|
||||
|
||||
/* Free allocated resources */
|
||||
g_free(realDomain);
|
||||
g_free(domain);
|
||||
}
|
||||
|
||||
/* Entry containing domain name which may be added to list has changed */
|
||||
static void _cookie_permission_manager_preferences_on_add_domain_entry_changed(CookiePermissionManagerPreferencesWindow *self,
|
||||
GtkEditable *inEditable)
|
||||
{
|
||||
CookiePermissionManagerPreferencesWindowPrivate *priv=self->priv;
|
||||
gchar *asciiDomain, *checkAsciiDomain;
|
||||
gchar *asciiDomainStart, *asciiDomainEnd;
|
||||
gint dots;
|
||||
gboolean isValid=FALSE;
|
||||
|
||||
/* Get ASCII representation of domain name entered */
|
||||
asciiDomain=g_hostname_to_ascii(gtk_entry_get_text(GTK_ENTRY(priv->addDomainEntry)));
|
||||
|
||||
/* Trim whitespaces from start and end of entered domain name */
|
||||
asciiDomainStart=asciiDomain;
|
||||
while(*asciiDomainStart && g_ascii_isspace(*asciiDomainStart)) asciiDomainStart++;
|
||||
|
||||
asciiDomainEnd=asciiDomain+strlen(asciiDomain)-1;
|
||||
while(*asciiDomainEnd && g_ascii_isspace(*asciiDomainEnd)) asciiDomainEnd--;
|
||||
|
||||
/* We allow only domain names and not cookie domain name so entered name
|
||||
* must not start with a dot
|
||||
*/
|
||||
checkAsciiDomain=asciiDomainStart;
|
||||
isValid=(*asciiDomainStart!='.' && *asciiDomainEnd!='.');
|
||||
|
||||
/* Now check if ASCII domain name is valid (very very simple check)
|
||||
* and contains a hostname besides TLD
|
||||
*/
|
||||
dots=0;
|
||||
|
||||
while(*checkAsciiDomain &&
|
||||
checkAsciiDomain<=asciiDomainEnd &&
|
||||
isValid)
|
||||
{
|
||||
/* Check for dot as (at least the first one) seperates hostname from TLD */
|
||||
if(*checkAsciiDomain=='.') dots++;
|
||||
else
|
||||
{
|
||||
/* Check for valid characters in domain name.
|
||||
* Valid domain name can only contain ASCII alphabetic letters,
|
||||
* digits (0-9) and hyphens ('-')
|
||||
*/
|
||||
isValid=(g_ascii_isalpha(*checkAsciiDomain) ||
|
||||
g_ascii_isdigit(*checkAsciiDomain) ||
|
||||
*checkAsciiDomain=='-');
|
||||
}
|
||||
|
||||
checkAsciiDomain++;
|
||||
}
|
||||
|
||||
/* If we have not reached the trimmed end of string something must have gone wrong
|
||||
* and domain entered is invalid. If domain name entered excluding dots is longer
|
||||
* than 255 character it is also invalid.
|
||||
*/
|
||||
if(checkAsciiDomain<asciiDomainEnd) isValid=FALSE;
|
||||
else if((checkAsciiDomain-asciiDomainStart-dots)>255) isValid=FALSE;
|
||||
|
||||
/* We need at least one dot in domain name (minimum number of dots to seperate
|
||||
* hostname from TLD)
|
||||
*/
|
||||
isValid=(isValid && dots>0);
|
||||
|
||||
/* Activate "add" button if hostname (equal to domain name here) is valid */
|
||||
gtk_widget_set_sensitive(priv->addDomainButton, isValid);
|
||||
|
||||
/* Free allocated resources */
|
||||
g_free(asciiDomain);
|
||||
}
|
||||
|
||||
/* Fill domain list with stored policies */
|
||||
static void _cookie_permission_manager_preferences_window_fill(CookiePermissionManagerPreferencesWindow *self)
|
||||
{
|
||||
CookiePermissionManagerPreferencesWindowPrivate *priv=self->priv;
|
||||
gint success;
|
||||
sqlite3_stmt *statement=NULL;
|
||||
|
||||
/* Clear tree/list view */
|
||||
gtk_list_store_clear(priv->listStore);
|
||||
|
||||
/* If no database is present return here */
|
||||
if(!priv->database) return;
|
||||
|
||||
/* Fill list store with policies from database */
|
||||
success=sqlite3_prepare_v2(priv->database,
|
||||
"SELECT domain, value FROM policies;",
|
||||
-1,
|
||||
&statement,
|
||||
NULL);
|
||||
if(statement && success==SQLITE_OK)
|
||||
{
|
||||
gchar *domain;
|
||||
gint policy;
|
||||
gchar *policyName;
|
||||
GtkTreeIter iter;
|
||||
|
||||
while(sqlite3_step(statement)==SQLITE_ROW)
|
||||
{
|
||||
/* Get values */
|
||||
domain=(gchar*)sqlite3_column_text(statement, 0);
|
||||
policy=sqlite3_column_int(statement, 1);
|
||||
|
||||
switch(policy)
|
||||
{
|
||||
case COOKIE_PERMISSION_MANAGER_POLICY_ACCEPT:
|
||||
policyName=_("Accept");
|
||||
break;
|
||||
|
||||
case COOKIE_PERMISSION_MANAGER_POLICY_ACCEPT_FOR_SESSION:
|
||||
policyName=_("Accept for session");
|
||||
break;
|
||||
|
||||
case COOKIE_PERMISSION_MANAGER_POLICY_BLOCK:
|
||||
policyName=_("Block");
|
||||
break;
|
||||
|
||||
default:
|
||||
policyName=NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
if(policyName)
|
||||
{
|
||||
gtk_list_store_append(priv->listStore, &iter);
|
||||
gtk_list_store_set(priv->listStore,
|
||||
&iter,
|
||||
DOMAIN_COLUMN, domain,
|
||||
POLICY_COLUMN, policyName,
|
||||
-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else g_warning(_("SQL fails: %s"), sqlite3_errmsg(priv->database));
|
||||
|
||||
sqlite3_finalize(statement);
|
||||
}
|
||||
|
||||
/* Database instance in manager changed */
|
||||
static void _cookie_permission_manager_preferences_window_manager_database_changed(CookiePermissionManagerPreferencesWindow *self,
|
||||
GParamSpec *inSpec,
|
||||
gpointer inUserData)
|
||||
{
|
||||
CookiePermissionManagerPreferencesWindowPrivate *priv=self->priv;
|
||||
CookiePermissionManager *manager=COOKIE_PERMISSION_MANAGER(inUserData);
|
||||
const gchar *databaseFilename;
|
||||
|
||||
/* Close connection to any open database */
|
||||
if(priv->database) sqlite3_close(priv->database);
|
||||
priv->database=NULL;
|
||||
|
||||
/* Get pointer to new database and open database */
|
||||
g_object_get(manager, "database-filename", &databaseFilename, NULL);
|
||||
if(databaseFilename)
|
||||
{
|
||||
gint success;
|
||||
|
||||
success=sqlite3_open(databaseFilename, &priv->database);
|
||||
if(success!=SQLITE_OK)
|
||||
{
|
||||
g_warning(_("Could not open database of extenstion: %s"), sqlite3_errmsg(priv->database));
|
||||
|
||||
if(priv->database) sqlite3_close(priv->database);
|
||||
priv->database=NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Fill list with new database */
|
||||
_cookie_permission_manager_preferences_window_fill(self);
|
||||
|
||||
/* Set up availability of management buttons */
|
||||
gtk_widget_set_sensitive(priv->deleteAllButton, priv->database!=NULL);
|
||||
gtk_widget_set_sensitive(priv->list, priv->database!=NULL);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Ask-for-unknown-policy in manager changed or check-box changed */
|
||||
static void _cookie_permission_manager_preferences_window_manager_ask_for_unknown_policy_changed(CookiePermissionManagerPreferencesWindow *self,
|
||||
GParamSpec *inSpec,
|
||||
gpointer inUserData)
|
||||
{
|
||||
CookiePermissionManagerPreferencesWindowPrivate *priv=self->priv;
|
||||
CookiePermissionManager *manager=COOKIE_PERMISSION_MANAGER(inUserData);
|
||||
gboolean doAsk;
|
||||
|
||||
/* Get new ask-for-unknown-policy value */
|
||||
g_object_get(manager, "ask-for-unknown-policy", &doAsk, NULL);
|
||||
|
||||
/* Set toogle in widget (but block signal for toggle) */
|
||||
g_signal_handler_block(priv->askForUnknownPolicyCheckbox, priv->signalAskForUnknownPolicyID);
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(priv->askForUnknownPolicyCheckbox), doAsk);
|
||||
g_signal_handler_unblock(priv->askForUnknownPolicyCheckbox, priv->signalAskForUnknownPolicyID);
|
||||
}
|
||||
|
||||
static void _cookie_permission_manager_preferences_window_ask_for_unknown_policy_changed(CookiePermissionManagerPreferencesWindow *self,
|
||||
gpointer *inUserData)
|
||||
{
|
||||
CookiePermissionManagerPreferencesWindowPrivate *priv=self->priv;
|
||||
gboolean doAsk;
|
||||
|
||||
/* Get toogle state of widget (but block signal for manager) and set in manager */
|
||||
g_signal_handler_block(priv->manager, priv->signalManagerAskForUnknownPolicyID);
|
||||
doAsk=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(priv->askForUnknownPolicyCheckbox));
|
||||
g_object_set(priv->manager, "ask-for-unknown-policy", doAsk, NULL);
|
||||
g_signal_handler_unblock(priv->manager, priv->signalManagerAskForUnknownPolicyID);
|
||||
}
|
||||
|
||||
/* Selection in list changed */
|
||||
void _cookie_permission_manager_preferences_changed_selection(CookiePermissionManagerPreferencesWindow *self,
|
||||
GtkTreeSelection *inSelection)
|
||||
{
|
||||
gboolean selected=(gtk_tree_selection_count_selected_rows(inSelection)>0 ? TRUE: FALSE);
|
||||
|
||||
gtk_widget_set_sensitive(self->priv->deleteButton, selected);
|
||||
}
|
||||
|
||||
/* Delete button was clicked on selection */
|
||||
void _cookie_permission_manager_preferences_on_delete_selection(CookiePermissionManagerPreferencesWindow *self,
|
||||
GtkButton *inButton)
|
||||
{
|
||||
CookiePermissionManagerPreferencesWindowPrivate *priv=self->priv;
|
||||
GList *rows, *row, *refs=NULL;
|
||||
GtkTreeRowReference *ref;
|
||||
GtkTreeModel *model=GTK_TREE_MODEL(priv->listStore);
|
||||
GtkTreeIter iter;
|
||||
GtkTreePath *path;
|
||||
gchar *domain;
|
||||
gchar *sql;
|
||||
gint success;
|
||||
gchar *error;
|
||||
|
||||
/* Get selected rows in list and create a row reference because
|
||||
* we will modify the model while iterating through selected rows
|
||||
*/
|
||||
rows=gtk_tree_selection_get_selected_rows(priv->listSelection, &model);
|
||||
for(row=rows; row; row=row->next)
|
||||
{
|
||||
ref=gtk_tree_row_reference_new(model, (GtkTreePath*)row->data);
|
||||
refs=g_list_prepend(refs, ref);
|
||||
}
|
||||
g_list_foreach(rows,(GFunc)gtk_tree_path_free, NULL);
|
||||
g_list_free(rows);
|
||||
|
||||
/* Delete each selected row by its reference */
|
||||
for(row=refs; row; row=row->next)
|
||||
{
|
||||
/* Get domain from selected row */
|
||||
path=gtk_tree_row_reference_get_path((GtkTreeRowReference*)row->data);
|
||||
gtk_tree_model_get_iter(model, &iter, path);
|
||||
gtk_tree_model_get(model, &iter, DOMAIN_COLUMN, &domain, -1);
|
||||
|
||||
/* Delete domain from database */
|
||||
sql=sqlite3_mprintf("DELETE FROM policies WHERE domain='%q';", domain);
|
||||
success=sqlite3_exec(priv->database,
|
||||
sql,
|
||||
NULL,
|
||||
NULL,
|
||||
&error);
|
||||
if(success!=SQLITE_OK || error)
|
||||
{
|
||||
if(error)
|
||||
{
|
||||
g_critical(_("Failed to execute database statement: %s"), error);
|
||||
sqlite3_free(error);
|
||||
}
|
||||
else g_critical(_("Failed to execute database statement: %s"), sqlite3_errmsg(priv->database));
|
||||
}
|
||||
sqlite3_free(sql);
|
||||
|
||||
/* Delete row from model */
|
||||
gtk_list_store_remove(priv->listStore, &iter);
|
||||
}
|
||||
g_list_foreach(refs,(GFunc)gtk_tree_row_reference_free, NULL);
|
||||
g_list_free(refs);
|
||||
}
|
||||
|
||||
/* Delete all button was clicked */
|
||||
void _cookie_permission_manager_preferences_on_delete_all(CookiePermissionManagerPreferencesWindow *self,
|
||||
GtkButton *inButton)
|
||||
{
|
||||
CookiePermissionManagerPreferencesWindowPrivate *priv=self->priv;
|
||||
gint success;
|
||||
gchar *error=NULL;
|
||||
GtkWidget *dialog;
|
||||
gint dialogResponse;
|
||||
|
||||
/* Ask user if he really wants to delete all permissions */
|
||||
dialog=gtk_message_dialog_new(GTK_WINDOW(self),
|
||||
GTK_DIALOG_MODAL,
|
||||
GTK_MESSAGE_QUESTION,
|
||||
GTK_BUTTONS_YES_NO,
|
||||
_("Do you really want to delete all cookie permissions?"));
|
||||
|
||||
gtk_window_set_title(GTK_WINDOW(dialog), _("Delete all cookie permissions?"));
|
||||
gtk_window_set_icon_name(GTK_WINDOW(dialog), GTK_STOCK_PROPERTIES);
|
||||
|
||||
gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
|
||||
_("This action will delete all cookie permissions. "
|
||||
"You will be asked for permissions again for each web site visited."));
|
||||
|
||||
dialogResponse=gtk_dialog_run(GTK_DIALOG(dialog));
|
||||
gtk_widget_destroy(dialog);
|
||||
|
||||
if(dialogResponse==GTK_RESPONSE_NO) return;
|
||||
|
||||
/* Delete all permission */
|
||||
success=sqlite3_exec(priv->database,
|
||||
"DELETE FROM policies;",
|
||||
NULL,
|
||||
NULL,
|
||||
&error);
|
||||
|
||||
if(success!=SQLITE_OK || error)
|
||||
{
|
||||
if(error)
|
||||
{
|
||||
g_critical(_("Failed to execute database statement: %s"), error);
|
||||
sqlite3_free(error);
|
||||
}
|
||||
}
|
||||
|
||||
/* Re-setup list */
|
||||
_cookie_permission_manager_preferences_window_fill(self);
|
||||
}
|
||||
|
||||
/* Sorting callbacks */
|
||||
static gint _cookie_permission_manager_preferences_sort_string_callback(GtkTreeModel *inModel,
|
||||
GtkTreeIter *inLeft,
|
||||
GtkTreeIter *inRight,
|
||||
gpointer inUserData)
|
||||
{
|
||||
gchar *left, *right;
|
||||
gint column=GPOINTER_TO_INT(inUserData);
|
||||
gint result;
|
||||
|
||||
gtk_tree_model_get(inModel, inLeft, column, &left, -1);
|
||||
gtk_tree_model_get(inModel, inRight, column, &right, -1);
|
||||
|
||||
result=g_strcmp0(left, right);
|
||||
|
||||
g_free(left);
|
||||
g_free(right);
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
/* IMPLEMENTATION: GObject */
|
||||
|
||||
/* Finalize this object */
|
||||
static void cookie_permission_manager_preferences_window_finalize(GObject *inObject)
|
||||
{
|
||||
CookiePermissionManagerPreferencesWindowPrivate *priv=COOKIE_PERMISSION_MANAGER_PREFERENCES_WINDOW(inObject)->priv;
|
||||
|
||||
/* Dispose allocated resources */
|
||||
if(priv->database) sqlite3_close(priv->database);
|
||||
priv->database=NULL;
|
||||
|
||||
if(priv->manager)
|
||||
{
|
||||
if(priv->signalManagerChangedDatabaseID) g_signal_handler_disconnect(priv->manager, priv->signalManagerChangedDatabaseID);
|
||||
priv->signalManagerChangedDatabaseID=0;
|
||||
|
||||
if(priv->signalManagerAskForUnknownPolicyID) g_signal_handler_disconnect(priv->manager, priv->signalManagerAskForUnknownPolicyID);
|
||||
priv->signalManagerAskForUnknownPolicyID=0;
|
||||
|
||||
g_object_unref(priv->manager);
|
||||
priv->manager=NULL;
|
||||
}
|
||||
|
||||
/* Call parent's class finalize method */
|
||||
G_OBJECT_CLASS(cookie_permission_manager_preferences_window_parent_class)->finalize(inObject);
|
||||
}
|
||||
|
||||
/* Set/get properties */
|
||||
static void cookie_permission_manager_preferences_window_set_property(GObject *inObject,
|
||||
guint inPropID,
|
||||
const GValue *inValue,
|
||||
GParamSpec *inSpec)
|
||||
{
|
||||
CookiePermissionManagerPreferencesWindow *self=COOKIE_PERMISSION_MANAGER_PREFERENCES_WINDOW(inObject);
|
||||
CookiePermissionManagerPreferencesWindowPrivate *priv=self->priv;
|
||||
GObject *manager;
|
||||
|
||||
switch(inPropID)
|
||||
{
|
||||
/* Construct-only properties */
|
||||
case PROP_MANAGER:
|
||||
/* Release old manager if available and disconnect signals */
|
||||
if(priv->manager)
|
||||
{
|
||||
if(priv->signalManagerChangedDatabaseID) g_signal_handler_disconnect(priv->manager, priv->signalManagerChangedDatabaseID);
|
||||
priv->signalManagerChangedDatabaseID=0;
|
||||
|
||||
if(priv->signalManagerAskForUnknownPolicyID) g_signal_handler_disconnect(priv->manager, priv->signalManagerAskForUnknownPolicyID);
|
||||
priv->signalManagerAskForUnknownPolicyID=0;
|
||||
|
||||
g_object_unref(priv->manager);
|
||||
priv->manager=NULL;
|
||||
}
|
||||
|
||||
/* Set new cookie permission manager and
|
||||
* listen to changes in database property
|
||||
*/
|
||||
manager=g_value_get_object(inValue);
|
||||
if(manager)
|
||||
{
|
||||
priv->manager=g_object_ref(manager);
|
||||
|
||||
priv->signalManagerChangedDatabaseID=
|
||||
g_signal_connect_swapped(priv->manager,
|
||||
"notify::database-filename",
|
||||
G_CALLBACK(_cookie_permission_manager_preferences_window_manager_database_changed),
|
||||
self);
|
||||
_cookie_permission_manager_preferences_window_manager_database_changed(self, NULL, priv->manager);
|
||||
|
||||
priv->signalManagerAskForUnknownPolicyID=
|
||||
g_signal_connect_swapped(priv->manager,
|
||||
"notify::ask-for-unknown-policy",
|
||||
G_CALLBACK(_cookie_permission_manager_preferences_window_manager_ask_for_unknown_policy_changed),
|
||||
self);
|
||||
_cookie_permission_manager_preferences_window_manager_ask_for_unknown_policy_changed(self, NULL, priv->manager);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID(inObject, inPropID, inSpec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void cookie_permission_manager_preferences_window_get_property(GObject *inObject,
|
||||
guint inPropID,
|
||||
GValue *outValue,
|
||||
GParamSpec *inSpec)
|
||||
{
|
||||
CookiePermissionManagerPreferencesWindow *self=COOKIE_PERMISSION_MANAGER_PREFERENCES_WINDOW(inObject);
|
||||
|
||||
switch(inPropID)
|
||||
{
|
||||
case PROP_MANAGER:
|
||||
g_value_set_object(outValue, self->priv->manager);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID(inObject, inPropID, inSpec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Class initialization
|
||||
* Override functions in parent classes and define properties and signals
|
||||
*/
|
||||
static void cookie_permission_manager_preferences_window_class_init(CookiePermissionManagerPreferencesWindowClass *klass)
|
||||
{
|
||||
GObjectClass *gobjectClass=G_OBJECT_CLASS(klass);
|
||||
|
||||
/* Override functions */
|
||||
gobjectClass->finalize=cookie_permission_manager_preferences_window_finalize;
|
||||
gobjectClass->set_property=cookie_permission_manager_preferences_window_set_property;
|
||||
gobjectClass->get_property=cookie_permission_manager_preferences_window_get_property;
|
||||
|
||||
/* Set up private structure */
|
||||
g_type_class_add_private(klass, sizeof(CookiePermissionManagerPreferencesWindowPrivate));
|
||||
|
||||
/* Define properties */
|
||||
CookiePermissionManagerPreferencesWindowProperties[PROP_MANAGER]=
|
||||
g_param_spec_object("manager",
|
||||
_("Cookie permission manager"),
|
||||
_("Instance of current cookie permission manager"),
|
||||
TYPE_COOKIE_PERMISSION_MANAGER,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
|
||||
|
||||
g_object_class_install_properties(gobjectClass, PROP_LAST, CookiePermissionManagerPreferencesWindowProperties);
|
||||
}
|
||||
|
||||
/* Object initialization
|
||||
* Create private structure and set up default values
|
||||
*/
|
||||
static void cookie_permission_manager_preferences_window_init(CookiePermissionManagerPreferencesWindow *self)
|
||||
{
|
||||
CookiePermissionManagerPreferencesWindowPrivate *priv;
|
||||
GtkTreeSortable *sortableList;
|
||||
GtkCellRenderer *renderer;
|
||||
GtkTreeViewColumn *column;
|
||||
GtkWidget *widget;
|
||||
gchar *text;
|
||||
gchar *dialogTitle;
|
||||
GtkWidget *scrolled;
|
||||
GtkWidget *vbox;
|
||||
GtkWidget *hbox;
|
||||
gint width, height;
|
||||
GtkListStore *list;
|
||||
GtkTreeIter listIter;
|
||||
|
||||
priv=self->priv=COOKIE_PERMISSION_MANAGER_PREFERENCES_WINDOW_GET_PRIVATE(self);
|
||||
|
||||
/* Set up default values */
|
||||
priv->manager=NULL;
|
||||
|
||||
/* Get content area to add gui controls to */
|
||||
priv->contentArea=gtk_dialog_get_content_area(GTK_DIALOG(self));
|
||||
#ifdef HAVE_GTK3
|
||||
vbox=gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
|
||||
gtk_box_set_homogeneous(GTK_BOX(vbox), FALSE);
|
||||
#else
|
||||
vbox=gtk_vbox_new(FALSE, 0);
|
||||
#endif
|
||||
|
||||
/* Set up dialog */
|
||||
dialogTitle=_("Configure cookie permission");
|
||||
|
||||
gtk_window_set_title(GTK_WINDOW(self), dialogTitle);
|
||||
gtk_window_set_icon_name(GTK_WINDOW(self), GTK_STOCK_PROPERTIES);
|
||||
|
||||
sokoke_widget_get_text_size(GTK_WIDGET(self), "M", &width, &height);
|
||||
gtk_window_set_default_size(GTK_WINDOW(self), width*52, -1);
|
||||
|
||||
widget=sokoke_xfce_header_new(gtk_window_get_icon_name(GTK_WINDOW(self)), dialogTitle);
|
||||
if(widget) gtk_box_pack_start(GTK_BOX(priv->contentArea), widget, FALSE, FALSE, 0);
|
||||
|
||||
gtk_dialog_add_button(GTK_DIALOG(self), GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE);
|
||||
|
||||
/* Set up description */
|
||||
widget=gtk_label_new(NULL);
|
||||
text=g_strdup_printf(_("Below is a list of all web sites and the policy set for them. "
|
||||
"You can delete policies by marking the entries and clicking on <i>Delete</i>."
|
||||
"You can also add a policy for a domain manually by entering the domain below, "
|
||||
"choosing the policy and clicking on <i>Add</i>."));
|
||||
gtk_label_set_markup(GTK_LABEL(widget), text);
|
||||
g_free(text);
|
||||
gtk_label_set_line_wrap(GTK_LABEL(widget), TRUE);
|
||||
gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, FALSE, 4);
|
||||
|
||||
/* Set up model for cookie domain list */
|
||||
priv->listStore=gtk_list_store_new(N_COLUMN,
|
||||
G_TYPE_STRING, /* DOMAIN_COLUMN */
|
||||
G_TYPE_STRING /* POLICY_COLUMN */);
|
||||
|
||||
sortableList=GTK_TREE_SORTABLE(priv->listStore);
|
||||
gtk_tree_sortable_set_sort_func(sortableList,
|
||||
DOMAIN_COLUMN,
|
||||
(GtkTreeIterCompareFunc)_cookie_permission_manager_preferences_sort_string_callback,
|
||||
GINT_TO_POINTER(DOMAIN_COLUMN),
|
||||
NULL);
|
||||
gtk_tree_sortable_set_sort_func(sortableList,
|
||||
POLICY_COLUMN,
|
||||
(GtkTreeIterCompareFunc)_cookie_permission_manager_preferences_sort_string_callback,
|
||||
GINT_TO_POINTER(POLICY_COLUMN),
|
||||
NULL);
|
||||
gtk_tree_sortable_set_sort_column_id(sortableList, DOMAIN_COLUMN, GTK_SORT_ASCENDING);
|
||||
|
||||
/* Set up domain addition widgets */
|
||||
#ifdef HAVE_GTK3
|
||||
hbox=gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
|
||||
gtk_box_set_homogeneous(GTK_BOX(hbox), FALSE);
|
||||
#else
|
||||
hbox=gtk_hbox_new(FALSE, 0);
|
||||
#endif
|
||||
|
||||
priv->addDomainEntry=gtk_entry_new();
|
||||
gtk_entry_set_max_length(GTK_ENTRY(priv->addDomainEntry), 64);
|
||||
gtk_container_add(GTK_CONTAINER(hbox), priv->addDomainEntry);
|
||||
g_signal_connect_swapped(priv->addDomainEntry, "changed", G_CALLBACK(_cookie_permission_manager_preferences_on_add_domain_entry_changed), self);
|
||||
|
||||
list=gtk_list_store_new(2, G_TYPE_INT, G_TYPE_STRING);
|
||||
gtk_list_store_append(list, &listIter);
|
||||
gtk_list_store_set(list, &listIter, 0, COOKIE_PERMISSION_MANAGER_POLICY_ACCEPT, 1, _("Accept"), -1);
|
||||
gtk_list_store_append(list, &listIter);
|
||||
gtk_list_store_set(list, &listIter, 0, COOKIE_PERMISSION_MANAGER_POLICY_ACCEPT_FOR_SESSION, 1, _("Accept for session"), -1);
|
||||
gtk_list_store_append(list, &listIter);
|
||||
gtk_list_store_set(list, &listIter, 0, COOKIE_PERMISSION_MANAGER_POLICY_BLOCK, 1, _("Block"), -1);
|
||||
|
||||
priv->addDomainPolicyCombo=gtk_combo_box_new_with_model(GTK_TREE_MODEL(list));
|
||||
gtk_combo_box_set_active(GTK_COMBO_BOX(priv->addDomainPolicyCombo), 0);
|
||||
gtk_container_add(GTK_CONTAINER(hbox), priv->addDomainPolicyCombo);
|
||||
|
||||
renderer=gtk_cell_renderer_text_new();
|
||||
gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(priv->addDomainPolicyCombo), renderer, TRUE);
|
||||
gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(priv->addDomainPolicyCombo), renderer, "text", 1);
|
||||
|
||||
priv->addDomainButton=gtk_button_new_from_stock(GTK_STOCK_ADD);
|
||||
gtk_widget_set_sensitive(priv->addDomainButton, FALSE);
|
||||
gtk_container_add(GTK_CONTAINER(hbox), priv->addDomainButton);
|
||||
g_signal_connect_swapped(priv->addDomainButton, "clicked", G_CALLBACK(_cookie_permission_manager_preferences_on_add_domain_clicked), self);
|
||||
|
||||
gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 5);
|
||||
|
||||
/* Set up cookie domain list */
|
||||
priv->list=gtk_tree_view_new_with_model(GTK_TREE_MODEL(priv->listStore));
|
||||
|
||||
#ifndef HAVE_GTK3
|
||||
gtk_widget_set_size_request(priv->list, -1, 300);
|
||||
#endif
|
||||
|
||||
priv->listSelection=gtk_tree_view_get_selection(GTK_TREE_VIEW(priv->list));
|
||||
gtk_tree_selection_set_mode(priv->listSelection, GTK_SELECTION_MULTIPLE);
|
||||
g_signal_connect_swapped(priv->listSelection, "changed", G_CALLBACK(_cookie_permission_manager_preferences_changed_selection), self);
|
||||
|
||||
renderer=gtk_cell_renderer_text_new();
|
||||
column=gtk_tree_view_column_new_with_attributes(_("Domain"),
|
||||
renderer,
|
||||
"text", DOMAIN_COLUMN,
|
||||
NULL);
|
||||
gtk_tree_view_column_set_sort_column_id(column, DOMAIN_COLUMN);
|
||||
gtk_tree_view_append_column(GTK_TREE_VIEW(priv->list), column);
|
||||
|
||||
renderer=gtk_cell_renderer_text_new();
|
||||
column=gtk_tree_view_column_new_with_attributes(_("Policy"),
|
||||
renderer,
|
||||
"text", POLICY_COLUMN,
|
||||
NULL);
|
||||
gtk_tree_view_column_set_sort_column_id(column, POLICY_COLUMN);
|
||||
gtk_tree_view_append_column(GTK_TREE_VIEW(priv->list), column);
|
||||
|
||||
scrolled=gtk_scrolled_window_new(NULL, NULL);
|
||||
#ifdef HAVE_GTK3
|
||||
gtk_scrolled_window_set_min_content_height(GTK_SCROLLED_WINDOW(scrolled), height*10);
|
||||
#endif
|
||||
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
|
||||
gtk_container_add(GTK_CONTAINER(scrolled), priv->list);
|
||||
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
|
||||
gtk_box_pack_start(GTK_BOX(vbox), scrolled, TRUE, TRUE, 5);
|
||||
|
||||
/* Set up cookie domain list management buttons */
|
||||
#ifdef HAVE_GTK3
|
||||
hbox=gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
|
||||
gtk_box_set_homogeneous(GTK_BOX(hbox), FALSE);
|
||||
#else
|
||||
hbox=gtk_hbox_new(FALSE, 0);
|
||||
#endif
|
||||
|
||||
priv->deleteButton=gtk_button_new_from_stock(GTK_STOCK_DELETE);
|
||||
gtk_widget_set_sensitive(priv->deleteButton, FALSE);
|
||||
gtk_container_add(GTK_CONTAINER(hbox), priv->deleteButton);
|
||||
g_signal_connect_swapped(priv->deleteButton, "clicked", G_CALLBACK(_cookie_permission_manager_preferences_on_delete_selection), self);
|
||||
|
||||
priv->deleteAllButton=gtk_button_new_with_mnemonic(_("Delete _all"));
|
||||
gtk_button_set_image(GTK_BUTTON(priv->deleteAllButton), gtk_image_new_from_stock(GTK_STOCK_DELETE, GTK_ICON_SIZE_BUTTON));
|
||||
gtk_widget_set_sensitive(priv->deleteAllButton, FALSE);
|
||||
gtk_container_add(GTK_CONTAINER(hbox), priv->deleteAllButton);
|
||||
g_signal_connect_swapped(priv->deleteAllButton, "clicked", G_CALLBACK(_cookie_permission_manager_preferences_on_delete_all), self);
|
||||
|
||||
gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 5);
|
||||
|
||||
/* Add "ask-for-unknown-policy" checkbox */
|
||||
priv->askForUnknownPolicyCheckbox=gtk_check_button_new_with_mnemonic(_("A_sk for policy if unknown for a domain"));
|
||||
priv->signalAskForUnknownPolicyID=g_signal_connect_swapped(priv->askForUnknownPolicyCheckbox,
|
||||
"toggled",
|
||||
G_CALLBACK(_cookie_permission_manager_preferences_window_ask_for_unknown_policy_changed),
|
||||
self);
|
||||
gtk_box_pack_start(GTK_BOX(vbox), priv->askForUnknownPolicyCheckbox, TRUE, TRUE, 5);
|
||||
|
||||
/* Finalize setup of content area */
|
||||
gtk_container_add(GTK_CONTAINER(priv->contentArea), vbox);
|
||||
}
|
||||
|
||||
/* Implementation: Public API */
|
||||
|
||||
/* Create new object */
|
||||
GtkWidget* cookie_permission_manager_preferences_window_new(CookiePermissionManager *inManager)
|
||||
{
|
||||
return(g_object_new(TYPE_COOKIE_PERMISSION_MANAGER_PREFERENCES_WINDOW,
|
||||
"manager", inManager,
|
||||
NULL));
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
Copyright (C) 2013 Stephan Haller <nomad@froevel.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 __COOKIE_PERMISSION_MANAGER_PREFERENCES_WINDOW__
|
||||
#define __COOKIE_PERMISSION_MANAGER_PREFERENCES_WINDOW__
|
||||
|
||||
#include "config.h"
|
||||
#include <midori/midori.h>
|
||||
|
||||
#include "cookie-permission-manager.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define TYPE_COOKIE_PERMISSION_MANAGER_PREFERENCES_WINDOW (cookie_permission_manager_preferences_window_get_type())
|
||||
#define COOKIE_PERMISSION_MANAGER_PREFERENCES_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_COOKIE_PERMISSION_MANAGER_PREFERENCES_WINDOW, CookiePermissionManagerPreferencesWindow))
|
||||
#define IS_COOKIE_PERMISSION_MANAGER_PREFERENCES_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), TYPE_COOKIE_PERMISSION_MANAGER_PREFERENCES_WINDOW))
|
||||
#define COOKIE_PERMISSION_MANAGER_PREFERENCES_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), TYPE_COOKIE_PERMISSION_MANAGER_PREFERENCES_WINDOW, CookiePermissionManagerPreferencesWindowClass))
|
||||
#define IS_COOKIE_PERMISSION_MANAGER_PREFERENCES_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_COOKIE_PERMISSION_MANAGER_PREFERENCES_WINDOW))
|
||||
#define COOKIE_PERMISSION_MANAGER_PREFERENCES_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), TYPE_COOKIE_PERMISSION_MANAGER_PREFERENCES_WINDOW, CookiePermissionManagerPreferencesWindowClass))
|
||||
|
||||
typedef struct _CookiePermissionManagerPreferencesWindow CookiePermissionManagerPreferencesWindow;
|
||||
typedef struct _CookiePermissionManagerPreferencesWindowClass CookiePermissionManagerPreferencesWindowClass;
|
||||
typedef struct _CookiePermissionManagerPreferencesWindowPrivate CookiePermissionManagerPreferencesWindowPrivate;
|
||||
|
||||
struct _CookiePermissionManagerPreferencesWindow
|
||||
{
|
||||
/* Parent instance */
|
||||
GtkDialog parent_instance;
|
||||
|
||||
/* Private structure */
|
||||
CookiePermissionManagerPreferencesWindowPrivate *priv;
|
||||
};
|
||||
|
||||
struct _CookiePermissionManagerPreferencesWindowClass
|
||||
{
|
||||
/* Parent class */
|
||||
GtkDialogClass parent_class;
|
||||
};
|
||||
|
||||
/* Public API */
|
||||
GType cookie_permission_manager_preferences_window_get_type(void);
|
||||
|
||||
GtkWidget* cookie_permission_manager_preferences_window_new(CookiePermissionManager *inManager);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __COOKIE_PERMISSION_MANAGER_PREFERENCES_WINDOW__ */
|
1127
extensions/cookie-permissions/cookie-permission-manager.c
Normal file
1127
extensions/cookie-permissions/cookie-permission-manager.c
Normal file
File diff suppressed because it is too large
Load diff
72
extensions/cookie-permissions/cookie-permission-manager.h
Normal file
72
extensions/cookie-permissions/cookie-permission-manager.h
Normal file
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
Copyright (C) 2013 Stephan Haller <nomad@froevel.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 __COOKIE_PERMISSION_MANAGER__
|
||||
#define __COOKIE_PERMISSION_MANAGER__
|
||||
|
||||
#include "config.h"
|
||||
#include <midori/midori.h>
|
||||
|
||||
#define COOKIE_PERMISSION_DATABASE "domains.db"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/* Cookie permission manager enums */
|
||||
typedef enum
|
||||
{
|
||||
COOKIE_PERMISSION_MANAGER_POLICY_UNDETERMINED,
|
||||
COOKIE_PERMISSION_MANAGER_POLICY_ACCEPT,
|
||||
COOKIE_PERMISSION_MANAGER_POLICY_ACCEPT_FOR_SESSION,
|
||||
COOKIE_PERMISSION_MANAGER_POLICY_BLOCK
|
||||
} CookiePermissionManagerPolicy;
|
||||
|
||||
/* Cookie permission manager object */
|
||||
#define TYPE_COOKIE_PERMISSION_MANAGER (cookie_permission_manager_get_type())
|
||||
#define COOKIE_PERMISSION_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_COOKIE_PERMISSION_MANAGER, CookiePermissionManager))
|
||||
#define IS_COOKIE_PERMISSION_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), TYPE_COOKIE_PERMISSION_MANAGER))
|
||||
#define COOKIE_PERMISSION_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), TYPE_COOKIE_PERMISSION_MANAGER, CookiePermissionManagerClass))
|
||||
#define IS_COOKIE_PERMISSION_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_COOKIE_PERMISSION_MANAGER))
|
||||
#define COOKIE_PERMISSION_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), TYPE_COOKIE_PERMISSION_MANAGER, CookiePermissionManagerClass))
|
||||
|
||||
typedef struct _CookiePermissionManager CookiePermissionManager;
|
||||
typedef struct _CookiePermissionManagerClass CookiePermissionManagerClass;
|
||||
typedef struct _CookiePermissionManagerPrivate CookiePermissionManagerPrivate;
|
||||
|
||||
struct _CookiePermissionManager
|
||||
{
|
||||
/* Parent instance */
|
||||
GObject parent_instance;
|
||||
|
||||
/* Private structure */
|
||||
CookiePermissionManagerPrivate *priv;
|
||||
};
|
||||
|
||||
struct _CookiePermissionManagerClass
|
||||
{
|
||||
/* Parent class */
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
/* Public API */
|
||||
GType cookie_permission_manager_get_type(void);
|
||||
|
||||
CookiePermissionManager* cookie_permission_manager_new(MidoriExtension *inExtension, MidoriApp *inApp);
|
||||
|
||||
gboolean cookie_permission_manager_get_ask_for_unknown_policy(CookiePermissionManager *self);
|
||||
void cookie_permission_manager_set_ask_for_unknown_policy(CookiePermissionManager *self, gboolean inDoAsk);
|
||||
|
||||
/* Enumeration */
|
||||
GType cookie_permission_manager_policy_get_type(void) G_GNUC_CONST;
|
||||
#define COOKIE_PERMISSION_MANAGER_TYPE_POLICY (cookie_permission_manager_policy_get_type())
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __COOKIE_PERMISSION_MANAGER__ */
|
76
extensions/cookie-permissions/main.c
Normal file
76
extensions/cookie-permissions/main.c
Normal file
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
Copyright (C) 2013 Stephan Haller <nomad@froevel.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 "cookie-permission-manager.h"
|
||||
#include "cookie-permission-manager-preferences-window.h"
|
||||
|
||||
/* Global instance */
|
||||
CookiePermissionManager *cpm=NULL;
|
||||
|
||||
/* This extension was activated */
|
||||
static void _cpm_on_activate(MidoriExtension *inExtension, MidoriApp *inApp, gpointer inUserData)
|
||||
{
|
||||
g_return_if_fail(cpm==NULL);
|
||||
|
||||
cpm=cookie_permission_manager_new(inExtension, inApp);
|
||||
g_object_set(cpm, "ask-for-unknown-policy", midori_extension_get_boolean(inExtension, "ask-for-unknown-policy"), NULL);
|
||||
}
|
||||
|
||||
/* This extension was deactivated */
|
||||
static void _cpm_on_deactivate(MidoriExtension *inExtension, gpointer inUserData)
|
||||
{
|
||||
g_return_if_fail(cpm);
|
||||
|
||||
g_object_unref(cpm);
|
||||
cpm=NULL;
|
||||
}
|
||||
|
||||
/* Preferences of this extension should be opened */
|
||||
static void _cpm_on_open_preferences_response(GtkWidget* inDialog,
|
||||
gint inResponse,
|
||||
MidoriExtension* inExtension)
|
||||
{
|
||||
gtk_widget_destroy(inDialog);
|
||||
}
|
||||
|
||||
static void _cpm_on_open_preferences(MidoriExtension *inExtension)
|
||||
{
|
||||
g_return_if_fail(cpm);
|
||||
|
||||
/* Show preferences window */
|
||||
GtkWidget* dialog;
|
||||
|
||||
dialog=cookie_permission_manager_preferences_window_new(cpm);
|
||||
gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
|
||||
g_signal_connect(dialog, "response", G_CALLBACK (_cpm_on_open_preferences_response), inExtension);
|
||||
gtk_widget_show_all(dialog);
|
||||
}
|
||||
|
||||
/* Main entry for extension */
|
||||
MidoriExtension *extension_init(void)
|
||||
{
|
||||
/* Set up extension */
|
||||
MidoriExtension *extension=g_object_new(MIDORI_TYPE_EXTENSION,
|
||||
"name", _("Cookie Security Manager"),
|
||||
"description", _("Manage cookie permission per site"),
|
||||
"version", "0.1" MIDORI_VERSION_SUFFIX,
|
||||
"authors", "Stephan Haller <nomad@froevel.de>",
|
||||
NULL);
|
||||
|
||||
midori_extension_install_boolean(extension, "ask-for-unknown-policy", TRUE);
|
||||
midori_extension_install_boolean(extension, "show-details-when-ask", FALSE);
|
||||
|
||||
g_signal_connect(extension, "activate", G_CALLBACK(_cpm_on_activate), NULL);
|
||||
g_signal_connect(extension, "deactivate", G_CALLBACK(_cpm_on_deactivate), NULL);
|
||||
g_signal_connect(extension, "open-preferences", G_CALLBACK(_cpm_on_open_preferences), NULL);
|
||||
|
||||
return(extension);
|
||||
}
|
|
@ -28,6 +28,7 @@ copy_tabs_apply_cb (GtkWidget* menuitem,
|
|||
}
|
||||
gtk_clipboard_set_text (clipboard, text->str, -1);
|
||||
g_string_free (text, TRUE);
|
||||
g_list_free (children);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
232
extensions/delayed-load.vala
Normal file
232
extensions/delayed-load.vala
Normal file
|
@ -0,0 +1,232 @@
|
|||
/*
|
||||
Copyright (C) 2012-2013 André Stösel <andre@stoesel.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.
|
||||
*/
|
||||
|
||||
using Gtk;
|
||||
using Katze;
|
||||
using Midori;
|
||||
|
||||
namespace DelayedLoad {
|
||||
private class PreferencesDialog : Gtk.Dialog {
|
||||
protected Manager dl_manager;
|
||||
protected Scale slider;
|
||||
|
||||
public PreferencesDialog (Manager manager) {
|
||||
this.dl_manager = manager;
|
||||
|
||||
this.title = _("Preferences for %s").printf ( _("Delayed load"));
|
||||
if (this.get_class ().find_property ("has-separator") != null)
|
||||
this.set ("has-separator", false);
|
||||
this.border_width = 5;
|
||||
this.set_modal (true);
|
||||
this.set_default_size (350, 100);
|
||||
this.create_widgets ();
|
||||
|
||||
this.response.connect (response_cb);
|
||||
}
|
||||
|
||||
private void response_cb (Gtk.Dialog source, int response_id) {
|
||||
switch (response_id) {
|
||||
case ResponseType.APPLY:
|
||||
this.dl_manager.set_integer ("delay", (int) (this.slider.get_value () * 1000));
|
||||
this.dl_manager.preferences_changed ();
|
||||
this.destroy ();
|
||||
break;
|
||||
case ResponseType.CANCEL:
|
||||
this.destroy ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void create_widgets () {
|
||||
Label text = new Label (_("Delay in seconds until loading the page:"));
|
||||
#if HAVE_GTK3
|
||||
this.slider = new Scale.with_range (Orientation.HORIZONTAL, 0, 15, 0.1);
|
||||
#else
|
||||
this.slider = new HScale.with_range (0, 15, 0.1);
|
||||
#endif
|
||||
|
||||
int delay = this.dl_manager.get_integer ("delay");
|
||||
if (delay > 0)
|
||||
this.slider.set_value ((float)delay / 1000);
|
||||
|
||||
#if HAVE_GTK3
|
||||
Gtk.Box vbox = get_content_area () as Gtk.Box;
|
||||
vbox.pack_start (text, false, false, 0);
|
||||
vbox.pack_start (this.slider, false, true, 0);
|
||||
#else
|
||||
this.vbox.pack_start (text, false, false, 0);
|
||||
this.vbox.pack_start (this.slider, false, true, 0);
|
||||
#endif
|
||||
|
||||
this.add_button (Gtk.STOCK_CANCEL, ResponseType.CANCEL);
|
||||
this.add_button (Gtk.STOCK_APPLY, ResponseType.APPLY);
|
||||
|
||||
this.show_all ();
|
||||
}
|
||||
}
|
||||
|
||||
private class TabShaker : GLib.Object {
|
||||
public unowned Midori.Browser browser;
|
||||
public GLib.PtrArray tasks;
|
||||
|
||||
public bool reload_tab () {
|
||||
if (tasks.len == 1) {
|
||||
Midori.View? view = browser.tab as Midori.View;
|
||||
Midori.View scheduled_view = tasks.index (0) as Midori.View;
|
||||
if (scheduled_view == view) {
|
||||
Katze.Item item = view.get_proxy_item ();
|
||||
item.ref();
|
||||
|
||||
int64 delay = item.get_meta_integer ("delay");
|
||||
if (delay == Midori.Delay.PENDING_UNDELAY) {
|
||||
view.reload (true);
|
||||
}
|
||||
}
|
||||
}
|
||||
tasks.remove_index (0);
|
||||
return false;
|
||||
}
|
||||
|
||||
public TabShaker (Midori.Browser browser) {
|
||||
this.browser = browser;
|
||||
}
|
||||
|
||||
construct {
|
||||
this.tasks = new GLib.PtrArray ();
|
||||
}
|
||||
}
|
||||
|
||||
private class Manager : Midori.Extension {
|
||||
private int timeout = 0;
|
||||
private bool initialized = false;
|
||||
private HashTable<Midori.Browser, TabShaker> tasks;
|
||||
|
||||
public signal void preferences_changed ();
|
||||
|
||||
private void preferences_changed_cb () {
|
||||
this.timeout = get_integer ("delay");
|
||||
}
|
||||
|
||||
private void show_preferences () {
|
||||
PreferencesDialog dialog = new PreferencesDialog (this);
|
||||
dialog.show ();
|
||||
}
|
||||
|
||||
private void schedule_reload (Midori.Browser browser, Midori.View view) {
|
||||
if (this.timeout == 0)
|
||||
view.reload (true);
|
||||
else {
|
||||
unowned TabShaker shaker = tasks.get (browser);
|
||||
if (shaker != null) {
|
||||
shaker.tasks.add (view);
|
||||
Midori.Timeout.add (this.timeout, shaker.reload_tab);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void tab_changed (Midori.View? old_view, Midori.View? new_view) {
|
||||
if (new_view != null) {
|
||||
Midori.App app = get_app ();
|
||||
Midori.Browser browser = app.browser;
|
||||
|
||||
Katze.Item item = new_view.get_proxy_item ();
|
||||
item.ref();
|
||||
|
||||
int64 delay = item.get_meta_integer ("delay");
|
||||
if (delay == Midori.Delay.PENDING_UNDELAY && new_view.progress < 1.0 && this.initialized) {
|
||||
this.schedule_reload (browser, new_view);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool reload_first_tab () {
|
||||
Midori.App app = get_app ();
|
||||
Midori.Browser? browser = app.browser;
|
||||
Midori.View? view = browser.tab as Midori.View;
|
||||
|
||||
if (view != null) {
|
||||
this.initialized = true;
|
||||
Katze.Item item = view.get_proxy_item ();
|
||||
item.ref();
|
||||
|
||||
int64 delay = item.get_meta_integer ("delay");
|
||||
if (delay != Midori.Delay.DELAYED) {
|
||||
if (view.load_status == Midori.LoadStatus.FINISHED) {
|
||||
if (this.timeout != 0)
|
||||
this.tasks.set (browser, new TabShaker (browser));
|
||||
|
||||
if (view.progress < 1.0)
|
||||
this.schedule_reload (browser, view);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void browser_added (Midori.Browser browser) {
|
||||
browser.switch_tab.connect_after (this.tab_changed);
|
||||
}
|
||||
|
||||
private void browser_removed (Midori.Browser browser) {
|
||||
browser.switch_tab.disconnect (this.tab_changed);
|
||||
}
|
||||
|
||||
public void activated (Midori.App app) {
|
||||
/* FIXME: override behavior without changing the preference */
|
||||
app.settings.load_on_startup = MidoriStartup.DELAYED_PAGES;
|
||||
|
||||
this.preferences_changed ();
|
||||
|
||||
Midori.Browser? focused_browser = app.browser;
|
||||
if (focused_browser == null)
|
||||
Midori.Timeout.add (50, this.reload_first_tab);
|
||||
else
|
||||
this.initialized = true;
|
||||
|
||||
foreach (Midori.Browser browser in app.get_browsers ()) {
|
||||
browser_added (browser);
|
||||
}
|
||||
app.add_browser.connect (browser_added);
|
||||
}
|
||||
|
||||
public void deactivated () {
|
||||
Midori.App app = get_app ();
|
||||
foreach (Midori.Browser browser in app.get_browsers ()) {
|
||||
browser_removed (browser);
|
||||
}
|
||||
app.add_browser.disconnect (browser_added);
|
||||
}
|
||||
|
||||
internal Manager () {
|
||||
GLib.Object (name: _("Delayed load"),
|
||||
description: _("Delay page load until you actually use the tab."),
|
||||
version: "0.1",
|
||||
authors: "André Stösel <andre@stoesel.de>");
|
||||
|
||||
install_integer ("delay", 0);
|
||||
|
||||
activate.connect (this.activated);
|
||||
deactivate.connect (this.deactivated);
|
||||
open_preferences.connect (show_preferences);
|
||||
preferences_changed.connect (preferences_changed_cb);
|
||||
|
||||
this.tasks = new HashTable<Midori.Browser, TabShaker> (GLib.direct_hash, GLib.direct_equal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Midori.Extension extension_init () {
|
||||
return new DelayedLoad.Manager ();
|
||||
}
|
||||
|
347
extensions/external-download-manager.vala
Normal file
347
extensions/external-download-manager.vala
Normal file
|
@ -0,0 +1,347 @@
|
|||
/*
|
||||
Copyright (C) 2012 André Stösel <andre@stoesel.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.
|
||||
*/
|
||||
|
||||
using Gtk;
|
||||
using Soup;
|
||||
using Katze;
|
||||
using Midori;
|
||||
using WebKit;
|
||||
|
||||
namespace EDM {
|
||||
#if !HAVE_WIN32
|
||||
[DBus (name = "net.launchpad.steadyflow.App")]
|
||||
interface SteadyflowInterface : GLib.Object {
|
||||
public abstract void AddFile (string url) throws IOError;
|
||||
}
|
||||
#endif
|
||||
|
||||
private class DownloadRequest : GLib.Object {
|
||||
public string uri;
|
||||
public string auth;
|
||||
public string referer;
|
||||
public string? cookie_header;
|
||||
}
|
||||
|
||||
internal Manager manager;
|
||||
|
||||
private class Manager : GLib.Object {
|
||||
private CookieJar cookie_jar;
|
||||
private GLib.PtrArray download_managers = new GLib.PtrArray ();
|
||||
|
||||
public bool download_requested (Midori.View view, WebKit.Download download) {
|
||||
Midori.DownloadType download_type = download.get_data<Midori.DownloadType> ("midori-download-type");
|
||||
|
||||
if (download_type == Midori.DownloadType.SAVE) {
|
||||
var dlReq = new DownloadRequest ();
|
||||
dlReq.uri = download.get_uri ();
|
||||
|
||||
var request = download.get_network_request ();
|
||||
var message = request.get_message ();
|
||||
weak MessageHeaders headers = message.request_headers;
|
||||
|
||||
dlReq.auth = headers.get ("Authorization");
|
||||
dlReq.referer = headers.get ("Referer");
|
||||
dlReq.cookie_header = this.cookie_jar.get_cookies (new Soup.URI (dlReq.uri), true);
|
||||
|
||||
for (var i = 0 ; i < download_managers.len; i++) {
|
||||
var dm = download_managers.index (i) as ExternalDownloadManager;
|
||||
if (dm.download (dlReq))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void tab_added (Midori.Browser browser, Midori.View view) {
|
||||
view.download_requested.connect (download_requested);
|
||||
}
|
||||
|
||||
public void tab_removed (Midori.Browser browser, Midori.View view) {
|
||||
view.download_requested.disconnect(download_requested);
|
||||
}
|
||||
|
||||
public void browser_added (Midori.Browser browser) {
|
||||
foreach (var tab in browser.get_tabs ())
|
||||
tab_added (browser, tab);
|
||||
browser.add_tab.connect (tab_added);
|
||||
browser.remove_tab.connect (tab_removed);
|
||||
}
|
||||
|
||||
public void browser_removed (Midori.Browser browser) {
|
||||
foreach (var tab in browser.get_tabs ())
|
||||
tab_removed (browser, tab);
|
||||
browser.add_tab.disconnect (tab_added);
|
||||
browser.remove_tab.disconnect (tab_removed);
|
||||
}
|
||||
|
||||
public void activated (Midori.Extension extension, Midori.App app) {
|
||||
this.download_managers.add (extension);
|
||||
if (this.download_managers.len == 1) {
|
||||
foreach (var browser in app.get_browsers ())
|
||||
browser_added (browser);
|
||||
app.add_browser.connect (browser_added);
|
||||
}
|
||||
}
|
||||
|
||||
public void deactivated (Midori.Extension extension) {
|
||||
this.download_managers.remove (extension);
|
||||
if (this.download_managers.len == 0) {
|
||||
var app = extension.get_app ();
|
||||
foreach (var browser in app.get_browsers ())
|
||||
browser_removed (browser);
|
||||
app.add_browser.disconnect (browser_added);
|
||||
}
|
||||
}
|
||||
|
||||
construct {
|
||||
var session = WebKit.get_default_session ();
|
||||
this.cookie_jar = session.get_feature (typeof (CookieJar)) as CookieJar;
|
||||
}
|
||||
}
|
||||
|
||||
private abstract class ExternalDownloadManager : Midori.Extension {
|
||||
public void activated (Midori.App app) {
|
||||
manager.activated (this, app);
|
||||
}
|
||||
|
||||
public void deactivated () {
|
||||
manager.deactivated (this);
|
||||
}
|
||||
|
||||
public void handle_exception (GLib.Error error) {
|
||||
string ext_name;
|
||||
this.get ("name",out ext_name);
|
||||
var dialog = new MessageDialog (null, DialogFlags.MODAL,
|
||||
MessageType.ERROR, ButtonsType.CLOSE,
|
||||
_("An error occurred when attempting to download a file with the following plugin:\n" +
|
||||
"%s\n\n" +
|
||||
"Error:\n%s\n\n" +
|
||||
"Carry on without this plugin."
|
||||
),
|
||||
ext_name, error.message);
|
||||
dialog.response.connect ((a) => { dialog.destroy (); });
|
||||
dialog.run ();
|
||||
}
|
||||
|
||||
public abstract bool download (DownloadRequest dlReq);
|
||||
}
|
||||
|
||||
#if !HAVE_WIN32
|
||||
private class Aria2 : ExternalDownloadManager {
|
||||
public override bool download (DownloadRequest dlReq) {
|
||||
var url = value_array_new ();
|
||||
value_array_insert (url, 0, typeof (string), dlReq.uri);
|
||||
|
||||
GLib.HashTable<string, GLib.Value?> options = value_hash_new ();
|
||||
var referer = new GLib.Value (typeof (string));
|
||||
referer.set_string (dlReq.referer);
|
||||
options.insert ("referer", referer);
|
||||
|
||||
var headers = value_array_new ();
|
||||
if (dlReq.cookie_header != null) {
|
||||
value_array_insert (headers, 0, typeof (string), "Cookie: %s".printf(dlReq.cookie_header));
|
||||
}
|
||||
|
||||
if (headers.n_values > 0)
|
||||
options.insert ("header", headers);
|
||||
|
||||
var message = XMLRPC.request_new ("http://127.0.0.1:6800/rpc",
|
||||
"aria2.addUri",
|
||||
typeof (ValueArray), url,
|
||||
typeof(HashTable), options);
|
||||
var session = new SessionSync ();
|
||||
session.send_message (message);
|
||||
|
||||
try {
|
||||
Value v;
|
||||
XMLRPC.parse_method_response ((string) message.response_body.flatten ().data, -1, out v);
|
||||
return true;
|
||||
} catch (Error e) {
|
||||
this.handle_exception (e);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal Aria2 () {
|
||||
GLib.Object (name: _("External Download Manager - Aria2"),
|
||||
description: _("Download files with Aria2"),
|
||||
version: "0.1" + Midori.VERSION_SUFFIX,
|
||||
authors: "André Stösel <andre@stoesel.de>",
|
||||
key: "aria2");
|
||||
|
||||
this.activate.connect (activated);
|
||||
this.deactivate.connect (deactivated);
|
||||
}
|
||||
}
|
||||
|
||||
private class SteadyFlow : ExternalDownloadManager {
|
||||
public override bool download (DownloadRequest dlReq) {
|
||||
try {
|
||||
SteadyflowInterface dm = Bus.get_proxy_sync (
|
||||
BusType.SESSION,
|
||||
"net.launchpad.steadyflow.App",
|
||||
"/net/launchpad/steadyflow/app");
|
||||
dm.AddFile (dlReq.uri);
|
||||
return true;
|
||||
} catch (Error e) {
|
||||
this.handle_exception (e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
internal SteadyFlow () {
|
||||
GLib.Object (name: _("External Download Manager - SteadyFlow"),
|
||||
description: _("Download files with SteadyFlow"),
|
||||
version: "0.1" + Midori.VERSION_SUFFIX,
|
||||
authors: "André Stösel <andre@stoesel.de>",
|
||||
key: "steadyflow");
|
||||
|
||||
this.activate.connect (activated);
|
||||
this.deactivate.connect (deactivated);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
private class CommandLinePreferences : Gtk.Dialog {
|
||||
protected Entry input;
|
||||
protected CommandLine commandline;
|
||||
|
||||
public CommandLinePreferences(CommandLine cl) {
|
||||
this.commandline = cl;
|
||||
|
||||
string ext_name;
|
||||
this.get ("name",out ext_name);
|
||||
|
||||
this.title = _("Preferences for %s").printf (ext_name);
|
||||
if (this.get_class ().find_property ("has-separator") != null)
|
||||
this.set ("has-separator", false);
|
||||
this.border_width = 5;
|
||||
this.set_modal (true);
|
||||
this.set_default_size (400, 100);
|
||||
this.create_widgets ();
|
||||
|
||||
this.response.connect (response_cb);
|
||||
}
|
||||
|
||||
private void response_cb (Gtk.Dialog source, int response_id) {
|
||||
switch (response_id) {
|
||||
case ResponseType.APPLY:
|
||||
this.commandline.set_string ("commandline", this.input.get_text ());
|
||||
this.commandline.update_description (this.commandline.get_app ());
|
||||
this.destroy ();
|
||||
break;
|
||||
case ResponseType.CANCEL:
|
||||
this.destroy ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void create_widgets () {
|
||||
Label text = new Label (_("Command:"));
|
||||
this.input = new Entry ();
|
||||
this.input.set_text (this.commandline.get_string ("commandline"));
|
||||
|
||||
|
||||
#if HAVE_GTK3
|
||||
Gtk.Box vbox = get_content_area () as Gtk.Box;
|
||||
vbox.pack_start (text, false, false, 0);
|
||||
vbox.pack_start (this.input, false, true, 0);
|
||||
#else
|
||||
this.vbox.pack_start (text, false, false, 0);
|
||||
this.vbox.pack_start (this.input, false, true, 0);
|
||||
#endif
|
||||
|
||||
this.add_button (Gtk.STOCK_CANCEL, ResponseType.CANCEL);
|
||||
this.add_button (Gtk.STOCK_APPLY, ResponseType.APPLY);
|
||||
|
||||
this.show_all ();
|
||||
}
|
||||
}
|
||||
|
||||
private class CommandLine : ExternalDownloadManager {
|
||||
private void show_preferences () {
|
||||
CommandLinePreferences dialog = new CommandLinePreferences (this);
|
||||
dialog.show ();
|
||||
}
|
||||
|
||||
public override bool download (DownloadRequest dlReq) {
|
||||
try {
|
||||
string cmd = this.get_string ("commandline");
|
||||
cmd = cmd.replace("{REFERER}", GLib.Shell.quote (dlReq.referer));
|
||||
if (dlReq.cookie_header != null) {
|
||||
cmd = cmd.replace("{COOKIES}", GLib.Shell.quote ("Cookie: " + dlReq.cookie_header));
|
||||
} else {
|
||||
cmd = cmd.replace("{COOKIES}", "\'\'");
|
||||
}
|
||||
cmd = cmd.replace("{URL}", GLib.Shell.quote (dlReq.uri));
|
||||
GLib.Process.spawn_command_line_async (cmd);
|
||||
return true;
|
||||
} catch (Error e) {
|
||||
this.handle_exception (e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static string description_with_command (string commandline) {
|
||||
string command;
|
||||
try {
|
||||
string[] argvp;
|
||||
Shell.parse_argv (commandline, out argvp);
|
||||
command = argvp[0];
|
||||
}
|
||||
catch (Error error) {
|
||||
command = commandline.split (" ")[0];
|
||||
}
|
||||
return _("Download files with \"%s\" or a custom command").printf (command);
|
||||
}
|
||||
|
||||
internal void update_description (Midori.App app) {
|
||||
this.description = description_with_command (get_string ("commandline"));
|
||||
}
|
||||
|
||||
internal CommandLine () {
|
||||
#if HAVE_WIN32
|
||||
string default_commandline = "\"%s\\FlashGet\\flashget.exe\" {URL}".printf (Environment.get_variable ("ProgramFiles"));
|
||||
#elif HAVE_FREEBSD
|
||||
string default_commandline = "fetch HTTP_REFERER={REFERER} {URL}";
|
||||
#else
|
||||
string default_commandline = "wget --no-check-certificate --referer={REFERER} --header={COOKIES} {URL}";
|
||||
#endif
|
||||
|
||||
GLib.Object (name: _("External Download Manager - CommandLine"),
|
||||
description: description_with_command (default_commandline),
|
||||
version: "0.1" + Midori.VERSION_SUFFIX,
|
||||
authors: "André Stösel <andre@stoesel.de>",
|
||||
key: "commandline");
|
||||
|
||||
this.install_string ("commandline", default_commandline);
|
||||
|
||||
this.activate.connect (activated);
|
||||
this.activate.connect (update_description);
|
||||
this.deactivate.connect (deactivated);
|
||||
this.open_preferences.connect (show_preferences);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Katze.Array extension_init () {
|
||||
EDM.manager = new EDM.Manager();
|
||||
|
||||
var extensions = new Katze.Array( typeof (Midori.Extension));
|
||||
#if !HAVE_WIN32
|
||||
extensions.add_item (new EDM.Aria2 ());
|
||||
extensions.add_item (new EDM.SteadyFlow ());
|
||||
#endif
|
||||
extensions.add_item (new EDM.CommandLine ());
|
||||
return extensions;
|
||||
}
|
||||
|
|
@ -95,7 +95,6 @@ atom_get_link (KatzeItem* item,
|
|||
gboolean newishtml;
|
||||
gboolean newlink;
|
||||
|
||||
newlink = FALSE;
|
||||
oldtype = (gchar*)katze_item_get_meta_string (item, "feedpanel:linktype");
|
||||
oldrel = (gchar*)katze_item_get_meta_string (item, "feedpanel:linkrel");
|
||||
|
||||
|
|
|
@ -24,7 +24,6 @@ struct _FeedPanel
|
|||
GtkWidget* treeview;
|
||||
GtkWidget* webview;
|
||||
GtkWidget* delete;
|
||||
GdkPixbuf* pixbuf;
|
||||
};
|
||||
|
||||
struct _FeedPanelClass
|
||||
|
@ -82,22 +81,17 @@ feed_panel_treeview_render_icon_cb (GtkTreeViewColumn* column,
|
|||
else
|
||||
pitem = item;
|
||||
|
||||
uri = katze_item_get_uri (pitem);
|
||||
if (uri)
|
||||
if ((uri = katze_item_get_uri (pitem)))
|
||||
{
|
||||
pixbuf = katze_load_cached_icon (uri, NULL);
|
||||
if (!pixbuf)
|
||||
pixbuf = panel->pixbuf;
|
||||
if (!(pixbuf = midori_paths_get_icon (uri, NULL)))
|
||||
pixbuf = gtk_widget_render_icon (panel->treeview, STOCK_NEWS_FEED, GTK_ICON_SIZE_MENU, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
pixbuf = gtk_widget_render_icon (panel->treeview,
|
||||
GTK_STOCK_DIALOG_ERROR, GTK_ICON_SIZE_MENU, NULL);
|
||||
}
|
||||
pixbuf = gtk_widget_render_icon (panel->treeview, GTK_STOCK_DIALOG_ERROR, GTK_ICON_SIZE_MENU, NULL);
|
||||
|
||||
g_object_set (renderer, "pixbuf", pixbuf, NULL);
|
||||
|
||||
if (pixbuf != panel->pixbuf)
|
||||
if (pixbuf)
|
||||
g_object_unref (pixbuf);
|
||||
}
|
||||
|
||||
|
@ -326,14 +320,11 @@ feed_panel_row_activated_cb (GtkTreeView* treeview,
|
|||
uri = katze_item_get_uri (item);
|
||||
if (uri && *uri)
|
||||
{
|
||||
MidoriWebSettings* settings;
|
||||
MidoriBrowser* browser;
|
||||
gint n;
|
||||
browser = midori_browser_get_for_widget (GTK_WIDGET (panel));
|
||||
n = midori_browser_add_item (browser, item);
|
||||
settings = midori_browser_get_settings (browser);
|
||||
MidoriBrowser* browser = midori_browser_get_for_widget (GTK_WIDGET (panel));
|
||||
GtkWidget* view = midori_browser_add_item (browser, item);
|
||||
MidoriWebSettings* settings = midori_browser_get_settings (browser);
|
||||
if (!katze_object_get_boolean (settings, "open-tabs-in-the-background"))
|
||||
midori_browser_set_current_page (browser, n);
|
||||
midori_browser_set_current_tab (browser, view);
|
||||
}
|
||||
g_object_unref (item);
|
||||
}
|
||||
|
@ -358,49 +349,45 @@ feed_panel_cursor_or_row_changed_cb (GtkTreeView* treeview,
|
|||
|
||||
if (KATZE_IS_ARRAY (item))
|
||||
{
|
||||
gint64 date;
|
||||
|
||||
text = NULL;
|
||||
if (!uri)
|
||||
text = g_strdup (katze_item_get_text (KATZE_ITEM (item)));
|
||||
else
|
||||
{
|
||||
KatzeItem* parent;
|
||||
const gchar* puri;
|
||||
|
||||
parent = katze_item_get_parent (item);
|
||||
KatzeItem* parent = katze_item_get_parent (item);
|
||||
gint64 added = katze_item_get_added (item);
|
||||
g_assert (KATZE_IS_ARRAY (parent));
|
||||
date = katze_item_get_added (item);
|
||||
puri = katze_item_get_uri (parent);
|
||||
if (date)
|
||||
if (added)
|
||||
{
|
||||
time_t date_t;
|
||||
const struct tm* tm;
|
||||
static gchar date_format[512];
|
||||
gchar* last_updated;
|
||||
#if GLIB_CHECK_VERSION (2, 26, 0)
|
||||
GDateTime* date = g_date_time_new_from_unix_local (added);
|
||||
gchar* pretty = g_date_time_format (date, "%c");
|
||||
g_date_time_unref (date);
|
||||
#else
|
||||
static gchar date_fmt[512];
|
||||
const struct tm *tm = localtime (&added);
|
||||
/* Some GCC versions falsely complain about "%c" */
|
||||
strftime (date_fmt, sizeof (date_fmt), "%c", tm);
|
||||
gchar* pretty = g_strdup (date_fmt);
|
||||
#endif
|
||||
|
||||
date_t = (time_t)date;
|
||||
tm = localtime (&date_t);
|
||||
/* Some gcc versions complain about "%c" for no reason */
|
||||
strftime (date_format, sizeof (date_format), "%c", tm);
|
||||
/* i18n: The local date a feed was last updated */
|
||||
last_updated = g_strdup_printf (C_("Feed", "Last updated: %s."),
|
||||
date_format);
|
||||
gchar* last_updated = g_strdup_printf (C_("Feed", "Last updated: %s."), pretty);
|
||||
text = g_strdup_printf (
|
||||
"<html><head><title>feed</title></head>"
|
||||
"<body><h3>%s</h3><p />%s</body></html>",
|
||||
puri, last_updated);
|
||||
katze_item_get_uri (KATZE_ITEM (parent)), last_updated);
|
||||
g_free (pretty);
|
||||
g_free (last_updated);
|
||||
}
|
||||
else
|
||||
{
|
||||
text = g_strdup_printf (
|
||||
"<html><head><title>feed</title></head>"
|
||||
"<body><h3>%s</h3></body></html>", puri);
|
||||
"<html><head><title>feed</title></head>"
|
||||
"<body><h3>%s</h3></body></html>", katze_item_get_uri (KATZE_ITEM (parent)));
|
||||
}
|
||||
}
|
||||
webkit_web_view_load_html_string (
|
||||
WEBKIT_WEB_VIEW (panel->webview), text ? text : "", uri);
|
||||
midori_view_set_html (MIDORI_VIEW (panel->webview), text ? text : "", uri, NULL);
|
||||
g_free ((gchar*) text);
|
||||
|
||||
sensitive = TRUE;
|
||||
|
@ -408,8 +395,7 @@ feed_panel_cursor_or_row_changed_cb (GtkTreeView* treeview,
|
|||
else
|
||||
{
|
||||
text = katze_item_get_text (item);
|
||||
webkit_web_view_load_html_string (
|
||||
WEBKIT_WEB_VIEW (panel->webview), text ? text : "", uri);
|
||||
midori_view_set_html (MIDORI_VIEW (panel->webview), text ? text : "", uri, NULL);
|
||||
}
|
||||
g_object_unref (item);
|
||||
}
|
||||
|
@ -468,14 +454,11 @@ feed_panel_open_in_tab_activate_cb (GtkWidget* menuitem,
|
|||
|
||||
if ((uri = katze_item_get_uri (item)) && *uri)
|
||||
{
|
||||
MidoriWebSettings* settings;
|
||||
MidoriBrowser* browser;
|
||||
|
||||
browser = midori_browser_get_for_widget (GTK_WIDGET (panel));
|
||||
n = midori_browser_add_item (browser, item);
|
||||
settings = midori_browser_get_settings (browser);
|
||||
MidoriBrowser* browser = midori_browser_get_for_widget (GTK_WIDGET (panel));
|
||||
GtkWidget* view = midori_browser_add_item (browser, item);
|
||||
MidoriWebSettings* settings = midori_browser_get_settings (browser);
|
||||
if (!katze_object_get_boolean (settings, "open-tabs-in-the-background"))
|
||||
midori_browser_set_current_page (browser, n);
|
||||
midori_browser_set_current_tab (browser, view);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -563,16 +546,11 @@ feed_panel_button_release_event_cb (GtkWidget* widget,
|
|||
|
||||
if (uri && *uri)
|
||||
{
|
||||
MidoriWebSettings* settings;
|
||||
MidoriBrowser* browser;
|
||||
gint n;
|
||||
|
||||
browser = midori_browser_get_for_widget (GTK_WIDGET (panel));
|
||||
n = midori_browser_add_item (browser, item);
|
||||
|
||||
settings = midori_browser_get_settings (browser);
|
||||
MidoriBrowser* browser = midori_browser_get_for_widget (GTK_WIDGET (panel));
|
||||
GtkWidget* view = midori_browser_add_item (browser, item);
|
||||
MidoriWebSettings* settings = midori_browser_get_settings (browser);
|
||||
if (!katze_object_get_boolean (settings, "open-tabs-in-the-background"))
|
||||
midori_browser_set_current_page (browser, n);
|
||||
midori_browser_set_current_tab (browser, view);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -620,6 +598,7 @@ webview_button_press_event_cb (GtkWidget* widget,
|
|||
return MIDORI_EVENT_CONTEXT_MENU (event);
|
||||
}
|
||||
|
||||
#ifndef HAVE_WEBKIT2
|
||||
static gboolean
|
||||
webview_navigation_request_cb (WebKitWebView* web_view,
|
||||
WebKitWebFrame* frame,
|
||||
|
@ -631,14 +610,10 @@ webview_navigation_request_cb (WebKitWebView* web_view,
|
|||
if (webkit_web_navigation_action_get_reason (navigation_action) ==
|
||||
WEBKIT_WEB_NAVIGATION_REASON_LINK_CLICKED)
|
||||
{
|
||||
MidoriBrowser* browser;
|
||||
const gchar* uri;
|
||||
gint n;
|
||||
|
||||
browser = midori_browser_get_for_widget (GTK_WIDGET (panel));
|
||||
uri = webkit_network_request_get_uri (request);
|
||||
n = midori_browser_add_uri (browser, uri);
|
||||
midori_browser_set_current_page (browser, n);
|
||||
MidoriBrowser* browser = midori_browser_get_for_widget (GTK_WIDGET (panel));
|
||||
const gchar* uri = webkit_network_request_get_uri (request);
|
||||
GtkWidget* view = midori_browser_add_uri (browser, uri);
|
||||
midori_browser_set_current_tab (browser, view);
|
||||
webkit_web_policy_decision_ignore (policy_decision);
|
||||
|
||||
return TRUE;
|
||||
|
@ -646,6 +621,7 @@ webview_navigation_request_cb (WebKitWebView* web_view,
|
|||
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const gchar*
|
||||
feed_panel_get_label (MidoriViewable* viewable)
|
||||
|
@ -729,9 +705,6 @@ feed_panel_get_toolbar (MidoriViewable* viewable)
|
|||
static void
|
||||
feed_panel_finalize (GObject* object)
|
||||
{
|
||||
FeedPanel* panel = FEED_PANEL (object);
|
||||
|
||||
g_object_unref (panel->pixbuf);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -786,7 +759,7 @@ feed_panel_init (FeedPanel* panel)
|
|||
GtkIconFactory *factory;
|
||||
GtkIconSource *icon_source;
|
||||
GtkIconSet *icon_set;
|
||||
WebKitWebSettings* settings;
|
||||
MidoriWebSettings* settings;
|
||||
PangoFontDescription* font_desc;
|
||||
const gchar* family;
|
||||
gint size;
|
||||
|
@ -838,22 +811,24 @@ feed_panel_init (FeedPanel* panel)
|
|||
NULL);
|
||||
gtk_widget_show (treeview);
|
||||
|
||||
webview = webkit_web_view_new ();
|
||||
#if GTK_CHECK_VERSION(3,0,0)
|
||||
font_desc = gtk_style_context_get_font(gtk_widget_get_style_context(treeview), GTK_STATE_FLAG_NORMAL);
|
||||
font_desc = (PangoFontDescription*)gtk_style_context_get_font (
|
||||
gtk_widget_get_style_context (treeview), GTK_STATE_FLAG_NORMAL);
|
||||
#else
|
||||
font_desc = treeview->style->font_desc;
|
||||
#endif
|
||||
family = pango_font_description_get_family (font_desc);
|
||||
size = pango_font_description_get_size (font_desc) / PANGO_SCALE;
|
||||
settings = webkit_web_settings_new ();
|
||||
settings = midori_web_settings_new ();
|
||||
g_object_set (settings, "default-font-family", family,
|
||||
"default-font-size", size, NULL);
|
||||
g_object_set (webview, "settings", settings, NULL);
|
||||
webview = midori_view_new_with_item (NULL, settings);
|
||||
gtk_widget_set_size_request (webview, -1, 50);
|
||||
g_object_connect (webview,
|
||||
g_object_connect (midori_tab_get_web_view (MIDORI_TAB (webview)),
|
||||
#ifndef HAVE_WEBKIT2
|
||||
"signal::navigation-policy-decision-requested",
|
||||
webview_navigation_request_cb, panel,
|
||||
#endif
|
||||
"signal::button-press-event",
|
||||
webview_button_press_event_cb, NULL,
|
||||
"signal::button-release-event",
|
||||
|
@ -871,13 +846,10 @@ feed_panel_init (FeedPanel* panel)
|
|||
|
||||
paned = gtk_vpaned_new ();
|
||||
gtk_paned_pack1 (GTK_PANED (paned), treewin, TRUE, FALSE);
|
||||
gtk_paned_pack2 (GTK_PANED (paned), webview, TRUE, FALSE);
|
||||
gtk_paned_pack2 (GTK_PANED (paned), webview, TRUE, TRUE);
|
||||
gtk_box_pack_start (GTK_BOX (panel), paned, TRUE, TRUE, 0);
|
||||
gtk_widget_show (webview);
|
||||
gtk_widget_show (paned);
|
||||
|
||||
panel->pixbuf = gtk_widget_render_icon (treeview,
|
||||
STOCK_NEWS_FEED, GTK_ICON_SIZE_MENU, NULL);
|
||||
}
|
||||
|
||||
GtkWidget*
|
||||
|
|
|
@ -219,6 +219,8 @@ feed_parse_doc (xmlDocPtr doc,
|
|||
feed_parse_node (fparser);
|
||||
}
|
||||
}
|
||||
else
|
||||
isvalid = FALSE;
|
||||
|
||||
fparser->error = NULL;
|
||||
fparser->doc = NULL;
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
#include <midori/midori.h>
|
||||
|
||||
#define EXTENSION_NAME "Feed Panel"
|
||||
#define UPDATE_FREQ 10
|
||||
|
||||
#define feed_get_flags(feed) \
|
||||
GPOINTER_TO_INT (g_object_get_data (G_OBJECT ((feed)), "flags"))
|
||||
|
@ -102,24 +101,10 @@ feed_deactivate_cb (MidoriExtension* extension,
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
feed_dialog_response_cb (GtkWidget* dialog,
|
||||
gint response,
|
||||
gpointer data)
|
||||
{
|
||||
gtk_widget_destroy (dialog);
|
||||
}
|
||||
|
||||
static KatzeArray*
|
||||
feed_add_item (KatzeArray* feeds,
|
||||
const gchar* uri)
|
||||
{
|
||||
KatzeArray* feed;
|
||||
|
||||
feed = NULL;
|
||||
|
||||
if (uri)
|
||||
{
|
||||
if (katze_array_find_token (feeds, uri))
|
||||
{
|
||||
GtkWidget* dialog;
|
||||
|
@ -131,24 +116,23 @@ feed_add_item (KatzeArray* feeds,
|
|||
_("Feed '%s' already exists"), uri);
|
||||
gtk_window_set_title (GTK_WINDOW (dialog), EXTENSION_NAME);
|
||||
gtk_widget_show (dialog);
|
||||
g_signal_connect (dialog, "response",
|
||||
G_CALLBACK (feed_dialog_response_cb), NULL);
|
||||
|
||||
g_signal_connect_swapped (dialog, "response",
|
||||
G_CALLBACK (gtk_widget_destroy), dialog);
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
KatzeArray* child;
|
||||
|
||||
feed = katze_array_new (KATZE_TYPE_ARRAY);
|
||||
KatzeArray* feed = katze_array_new (KATZE_TYPE_ARRAY);
|
||||
child = katze_array_new (KATZE_TYPE_ITEM);
|
||||
katze_item_set_uri (KATZE_ITEM (feed), uri);
|
||||
katze_item_set_token (KATZE_ITEM (feed), uri);
|
||||
katze_item_set_uri (KATZE_ITEM (child), uri);
|
||||
katze_array_add_item (feeds, feed);
|
||||
katze_array_add_item (feed, child);
|
||||
return feed;
|
||||
}
|
||||
}
|
||||
return feed;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -464,8 +448,7 @@ feed_app_add_browser_cb (MidoriApp* app,
|
|||
priv->parsers = g_slist_prepend (priv->parsers, rss_init_parser ());
|
||||
|
||||
sfeeds = midori_extension_get_string_list (extension, "feeds", &n);
|
||||
g_assert (n == 0 || sfeeds);
|
||||
|
||||
if (sfeeds != NULL)
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
if (sfeeds[i])
|
||||
|
@ -475,7 +458,6 @@ feed_app_add_browser_cb (MidoriApp* app,
|
|||
update_feed (priv, KATZE_ITEM (feed));
|
||||
}
|
||||
}
|
||||
g_strdupv (sfeeds);
|
||||
action_group = midori_browser_get_action_group (browser);
|
||||
action = gtk_action_group_get_action (action_group, "Location");
|
||||
|
||||
|
@ -488,8 +470,8 @@ feed_app_add_browser_cb (MidoriApp* app,
|
|||
g_signal_connect (extension, "deactivate",
|
||||
G_CALLBACK (feed_deactivate_cb), priv);
|
||||
|
||||
priv->source_id = g_timeout_add_seconds (UPDATE_FREQ * 60,
|
||||
(GSourceFunc) update_feeds, priv);
|
||||
priv->source_id = midori_timeout_add_seconds (
|
||||
600, (GSourceFunc) update_feeds, priv, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -512,7 +494,6 @@ MidoriExtension*
|
|||
extension_init (void)
|
||||
{
|
||||
MidoriExtension* extension;
|
||||
gchar* sfeed[2];
|
||||
|
||||
extension = g_object_new (MIDORI_TYPE_EXTENSION,
|
||||
"name", _("Feed Panel"),
|
||||
|
@ -521,8 +502,7 @@ extension_init (void)
|
|||
"authors", "Dale Whittaker <dayul@users.sf.net>",
|
||||
NULL);
|
||||
|
||||
sfeed[0] = NULL;
|
||||
midori_extension_install_string_list (extension, "feeds", sfeed, 1);
|
||||
midori_extension_install_string_list (extension, "feeds", NULL, 0);
|
||||
|
||||
g_signal_connect (extension, "activate",
|
||||
G_CALLBACK (feed_activate_cb), NULL);
|
||||
|
|
|
@ -1,600 +0,0 @@
|
|||
/*
|
||||
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
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#define MAXCHARS 60
|
||||
#define MINCHARS 2
|
||||
|
||||
#include <midori/midori.h>
|
||||
#include <glib/gstdio.h>
|
||||
|
||||
#include "config.h"
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
static GHashTable* global_keys;
|
||||
static gchar* jsforms;
|
||||
|
||||
|
||||
static void
|
||||
formhistory_toggle_state_cb (GtkAction* action,
|
||||
MidoriBrowser* browser);
|
||||
|
||||
static gboolean
|
||||
formhistory_prepare_js ()
|
||||
{
|
||||
gchar* autosuggest;
|
||||
gchar* style;
|
||||
guint i;
|
||||
gchar* file;
|
||||
|
||||
file = sokoke_find_data_filename ("autosuggestcontrol.js", TRUE);
|
||||
if (!g_file_get_contents (file, &autosuggest, NULL, NULL))
|
||||
{
|
||||
g_free (file);
|
||||
return FALSE;
|
||||
}
|
||||
g_strchomp (autosuggest);
|
||||
|
||||
katze_assign (file, sokoke_find_data_filename ("autosuggestcontrol.css", TRUE));
|
||||
if (!g_file_get_contents (file, &style, NULL, NULL))
|
||||
{
|
||||
g_free (file);
|
||||
return FALSE;
|
||||
}
|
||||
g_strchomp (style);
|
||||
i = 0;
|
||||
while (style[i])
|
||||
{
|
||||
if (style[i] == '\n')
|
||||
style[i] = ' ';
|
||||
i++;
|
||||
}
|
||||
|
||||
jsforms = g_strdup_printf (
|
||||
"%s"
|
||||
"window.addEventListener ('DOMContentLoaded',"
|
||||
"function () {"
|
||||
" if (document.getElementById('formhistory'))"
|
||||
" return;"
|
||||
" if (!initSuggestions ())"
|
||||
" return;"
|
||||
" var mystyle = document.createElement('style');"
|
||||
" mystyle.setAttribute('type', 'text/css');"
|
||||
" mystyle.setAttribute('id', 'formhistory');"
|
||||
" mystyle.appendChild(document.createTextNode('%s'));"
|
||||
" var head = document.getElementsByTagName('head')[0];"
|
||||
" if (head) head.appendChild(mystyle);"
|
||||
"}, true);",
|
||||
autosuggest,
|
||||
style);
|
||||
g_strstrip (jsforms);
|
||||
g_free (file);
|
||||
g_free (style);
|
||||
g_free (autosuggest);
|
||||
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 ()
|
||||
{
|
||||
GString* suggestions;
|
||||
GHashTableIter iter;
|
||||
gpointer key, value;
|
||||
|
||||
suggestions = g_string_new (
|
||||
"function FormSuggestions(eid) { "
|
||||
"arr = new Array();");
|
||||
g_hash_table_iter_init (&iter, global_keys);
|
||||
while (g_hash_table_iter_next (&iter, &key, &value))
|
||||
{
|
||||
g_string_append_printf (suggestions, " arr[\"%s\"] = [%s]; ",
|
||||
(gchar*)key, (gchar*)value);
|
||||
}
|
||||
g_string_append (suggestions, "this.suggestions = arr[eid]; }");
|
||||
g_string_append (suggestions, jsforms);
|
||||
return g_string_free (suggestions, FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
formhistory_update_database (gpointer db,
|
||||
const gchar* key,
|
||||
const gchar* value)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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 (key);
|
||||
formhistory_fixup_value (value);
|
||||
if ((tmp = g_hash_table_lookup (global_keys, (gpointer)key)))
|
||||
{
|
||||
gchar* rvalue = g_strdup_printf ("\"%s\"",value);
|
||||
gchar* patt = g_regex_escape_string (rvalue, -1);
|
||||
if (!g_regex_match_simple (patt, 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);
|
||||
g_free (patt);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_free (rvalue);
|
||||
g_free (patt);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gchar* new_value = g_strdup_printf ("\"%s\",",value);
|
||||
g_hash_table_replace (global_keys, g_strdup (key), new_value);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
formhistory_navigation_decision_cb (WebKitWebView* web_view,
|
||||
WebKitWebFrame* web_frame,
|
||||
WebKitNetworkRequest* request,
|
||||
WebKitWebNavigationAction* action,
|
||||
WebKitWebPolicyDecision* decision,
|
||||
MidoriExtension* extension)
|
||||
{
|
||||
/* 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].getAttribute('autocomplete') == 'off')"
|
||||
" continue;"
|
||||
" 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;"
|
||||
" if (inputs[i].getAttribute('autocomplete') != 'off')"
|
||||
" 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)
|
||||
{
|
||||
JSContextRef js_context = webkit_web_frame_get_global_context (web_frame);
|
||||
gchar* value = sokoke_js_script_eval (js_context, script, NULL);
|
||||
if (value && *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;
|
||||
}
|
||||
|
||||
static void
|
||||
formhistory_window_object_cleared_cb (WebKitWebView* web_view,
|
||||
WebKitWebFrame* web_frame,
|
||||
JSContextRef js_context,
|
||||
JSObjectRef js_window)
|
||||
{
|
||||
gchar* script;
|
||||
const gchar* page_uri;
|
||||
|
||||
page_uri = webkit_web_frame_get_uri (web_frame);
|
||||
if (!midori_uri_is_http (page_uri))
|
||||
return;
|
||||
|
||||
script = formhistory_build_js ();
|
||||
sokoke_js_script_eval (js_context, script, NULL);
|
||||
g_free (script);
|
||||
}
|
||||
|
||||
static void
|
||||
formhistory_add_tab_cb (MidoriBrowser* browser,
|
||||
MidoriView* view,
|
||||
MidoriExtension* extension)
|
||||
{
|
||||
GtkWidget* web_view = midori_view_get_web_view (view);
|
||||
g_signal_connect (web_view, "window-object-cleared",
|
||||
G_CALLBACK (formhistory_window_object_cleared_cb), NULL);
|
||||
g_signal_connect (web_view, "navigation-policy-decision-requested",
|
||||
G_CALLBACK (formhistory_navigation_decision_cb), extension);
|
||||
}
|
||||
|
||||
static void
|
||||
formhistory_deactivate_cb (MidoriExtension* extension,
|
||||
MidoriBrowser* browser);
|
||||
|
||||
static void
|
||||
formhistory_add_tab_foreach_cb (MidoriView* view,
|
||||
MidoriBrowser* browser,
|
||||
MidoriExtension* extension)
|
||||
{
|
||||
formhistory_add_tab_cb (browser, view, extension);
|
||||
}
|
||||
|
||||
static void
|
||||
formhistory_app_add_browser_cb (MidoriApp* app,
|
||||
MidoriBrowser* browser,
|
||||
MidoriExtension* extension)
|
||||
{
|
||||
GtkAccelGroup* acg = gtk_accel_group_new ();
|
||||
GtkActionGroup* action_group = midori_browser_get_action_group (browser);
|
||||
GtkAction* action = gtk_action_new ("FormHistoryToggleState",
|
||||
_("Toggle form history state"),
|
||||
_("Activate or deactivate form history for the current tab."), NULL);
|
||||
gtk_window_add_accel_group (GTK_WINDOW (browser), acg);
|
||||
|
||||
g_object_set_data (G_OBJECT (browser), "FormHistoryExtension", extension);
|
||||
|
||||
g_signal_connect (action, "activate",
|
||||
G_CALLBACK (formhistory_toggle_state_cb), browser);
|
||||
|
||||
gtk_action_group_add_action_with_accel (action_group, action, "<Ctrl><Shift>F");
|
||||
gtk_action_set_accel_group (action, acg);
|
||||
gtk_action_connect_accelerator (action);
|
||||
|
||||
if (midori_extension_get_boolean (extension, "always-load"))
|
||||
{
|
||||
midori_browser_foreach (browser,
|
||||
(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,
|
||||
MidoriExtension* extension)
|
||||
{
|
||||
GtkWidget* web_view = midori_view_get_web_view (view);
|
||||
g_signal_handlers_disconnect_by_func (
|
||||
web_view, formhistory_window_object_cleared_cb, NULL);
|
||||
g_signal_handlers_disconnect_by_func (
|
||||
web_view, formhistory_navigation_decision_cb, extension);
|
||||
}
|
||||
|
||||
static void
|
||||
formhistory_deactivate_cb (MidoriExtension* extension,
|
||||
MidoriBrowser* browser)
|
||||
{
|
||||
MidoriApp* app = midori_extension_get_app (extension);
|
||||
sqlite3* db;
|
||||
|
||||
GtkActionGroup* action_group = midori_browser_get_action_group (browser);
|
||||
GtkAction* action;
|
||||
|
||||
g_signal_handlers_disconnect_by_func (
|
||||
browser, formhistory_add_tab_cb, extension);
|
||||
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, extension);
|
||||
|
||||
g_object_set_data (G_OBJECT (browser), "FormHistoryExtension", NULL);
|
||||
action = gtk_action_group_get_action ( action_group, "FormHistoryToggleState");
|
||||
if (action != NULL)
|
||||
{
|
||||
gtk_action_group_remove_action (action_group, action);
|
||||
g_object_unref (action);
|
||||
}
|
||||
|
||||
katze_assign (jsforms, NULL);
|
||||
if (global_keys)
|
||||
g_hash_table_destroy (global_keys);
|
||||
|
||||
if ((db = g_object_get_data (G_OBJECT (extension), "formhistory-db")))
|
||||
sqlite3_close (db);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static void
|
||||
formhistory_activate_cb (MidoriExtension* extension,
|
||||
MidoriApp* app)
|
||||
{
|
||||
const gchar* config_dir;
|
||||
gchar* filename;
|
||||
sqlite3* db;
|
||||
char* errmsg = NULL, *errmsg2 = NULL;
|
||||
KatzeArray* browsers;
|
||||
MidoriBrowser* browser;
|
||||
|
||||
global_keys = g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||
(GDestroyNotify)g_free,
|
||||
(GDestroyNotify)g_free);
|
||||
if(!jsforms)
|
||||
formhistory_prepare_js ();
|
||||
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) != SQLITE_OK)
|
||||
{
|
||||
/* If the folder is /, this is a test run, thus no error */
|
||||
if (!g_str_equal (midori_extension_get_config_dir (extension), "/"))
|
||||
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);
|
||||
}
|
||||
|
||||
browsers = katze_object_get_object (app, "browsers");
|
||||
KATZE_ARRAY_FOREACH_ITEM (browser, browsers)
|
||||
formhistory_app_add_browser_cb (app, browser, extension);
|
||||
g_signal_connect (app, "add-browser",
|
||||
G_CALLBACK (formhistory_app_add_browser_cb), extension);
|
||||
|
||||
g_object_unref (browsers);
|
||||
}
|
||||
|
||||
static void
|
||||
formhistory_preferences_response_cb (GtkWidget* dialog,
|
||||
gint response_id,
|
||||
MidoriExtension* extension)
|
||||
{
|
||||
GtkWidget* checkbox;
|
||||
gboolean old_state;
|
||||
gboolean new_state;
|
||||
MidoriApp* app;
|
||||
KatzeArray* browsers;
|
||||
MidoriBrowser* browser;
|
||||
|
||||
if (response_id == GTK_RESPONSE_APPLY)
|
||||
{
|
||||
checkbox = g_object_get_data (G_OBJECT (dialog), "always-load-checkbox");
|
||||
new_state = !gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (checkbox));
|
||||
old_state = midori_extension_get_boolean (extension, "always-load");
|
||||
|
||||
if (old_state != new_state)
|
||||
{
|
||||
midori_extension_set_boolean (extension, "always-load", new_state);
|
||||
|
||||
app = midori_extension_get_app (extension);
|
||||
browsers = katze_object_get_object (app, "browsers");
|
||||
KATZE_ARRAY_FOREACH_ITEM (browser, browsers)
|
||||
{
|
||||
midori_browser_foreach (browser,
|
||||
(GtkCallback)formhistory_deactivate_tabs, extension);
|
||||
g_signal_handlers_disconnect_by_func (
|
||||
browser, formhistory_add_tab_cb, extension);
|
||||
|
||||
if (new_state)
|
||||
{
|
||||
midori_browser_foreach (browser,
|
||||
(GtkCallback)formhistory_add_tab_foreach_cb, extension);
|
||||
g_signal_connect (browser, "add-tab",
|
||||
G_CALLBACK (formhistory_add_tab_cb), extension);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
gtk_widget_destroy (dialog);
|
||||
}
|
||||
|
||||
static void
|
||||
formhistory_preferences_cb (MidoriExtension* extension)
|
||||
{
|
||||
GtkWidget* dialog;
|
||||
GtkWidget* content_area;
|
||||
GtkWidget* checkbox;
|
||||
|
||||
dialog = gtk_dialog_new ();
|
||||
|
||||
gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
|
||||
|
||||
gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
|
||||
gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_APPLY, GTK_RESPONSE_APPLY);
|
||||
|
||||
content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
|
||||
checkbox = gtk_check_button_new_with_label (_("only activate form history via hotkey (Ctrl+Shift+F) per tab"));
|
||||
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbox),
|
||||
!midori_extension_get_boolean (extension, "always-load"));
|
||||
g_object_set_data (G_OBJECT (dialog), "always-load-checkbox", checkbox);
|
||||
gtk_container_add (GTK_CONTAINER (content_area), checkbox);
|
||||
|
||||
g_signal_connect (dialog,
|
||||
"response",
|
||||
G_CALLBACK (formhistory_preferences_response_cb),
|
||||
extension);
|
||||
gtk_widget_show_all (dialog);
|
||||
}
|
||||
|
||||
static void
|
||||
formhistory_toggle_state_cb (GtkAction* action,
|
||||
MidoriBrowser* browser)
|
||||
{
|
||||
MidoriView* view = MIDORI_VIEW (midori_browser_get_current_tab (browser));
|
||||
MidoriExtension* extension = g_object_get_data (G_OBJECT (browser), "FormHistoryExtension");
|
||||
GtkWidget* web_view = midori_view_get_web_view (view);
|
||||
|
||||
if (g_signal_handler_find (web_view, G_SIGNAL_MATCH_FUNC,
|
||||
g_signal_lookup ("window-object-cleared", MIDORI_TYPE_VIEW), 0, NULL,
|
||||
formhistory_window_object_cleared_cb, extension))
|
||||
{
|
||||
formhistory_deactivate_tabs (view, browser, extension);
|
||||
} else {
|
||||
formhistory_add_tab_cb (browser, view, extension);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if G_ENABLE_DEBUG
|
||||
/*
|
||||
<html>
|
||||
<head>
|
||||
<title>autosuggest testcase</title>
|
||||
</head>
|
||||
<body>
|
||||
<form method=post>
|
||||
<p><input type="text" id="txt1" /></p>
|
||||
<p><input type="text" name="txt2" /></p>
|
||||
<input type=submit>
|
||||
</form>
|
||||
</body>
|
||||
</html> */
|
||||
#endif
|
||||
|
||||
MidoriExtension*
|
||||
extension_init (void)
|
||||
{
|
||||
gboolean should_init = TRUE;
|
||||
const gchar* ver;
|
||||
gchar* desc;
|
||||
MidoriExtension* extension;
|
||||
|
||||
if (formhistory_prepare_js ())
|
||||
{
|
||||
ver = "1.0" MIDORI_VERSION_SUFFIX;
|
||||
desc = g_strdup (_("Stores history of entered form data"));
|
||||
}
|
||||
else
|
||||
{
|
||||
desc = g_strdup_printf (_("Not available: %s"),
|
||||
_("Resource files not installed"));
|
||||
ver = NULL;
|
||||
should_init = FALSE;
|
||||
}
|
||||
|
||||
extension = g_object_new (MIDORI_TYPE_EXTENSION,
|
||||
"name", _("Form history filler"),
|
||||
"description", desc,
|
||||
"version", ver,
|
||||
"authors", "Alexander V. Butenko <a.butenka@gmail.com>",
|
||||
NULL);
|
||||
|
||||
g_free (desc);
|
||||
|
||||
if (should_init)
|
||||
{
|
||||
midori_extension_install_boolean (extension, "always-load", TRUE);
|
||||
g_signal_connect (extension, "activate",
|
||||
G_CALLBACK (formhistory_activate_cb), NULL);
|
||||
g_signal_connect (extension, "open-preferences",
|
||||
G_CALLBACK (formhistory_preferences_cb), NULL);
|
||||
}
|
||||
|
||||
return extension;
|
||||
}
|
74
extensions/formhistory/formhistory-frontend.h
Normal file
74
extensions/formhistory/formhistory-frontend.h
Normal file
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
Copyright (C) 2009-2012 Alexander Butenko <a.butenka@gmail.com>
|
||||
Copyright (C) 2009-2012 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.
|
||||
*/
|
||||
|
||||
#ifndef __FORMHISTORY_FRONTEND_H__
|
||||
#define __FORMHISTORY_FRONTEND_H__
|
||||
#include <midori/midori.h>
|
||||
#include <glib/gstdio.h>
|
||||
|
||||
#include "config.h"
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if WEBKIT_CHECK_VERSION (1, 3, 1)
|
||||
#define FORMHISTORY_USE_GDOM 1
|
||||
#else
|
||||
#define FORMHISTORY_USE_JS 1
|
||||
#endif
|
||||
#define MAXPASSSIZE 64
|
||||
|
||||
typedef struct
|
||||
{
|
||||
sqlite3* db;
|
||||
#ifdef FORMHISTORY_USE_GDOM
|
||||
WebKitDOMElement* element;
|
||||
int completion_timeout;
|
||||
GtkTreeModel* completion_model;
|
||||
GtkWidget* treeview;
|
||||
GtkWidget* popup;
|
||||
gchar* oldkeyword;
|
||||
glong selection_index;
|
||||
#else
|
||||
gchar* jsforms;
|
||||
#endif
|
||||
gchar* master_password;
|
||||
int master_password_canceled;
|
||||
} FormHistoryPriv;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
gchar* domain;
|
||||
gchar* form_data;
|
||||
FormHistoryPriv* priv;
|
||||
} FormhistoryPasswordEntry;
|
||||
|
||||
FormHistoryPriv*
|
||||
formhistory_private_new ();
|
||||
|
||||
void
|
||||
formhistory_private_destroy (FormHistoryPriv *priv);
|
||||
|
||||
gboolean
|
||||
formhistory_construct_popup_gui (FormHistoryPriv* priv);
|
||||
|
||||
void
|
||||
formhistory_setup_suggestions (WebKitWebView* web_view,
|
||||
JSContextRef js_context,
|
||||
MidoriExtension* extension);
|
||||
|
||||
#ifdef FORMHISTORY_USE_GDOM
|
||||
void
|
||||
formhistory_suggestions_hide_cb (WebKitDOMElement* element,
|
||||
WebKitDOMEvent* dom_event,
|
||||
FormHistoryPriv* priv);
|
||||
#endif
|
||||
|
||||
#endif
|
514
extensions/formhistory/formhistory-gdom-frontend.c
Normal file
514
extensions/formhistory/formhistory-gdom-frontend.c
Normal file
|
@ -0,0 +1,514 @@
|
|||
/*
|
||||
Copyright (C) 2009-2012 Alexander Butenko <a.butenka@gmail.com>
|
||||
Copyright (C) 2009-2012 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.
|
||||
*/
|
||||
#include "formhistory-frontend.h"
|
||||
#ifdef FORMHISTORY_USE_GDOM
|
||||
#define COMPLETION_DELAY 200
|
||||
|
||||
FormHistoryPriv*
|
||||
formhistory_private_new ()
|
||||
{
|
||||
FormHistoryPriv* priv = g_slice_new (FormHistoryPriv);
|
||||
priv->oldkeyword = g_strdup ("");
|
||||
priv->selection_index = -1;
|
||||
return priv;
|
||||
}
|
||||
|
||||
void
|
||||
formhistory_suggestions_hide_cb (WebKitDOMElement* element,
|
||||
WebKitDOMEvent* dom_event,
|
||||
FormHistoryPriv* priv)
|
||||
{
|
||||
if (gtk_widget_get_visible (priv->popup))
|
||||
gtk_widget_hide (priv->popup);
|
||||
priv->selection_index = -1;
|
||||
}
|
||||
|
||||
static void
|
||||
formhistory_suggestion_set (GtkTreePath* path,
|
||||
FormHistoryPriv* priv)
|
||||
{
|
||||
GtkTreeIter iter;
|
||||
gchar* value;
|
||||
|
||||
if (!gtk_tree_model_get_iter (priv->completion_model, &iter, path))
|
||||
return;
|
||||
|
||||
gtk_tree_model_get (priv->completion_model, &iter, 0, &value, -1);
|
||||
g_object_set (priv->element, "value", value, NULL);
|
||||
g_free (value);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
formhistory_suggestion_selected_cb (GtkWidget* treeview,
|
||||
GdkEventButton* event,
|
||||
FormHistoryPriv* priv)
|
||||
|
||||
{
|
||||
GtkTreePath* path;
|
||||
|
||||
if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (treeview),
|
||||
event->x, event->y, &path, NULL, NULL, NULL))
|
||||
{
|
||||
formhistory_suggestion_set (path, priv);
|
||||
formhistory_suggestions_hide_cb (NULL, NULL, priv);
|
||||
gtk_tree_path_free (path);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
static void
|
||||
formhistory_suggestion_remove (GtkTreePath* path,
|
||||
FormHistoryPriv* priv)
|
||||
{
|
||||
GtkTreeIter iter;
|
||||
gchar* sqlcmd;
|
||||
char* errmsg = NULL;
|
||||
gchar* name;
|
||||
gchar* value;
|
||||
|
||||
if (!gtk_tree_model_get_iter (priv->completion_model, &iter, path))
|
||||
return;
|
||||
|
||||
if (!priv->db)
|
||||
return;
|
||||
|
||||
gtk_tree_model_get (priv->completion_model, &iter, 0, &value, -1);
|
||||
g_object_get (priv->element, "name", &name, NULL);
|
||||
gtk_list_store_remove (GTK_LIST_STORE (priv->completion_model), &iter);
|
||||
|
||||
sqlcmd = sqlite3_mprintf ("DELETE FROM forms WHERE field = '%q' AND value = '%q'",
|
||||
name, value);
|
||||
g_free (name);
|
||||
g_free (value);
|
||||
sqlite3_exec (priv->db, sqlcmd, NULL, NULL, &errmsg);
|
||||
sqlite3_free (sqlcmd);
|
||||
}
|
||||
|
||||
static void
|
||||
get_absolute_offset_for_element (WebKitDOMElement* element,
|
||||
WebKitDOMDocument* element_document,
|
||||
WebKitDOMNodeList* frames,
|
||||
glong* x,
|
||||
glong* y,
|
||||
gboolean ismainframe)
|
||||
{
|
||||
WebKitDOMElement* offset_parent;
|
||||
gint offset_top = 0, offset_left = 0;
|
||||
gulong i;
|
||||
|
||||
g_object_get (element, "offset-left", &offset_left,
|
||||
"offset-top", &offset_top,
|
||||
"offset-parent", &offset_parent,
|
||||
NULL);
|
||||
*x += offset_left;
|
||||
*y += offset_top;
|
||||
/* To avoid deadlock check only first element of the mainframe parent */
|
||||
if (ismainframe == TRUE)
|
||||
return;
|
||||
if (offset_parent)
|
||||
goto finish;
|
||||
|
||||
/* Element havent returned any parents. Thats mean or there is no parents or we are inside the frame
|
||||
Loop over all frames we have to find frame == element_document which is a root for our element
|
||||
and get its offsets */
|
||||
for (i = 0; i < webkit_dom_node_list_get_length (frames); i++)
|
||||
{
|
||||
WebKitDOMDocument *fdoc;
|
||||
WebKitDOMNode *frame = webkit_dom_node_list_item (frames, i);
|
||||
|
||||
if (WEBKIT_DOM_IS_HTML_IFRAME_ELEMENT (frame))
|
||||
fdoc = webkit_dom_html_iframe_element_get_content_document (WEBKIT_DOM_HTML_IFRAME_ELEMENT (frame));
|
||||
else
|
||||
fdoc = webkit_dom_html_frame_element_get_content_document (WEBKIT_DOM_HTML_FRAME_ELEMENT (frame));
|
||||
if (fdoc == element_document)
|
||||
{
|
||||
offset_parent = WEBKIT_DOM_ELEMENT (frame);
|
||||
ismainframe = TRUE;
|
||||
/* Add extra 4px to ~cover size of borders */
|
||||
*y += 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
finish:
|
||||
if (offset_parent)
|
||||
get_absolute_offset_for_element (offset_parent, element_document, frames, x, y, ismainframe);
|
||||
}
|
||||
|
||||
static void
|
||||
formhistory_reposition_popup (FormHistoryPriv* priv)
|
||||
{
|
||||
WebKitDOMDocument* element_document;
|
||||
WebKitDOMNodeList* frames;
|
||||
GtkWidget* view;
|
||||
GdkWindow* window;
|
||||
GtkWidget* toplevel;
|
||||
gint rx, ry;
|
||||
gint wx, wy;
|
||||
glong x = 0, y = 0;
|
||||
glong height;
|
||||
|
||||
view = g_object_get_data (G_OBJECT (priv->element), "webview");
|
||||
toplevel = gtk_widget_get_toplevel (view);
|
||||
/* Position of a root window */
|
||||
window = gtk_widget_get_window (toplevel);
|
||||
gdk_window_get_position (window, &rx, &ry);
|
||||
|
||||
/* Postion of webview in root window */
|
||||
window = gtk_widget_get_window (view);
|
||||
gdk_window_get_position (window, &wx, &wy);
|
||||
|
||||
/* Position of editbox on the webview */
|
||||
frames = g_object_get_data (G_OBJECT (priv->element), "framelist");
|
||||
element_document = g_object_get_data (G_OBJECT (priv->element), "doc");
|
||||
get_absolute_offset_for_element (priv->element, element_document, frames, &x, &y, FALSE);
|
||||
/* Add height as menu should start under editbox, now on top of it */
|
||||
g_object_get (priv->element, "client-height", &height, NULL);
|
||||
y += height + 1;
|
||||
gtk_window_move (GTK_WINDOW (priv->popup), rx + wx + x, ry +wy + y);
|
||||
|
||||
/* Window configuration */
|
||||
gtk_window_set_screen (GTK_WINDOW (priv->popup), gtk_widget_get_screen (view));
|
||||
gtk_window_set_transient_for (GTK_WINDOW (priv->popup), GTK_WINDOW (toplevel));
|
||||
gtk_tree_view_columns_autosize (GTK_TREE_VIEW (priv->treeview));
|
||||
/* FIXME: Adjust size according to treeview width and some reasonable height */
|
||||
gtk_window_resize (GTK_WINDOW (priv->popup), 50, 80);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
formhistory_suggestions_show (FormHistoryPriv* priv)
|
||||
{
|
||||
GtkListStore* store;
|
||||
static sqlite3_stmt* stmt;
|
||||
gchar* value, * name;
|
||||
const char* sqlcmd;
|
||||
gint result;
|
||||
gchar* likedvalue;
|
||||
int pos = 0;
|
||||
|
||||
g_return_val_if_fail (priv->element, FALSE);
|
||||
|
||||
g_object_get (priv->element,
|
||||
"name", &name,
|
||||
"value", &value,
|
||||
NULL);
|
||||
|
||||
katze_assign (priv->oldkeyword, g_strdup (value));
|
||||
if (!priv->popup)
|
||||
formhistory_construct_popup_gui (priv);
|
||||
|
||||
if (!stmt)
|
||||
{
|
||||
if (!priv->db)
|
||||
goto free_data;
|
||||
|
||||
sqlcmd = "SELECT DISTINCT value FROM forms WHERE field = ?1 and value like ?2";
|
||||
sqlite3_prepare_v2 (priv->db, sqlcmd, strlen (sqlcmd) + 1, &stmt, NULL);
|
||||
}
|
||||
|
||||
likedvalue = g_strdup_printf ("%s%%", value);
|
||||
sqlite3_bind_text (stmt, 1, name, -1, NULL);
|
||||
sqlite3_bind_text (stmt, 2, likedvalue, -1, g_free);
|
||||
result = sqlite3_step (stmt);
|
||||
|
||||
if (result != SQLITE_ROW)
|
||||
{
|
||||
if (result == SQLITE_ERROR)
|
||||
g_print (_("Failed to select suggestions\n"));
|
||||
sqlite3_reset (stmt);
|
||||
sqlite3_clear_bindings (stmt);
|
||||
formhistory_suggestions_hide_cb (NULL, NULL, priv);
|
||||
goto free_data;
|
||||
}
|
||||
|
||||
store = GTK_LIST_STORE (priv->completion_model);
|
||||
gtk_list_store_clear (store);
|
||||
|
||||
while (result == SQLITE_ROW)
|
||||
{
|
||||
const unsigned char* text = sqlite3_column_text (stmt, 0);
|
||||
pos++;
|
||||
gtk_list_store_insert_with_values (store, NULL, pos, 0, text, -1);
|
||||
result = sqlite3_step (stmt);
|
||||
}
|
||||
sqlite3_reset (stmt);
|
||||
sqlite3_clear_bindings (stmt);
|
||||
|
||||
if (!gtk_widget_get_visible (priv->popup))
|
||||
{
|
||||
formhistory_reposition_popup (priv);
|
||||
gtk_widget_show_all (priv->popup);
|
||||
}
|
||||
|
||||
free_data:
|
||||
g_free (name);
|
||||
g_free (value);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
formhistory_editbox_key_pressed_cb (WebKitDOMElement* element,
|
||||
WebKitDOMEvent* dom_event,
|
||||
FormHistoryPriv* priv)
|
||||
{
|
||||
glong key;
|
||||
GtkTreePath* path;
|
||||
gchar* keyword;
|
||||
gint matches;
|
||||
|
||||
/* FIXME: Priv is still set after module is disabled */
|
||||
g_return_if_fail (priv);
|
||||
g_return_if_fail (element);
|
||||
|
||||
if (priv->completion_timeout > 0)
|
||||
g_source_remove (priv->completion_timeout);
|
||||
|
||||
katze_object_assign (priv->element, g_object_ref (element));
|
||||
|
||||
key = webkit_dom_ui_event_get_key_code (WEBKIT_DOM_UI_EVENT (dom_event));
|
||||
switch (key)
|
||||
{
|
||||
/* ESC key*/
|
||||
case 27:
|
||||
case 35:
|
||||
case 36:
|
||||
/* Left key*/
|
||||
case 37:
|
||||
/* Right key*/
|
||||
case 39:
|
||||
/* Enter key*/
|
||||
case 13:
|
||||
if (key == 27)
|
||||
g_object_set (element, "value", priv->oldkeyword, NULL);
|
||||
formhistory_suggestions_hide_cb (element, dom_event, priv);
|
||||
return;
|
||||
break;
|
||||
/* Del key */
|
||||
case 46:
|
||||
/* Up key */
|
||||
case 38:
|
||||
/* Down key */
|
||||
case 40:
|
||||
|
||||
if (!gtk_widget_get_visible (priv->popup))
|
||||
{
|
||||
formhistory_suggestions_show (priv);
|
||||
return;
|
||||
}
|
||||
matches = gtk_tree_model_iter_n_children (priv->completion_model, NULL);
|
||||
if (key == 38)
|
||||
{
|
||||
if (priv->selection_index <= 0)
|
||||
priv->selection_index = matches - 1;
|
||||
else
|
||||
priv->selection_index = MAX (priv->selection_index - 1, 0);
|
||||
}
|
||||
else if (key == 40)
|
||||
{
|
||||
if (priv->selection_index == matches - 1)
|
||||
priv->selection_index = 0;
|
||||
else
|
||||
priv->selection_index = MIN (priv->selection_index + 1, matches -1);
|
||||
}
|
||||
if (priv->selection_index == -1)
|
||||
{
|
||||
/* No element is selected */
|
||||
return;
|
||||
}
|
||||
|
||||
path = gtk_tree_path_new_from_indices (priv->selection_index, -1);
|
||||
if (key == 46)
|
||||
{
|
||||
g_object_set (element, "value", priv->oldkeyword, NULL);
|
||||
formhistory_suggestion_remove (path, priv);
|
||||
matches--;
|
||||
}
|
||||
|
||||
if (matches == 0)
|
||||
formhistory_suggestions_hide_cb (element, dom_event, priv);
|
||||
else
|
||||
{
|
||||
gtk_tree_view_set_cursor (GTK_TREE_VIEW (priv->treeview), path, NULL, FALSE);
|
||||
formhistory_suggestion_set (path, priv);
|
||||
}
|
||||
gtk_tree_path_free (path);
|
||||
return;
|
||||
break;
|
||||
/* PgUp, PgDn, Ins */
|
||||
case 33:
|
||||
case 34:
|
||||
case 45:
|
||||
/* Shift, Ctrl, Alt, Tab, Caps Lock*/
|
||||
case 16:
|
||||
case 17:
|
||||
case 18:
|
||||
case 20:
|
||||
case 9:
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
g_object_get (element, "value", &keyword, NULL);
|
||||
if (!(keyword && *keyword && *keyword != ' '))
|
||||
{
|
||||
formhistory_suggestions_hide_cb (element, dom_event, priv);
|
||||
goto free_data;
|
||||
}
|
||||
|
||||
/* If the same keyword is submitted there's no need to regenerate suggestions */
|
||||
if (gtk_widget_get_visible (priv->popup) &&
|
||||
!g_strcmp0 (keyword, priv->oldkeyword))
|
||||
goto free_data;
|
||||
priv->completion_timeout = midori_timeout_add (COMPLETION_DELAY,
|
||||
(GSourceFunc)formhistory_suggestions_show, priv, NULL);
|
||||
free_data:
|
||||
g_free (keyword);
|
||||
}
|
||||
|
||||
static void
|
||||
formhistory_DOMContentLoaded_cb (WebKitDOMElement* window,
|
||||
WebKitDOMEvent* dom_event,
|
||||
FormHistoryPriv* priv)
|
||||
{
|
||||
gulong i;
|
||||
WebKitDOMDocument* doc;
|
||||
WebKitDOMNodeList* inputs;
|
||||
WebKitDOMNodeList* frames;
|
||||
GtkWidget* web_view;
|
||||
|
||||
if (WEBKIT_DOM_IS_DOCUMENT (window))
|
||||
doc = WEBKIT_DOM_DOCUMENT (window);
|
||||
else
|
||||
doc = webkit_dom_dom_window_get_document (WEBKIT_DOM_DOM_WINDOW (window));
|
||||
inputs = webkit_dom_document_query_selector_all (doc, "input[type='text']", NULL);
|
||||
frames = g_object_get_data (G_OBJECT (window), "framelist");
|
||||
web_view = g_object_get_data (G_OBJECT (window), "webview");
|
||||
|
||||
for (i = 0; i < webkit_dom_node_list_get_length (inputs); i++)
|
||||
{
|
||||
WebKitDOMNode* element = webkit_dom_node_list_item (inputs, i);
|
||||
#if WEBKIT_CHECK_VERSION (1, 6, 1)
|
||||
gchar* autocomplete = webkit_dom_html_input_element_get_autocomplete (
|
||||
WEBKIT_DOM_HTML_INPUT_ELEMENT (element));
|
||||
gboolean off = !g_strcmp0 (autocomplete, "off");
|
||||
g_free (autocomplete);
|
||||
if (off)
|
||||
continue;
|
||||
#endif
|
||||
|
||||
g_object_set_data (G_OBJECT (element), "doc", doc);
|
||||
g_object_set_data (G_OBJECT (element), "webview", web_view);
|
||||
g_object_set_data (G_OBJECT (element), "framelist", frames);
|
||||
/* Add dblclick? */
|
||||
webkit_dom_event_target_add_event_listener (
|
||||
WEBKIT_DOM_EVENT_TARGET (element), "keyup",
|
||||
G_CALLBACK (formhistory_editbox_key_pressed_cb), false,
|
||||
priv);
|
||||
webkit_dom_event_target_add_event_listener (
|
||||
WEBKIT_DOM_EVENT_TARGET (element), "blur",
|
||||
G_CALLBACK (formhistory_suggestions_hide_cb), false,
|
||||
priv);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
formhistory_setup_suggestions (WebKitWebView* web_view,
|
||||
JSContextRef js_context,
|
||||
MidoriExtension* extension)
|
||||
{
|
||||
WebKitDOMDocument* doc;
|
||||
WebKitDOMNodeList* frames;
|
||||
gulong i;
|
||||
|
||||
FormHistoryPriv* priv = g_object_get_data (G_OBJECT (extension), "priv");
|
||||
doc = webkit_web_view_get_dom_document (web_view);
|
||||
frames = webkit_dom_document_query_selector_all (doc, "iframe, frame", NULL);
|
||||
g_object_set_data (G_OBJECT (doc), "framelist", frames);
|
||||
g_object_set_data (G_OBJECT (doc), "webview", web_view);
|
||||
/* Connect to DOMContentLoaded of the main frame */
|
||||
webkit_dom_event_target_add_event_listener(
|
||||
WEBKIT_DOM_EVENT_TARGET (doc), "DOMContentLoaded",
|
||||
G_CALLBACK (formhistory_DOMContentLoaded_cb), false,
|
||||
priv);
|
||||
|
||||
/* Connect to DOMContentLoaded of frames */
|
||||
for (i = 0; i < webkit_dom_node_list_get_length (frames); i++)
|
||||
{
|
||||
WebKitDOMDOMWindow* framewin;
|
||||
|
||||
WebKitDOMNode* frame = webkit_dom_node_list_item (frames, i);
|
||||
if (WEBKIT_DOM_IS_HTML_IFRAME_ELEMENT (frame))
|
||||
framewin = webkit_dom_html_iframe_element_get_content_window (WEBKIT_DOM_HTML_IFRAME_ELEMENT (frame));
|
||||
else
|
||||
framewin = webkit_dom_html_frame_element_get_content_window (WEBKIT_DOM_HTML_FRAME_ELEMENT (frame));
|
||||
g_object_set_data (G_OBJECT (framewin), "framelist", frames);
|
||||
g_object_set_data (G_OBJECT (framewin), "webview", (GtkWidget*)web_view);
|
||||
webkit_dom_event_target_add_event_listener (
|
||||
WEBKIT_DOM_EVENT_TARGET (framewin), "DOMContentLoaded",
|
||||
G_CALLBACK (formhistory_DOMContentLoaded_cb), false,
|
||||
priv);
|
||||
}
|
||||
formhistory_suggestions_hide_cb (NULL, NULL, priv);
|
||||
}
|
||||
|
||||
void
|
||||
formhistory_private_destroy (FormHistoryPriv *priv)
|
||||
{
|
||||
if (priv->db)
|
||||
{
|
||||
sqlite3_close (priv->db);
|
||||
priv->db = NULL;
|
||||
}
|
||||
katze_assign (priv->oldkeyword, NULL);
|
||||
gtk_widget_destroy (priv->popup);
|
||||
priv->popup = NULL;
|
||||
katze_object_assign (priv->element, NULL);
|
||||
g_slice_free (FormHistoryPriv, priv);
|
||||
}
|
||||
|
||||
gboolean
|
||||
formhistory_construct_popup_gui (FormHistoryPriv* priv)
|
||||
{
|
||||
GtkTreeModel* model = NULL;
|
||||
GtkWidget* popup;
|
||||
GtkWidget* popup_frame;
|
||||
GtkWidget* scrolled;
|
||||
GtkWidget* treeview;
|
||||
GtkCellRenderer* renderer;
|
||||
GtkTreeViewColumn* column;
|
||||
|
||||
model = (GtkTreeModel*) gtk_list_store_new (1, G_TYPE_STRING);
|
||||
priv->completion_model = model;
|
||||
popup = gtk_window_new (GTK_WINDOW_POPUP);
|
||||
gtk_window_set_type_hint (GTK_WINDOW (popup), GDK_WINDOW_TYPE_HINT_COMBO);
|
||||
popup_frame = gtk_frame_new (NULL);
|
||||
gtk_frame_set_shadow_type (GTK_FRAME (popup_frame), GTK_SHADOW_ETCHED_IN);
|
||||
gtk_container_add (GTK_CONTAINER (popup), popup_frame);
|
||||
scrolled = g_object_new (GTK_TYPE_SCROLLED_WINDOW,
|
||||
"hscrollbar-policy", GTK_POLICY_NEVER,
|
||||
"vscrollbar-policy", GTK_POLICY_AUTOMATIC, NULL);
|
||||
gtk_container_add (GTK_CONTAINER (popup_frame), scrolled);
|
||||
treeview = gtk_tree_view_new_with_model (model);
|
||||
priv->treeview = treeview;
|
||||
gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
|
||||
gtk_tree_view_set_hover_selection (GTK_TREE_VIEW (treeview), TRUE);
|
||||
gtk_container_add (GTK_CONTAINER (scrolled), treeview);
|
||||
gtk_widget_set_size_request (gtk_scrolled_window_get_vscrollbar (
|
||||
GTK_SCROLLED_WINDOW (scrolled)), -1, 0);
|
||||
|
||||
renderer = gtk_cell_renderer_text_new ();
|
||||
column = gtk_tree_view_column_new_with_attributes ("suggestions", renderer, "text", 0, NULL);
|
||||
gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
|
||||
priv->popup = popup;
|
||||
|
||||
g_signal_connect (treeview, "button-press-event",
|
||||
G_CALLBACK (formhistory_suggestion_selected_cb), priv);
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
141
extensions/formhistory/formhistory-js-frontend.c
Normal file
141
extensions/formhistory/formhistory-js-frontend.c
Normal file
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
Copyright (C) 2009-2012 Alexander Butenko <a.butenka@gmail.com>
|
||||
Copyright (C) 2009-2012 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.
|
||||
*/
|
||||
#include "formhistory-frontend.h"
|
||||
#ifdef FORMHISTORY_USE_JS
|
||||
|
||||
FormHistoryPriv*
|
||||
formhistory_private_new ()
|
||||
{
|
||||
FormHistoryPriv* priv = g_slice_new (FormHistoryPriv);
|
||||
return priv;
|
||||
}
|
||||
|
||||
gboolean
|
||||
formhistory_construct_popup_gui (FormHistoryPriv* priv)
|
||||
{
|
||||
gchar* autosuggest;
|
||||
gchar* style;
|
||||
guint i;
|
||||
gchar* file;
|
||||
|
||||
file = midori_app_find_res_filename ("autosuggestcontrol.js");
|
||||
if (!g_file_get_contents (file, &autosuggest, NULL, NULL))
|
||||
{
|
||||
g_free (file);
|
||||
return FALSE;
|
||||
}
|
||||
g_strchomp (autosuggest);
|
||||
|
||||
katze_assign (file, midori_app_find_res_filename ("autosuggestcontrol.css"));
|
||||
if (!g_file_get_contents (file, &style, NULL, NULL))
|
||||
{
|
||||
g_free (file);
|
||||
return FALSE;
|
||||
}
|
||||
g_strchomp (style);
|
||||
g_free (file);
|
||||
|
||||
i = 0;
|
||||
while (style[i])
|
||||
{
|
||||
if (style[i] == '\n')
|
||||
style[i] = ' ';
|
||||
i++;
|
||||
}
|
||||
|
||||
priv->jsforms = g_strdup_printf (
|
||||
"%s"
|
||||
"window.addEventListener ('DOMContentLoaded',"
|
||||
"function () {"
|
||||
" if (document.getElementById('formhistory'))"
|
||||
" return;"
|
||||
" if (!initSuggestions ())"
|
||||
" return;"
|
||||
" var mystyle = document.createElement('style');"
|
||||
" mystyle.setAttribute('type', 'text/css');"
|
||||
" mystyle.setAttribute('id', 'formhistory');"
|
||||
" mystyle.appendChild(document.createTextNode('%s'));"
|
||||
" var head = document.getElementsByTagName('head')[0];"
|
||||
" if (head) head.appendChild(mystyle);"
|
||||
"}, true);",
|
||||
autosuggest,
|
||||
style);
|
||||
g_strstrip (priv->jsforms);
|
||||
g_free (style);
|
||||
g_free (autosuggest);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
formhistory_setup_suggestions (WebKitWebView* web_view,
|
||||
JSContextRef js_context,
|
||||
MidoriExtension* extension)
|
||||
{
|
||||
GString* suggestions;
|
||||
FormHistoryPriv* priv;
|
||||
static sqlite3_stmt* stmt;
|
||||
const char* sqlcmd;
|
||||
const unsigned char* key;
|
||||
const unsigned char* value;
|
||||
|
||||
gint result, pos;
|
||||
|
||||
priv = g_object_get_data (G_OBJECT (extension), "priv");
|
||||
if (!priv->db)
|
||||
return;
|
||||
|
||||
if (!stmt)
|
||||
{
|
||||
sqlcmd = "SELECT DISTINCT group_concat(value,'\",\"'), field FROM forms \
|
||||
GROUP BY field ORDER BY field";
|
||||
sqlite3_prepare_v2 (priv->db, sqlcmd, strlen (sqlcmd) + 1, &stmt, NULL);
|
||||
}
|
||||
result = sqlite3_step (stmt);
|
||||
if (result != SQLITE_ROW)
|
||||
{
|
||||
if (result == SQLITE_ERROR)
|
||||
g_print (_("Failed to select suggestions\n"));
|
||||
sqlite3_reset (stmt);
|
||||
return;
|
||||
}
|
||||
suggestions = g_string_new (
|
||||
"function FormSuggestions(eid) { "
|
||||
"arr = new Array();");
|
||||
|
||||
while (result == SQLITE_ROW)
|
||||
{
|
||||
pos++;
|
||||
value = sqlite3_column_text (stmt, 0);
|
||||
key = sqlite3_column_text (stmt, 1);
|
||||
if (value)
|
||||
{
|
||||
g_string_append_printf (suggestions, " arr[\"%s\"] = [\"%s\"]; ",
|
||||
(gchar*)key, (gchar*)value);
|
||||
}
|
||||
result = sqlite3_step (stmt);
|
||||
}
|
||||
g_string_append (suggestions, "this.suggestions = arr[eid]; }");
|
||||
g_string_append (suggestions, priv->jsforms);
|
||||
sokoke_js_script_eval (js_context, suggestions->str, NULL);
|
||||
g_string_free (suggestions, TRUE);
|
||||
}
|
||||
|
||||
void
|
||||
formhistory_private_destroy (FormHistoryPriv *priv)
|
||||
{
|
||||
if (priv->db)
|
||||
{
|
||||
sqlite3_close (priv->db);
|
||||
priv->db = NULL;
|
||||
}
|
||||
katze_assign (priv->jsforms, NULL);
|
||||
g_slice_free (FormHistoryPriv, priv);
|
||||
}
|
||||
#endif
|
694
extensions/formhistory/formhistory.c
Normal file
694
extensions/formhistory/formhistory.c
Normal file
|
@ -0,0 +1,694 @@
|
|||
/*
|
||||
Copyright (C) 2009-2012 Alexander Butenko <a.butenka@gmail.com>
|
||||
Copyright (C) 2009-2012 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.
|
||||
*/
|
||||
#define MAXCHARS 60
|
||||
#define MINCHARS 2
|
||||
#define GTK_RESPONSE_IGNORE 99
|
||||
#include "formhistory-frontend.h"
|
||||
|
||||
static void
|
||||
formhistory_toggle_state_cb (GtkAction* action,
|
||||
MidoriBrowser* browser);
|
||||
|
||||
static void
|
||||
formhistory_update_database (gpointer db,
|
||||
const gchar* host,
|
||||
const gchar* key,
|
||||
const gchar* value)
|
||||
{
|
||||
gchar* sqlcmd;
|
||||
gchar* errmsg;
|
||||
gint success;
|
||||
|
||||
if (!(value && *value))
|
||||
return;
|
||||
|
||||
sqlcmd = sqlite3_mprintf ("INSERT INTO forms VALUES('%q', '%q', '%q')",
|
||||
host, 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;
|
||||
}
|
||||
}
|
||||
|
||||
static gchar*
|
||||
formhistory_get_login_data (gpointer db,
|
||||
const gchar* uri)
|
||||
{
|
||||
gchar* domain;
|
||||
static sqlite3_stmt* stmt;
|
||||
gint result;
|
||||
gchar* value = NULL;
|
||||
|
||||
g_return_val_if_fail (db != NULL, NULL);
|
||||
g_return_val_if_fail (uri != NULL, NULL);
|
||||
domain = midori_uri_parse_hostname (uri, NULL);
|
||||
g_return_val_if_fail (domain != NULL, NULL);
|
||||
|
||||
if (!stmt)
|
||||
{
|
||||
const gchar* sqlcmd = "SELECT value FROM forms WHERE domain = ?1 and field = 'MidoriPasswordManager' limit 1";
|
||||
sqlite3_prepare_v2 (db, sqlcmd, strlen (sqlcmd) + 1, &stmt, NULL);
|
||||
}
|
||||
sqlite3_bind_text (stmt, 1, domain, -1, NULL);
|
||||
result = sqlite3_step (stmt);
|
||||
if (result == SQLITE_ROW)
|
||||
value = g_strdup ((gchar*)sqlite3_column_text (stmt, 0));
|
||||
sqlite3_reset (stmt);
|
||||
sqlite3_clear_bindings (stmt);
|
||||
g_free (domain);
|
||||
return value;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
formhistory_check_master_password (GtkWidget* parent,
|
||||
FormHistoryPriv* priv)
|
||||
{
|
||||
GtkWidget* dialog;
|
||||
GtkWidget* content_area;
|
||||
GtkWidget* hbox;
|
||||
GtkWidget* image;
|
||||
GtkWidget* label;
|
||||
GtkWidget* entry;
|
||||
const gchar* title;
|
||||
static int alive;
|
||||
gboolean ret = FALSE;
|
||||
|
||||
/* Password is set */
|
||||
if (priv->master_password && *priv->master_password)
|
||||
return TRUE;
|
||||
|
||||
/* Other prompt is active */
|
||||
if (alive == 1)
|
||||
return FALSE;
|
||||
|
||||
/* Prompt was cancelled */
|
||||
if (priv->master_password_canceled == 1)
|
||||
return FALSE;
|
||||
|
||||
alive = 1;
|
||||
title = _("Form history");
|
||||
dialog = gtk_dialog_new_with_buttons (title, GTK_WINDOW (parent),
|
||||
GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
|
||||
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
||||
GTK_STOCK_OK, GTK_RESPONSE_OK,
|
||||
NULL);
|
||||
content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
|
||||
gtk_window_set_icon_name (GTK_WINDOW (dialog), GTK_STOCK_DIALOG_AUTHENTICATION);
|
||||
gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
|
||||
gtk_container_set_border_width (GTK_CONTAINER (content_area), 5);
|
||||
|
||||
hbox = gtk_hbox_new (FALSE, 8);
|
||||
gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
|
||||
image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_AUTHENTICATION,
|
||||
GTK_ICON_SIZE_DIALOG);
|
||||
gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
|
||||
|
||||
label = gtk_label_new (_("Master password required\n"
|
||||
"to open password database"));
|
||||
gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0);
|
||||
gtk_container_add (GTK_CONTAINER (content_area), hbox);
|
||||
|
||||
entry = gtk_entry_new ();
|
||||
g_object_set (entry, "truncate-multiline", TRUE, NULL);
|
||||
gtk_entry_set_visibility(GTK_ENTRY (entry),FALSE);
|
||||
gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
|
||||
gtk_container_add (GTK_CONTAINER (content_area), entry);
|
||||
|
||||
gtk_widget_show_all (entry);
|
||||
gtk_widget_show_all (hbox);
|
||||
gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
|
||||
|
||||
if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK)
|
||||
{
|
||||
/* FIXME: add password verification */
|
||||
katze_assign (priv->master_password,
|
||||
g_strdup (gtk_entry_get_text (GTK_ENTRY (entry))));
|
||||
ret = TRUE;
|
||||
}
|
||||
else
|
||||
priv->master_password_canceled = 1;
|
||||
|
||||
gtk_widget_destroy (dialog);
|
||||
alive = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gchar*
|
||||
formhistory_encrypt (const gchar* data,
|
||||
const gchar* password)
|
||||
{
|
||||
/* TODO: Implement persistent storage/ keyring support */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
formhistory_remember_password_response (GtkWidget* infobar,
|
||||
gint response_id,
|
||||
FormhistoryPasswordEntry* entry)
|
||||
{
|
||||
gchar* encrypted_form;
|
||||
|
||||
if (response_id == GTK_RESPONSE_IGNORE)
|
||||
goto cleanup;
|
||||
|
||||
if (formhistory_check_master_password (NULL, entry->priv))
|
||||
{
|
||||
if (response_id != GTK_RESPONSE_ACCEPT)
|
||||
katze_assign (entry->form_data, g_strdup ("never"));
|
||||
|
||||
if ((encrypted_form = formhistory_encrypt (entry->form_data,
|
||||
entry->priv->master_password)))
|
||||
formhistory_update_database (entry->priv->db, entry->domain, "MidoriPasswordManager", encrypted_form);
|
||||
g_free (encrypted_form);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
g_free (entry->form_data);
|
||||
g_free (entry->domain);
|
||||
g_slice_free (FormhistoryPasswordEntry, entry);
|
||||
gtk_widget_destroy (infobar);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
formhistory_navigation_decision_cb (WebKitWebView* web_view,
|
||||
WebKitWebFrame* web_frame,
|
||||
WebKitNetworkRequest* request,
|
||||
WebKitWebNavigationAction* action,
|
||||
WebKitWebPolicyDecision* decision,
|
||||
MidoriExtension* extension)
|
||||
{
|
||||
FormHistoryPriv* priv;
|
||||
JSContextRef js_context;
|
||||
gchar* value;
|
||||
|
||||
/* 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 (var i = 0; i < inputs.length; i++) {"
|
||||
" if (inputs[i].getAttribute('autocomplete') == 'off' && "
|
||||
" inputs[i].type == 'text')"
|
||||
" continue;"
|
||||
" 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 (!eid && ename)"
|
||||
" eid=ename;"
|
||||
" out += eid+'|,|'+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)
|
||||
return FALSE;
|
||||
|
||||
priv = g_object_get_data (G_OBJECT (extension), "priv");
|
||||
js_context = webkit_web_frame_get_global_context (web_frame);
|
||||
value = sokoke_js_script_eval (js_context, script, NULL);
|
||||
|
||||
#ifdef FORMHISTORY_USE_GDOM
|
||||
formhistory_suggestions_hide_cb (NULL, NULL, priv);
|
||||
#endif
|
||||
if (value && *value)
|
||||
{
|
||||
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])
|
||||
{
|
||||
if (strcmp (parts[2], "password"))
|
||||
formhistory_update_database (priv->db, NULL, parts[0], parts[1]);
|
||||
#if WEBKIT_CHECK_VERSION (1, 3, 8)
|
||||
else
|
||||
{
|
||||
#if 0
|
||||
FormhistoryPasswordEntry* entry;
|
||||
#endif
|
||||
gchar* data = formhistory_get_login_data (priv->db, webkit_web_frame_get_uri (web_frame));
|
||||
if (data)
|
||||
{
|
||||
g_free (data);
|
||||
break;
|
||||
}
|
||||
#if 0
|
||||
entry = g_slice_new (FormhistoryPasswordEntry);
|
||||
/* Domain and form data are freed from infopanel callback*/
|
||||
entry->form_data = g_strdup (value);
|
||||
entry->domain = domain;
|
||||
entry->priv = priv;
|
||||
g_object_set_data (G_OBJECT (web_view), "FormHistoryPasswordEntry", entry);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
g_strfreev (parts);
|
||||
i++;
|
||||
}
|
||||
g_strfreev (inputs);
|
||||
g_free (value);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
formhistory_window_object_cleared_cb (WebKitWebView* web_view,
|
||||
WebKitWebFrame* web_frame,
|
||||
JSContextRef js_context,
|
||||
JSObjectRef js_window,
|
||||
MidoriExtension* extension)
|
||||
{
|
||||
const gchar* page_uri;
|
||||
FormhistoryPasswordEntry* entry;
|
||||
GtkWidget* view;
|
||||
|
||||
page_uri = webkit_web_frame_get_uri (web_frame);
|
||||
if (!page_uri)
|
||||
return;
|
||||
|
||||
if (!midori_uri_is_http (page_uri) && !g_str_has_prefix (page_uri, "file"))
|
||||
return;
|
||||
|
||||
formhistory_setup_suggestions (web_view, js_context, extension);
|
||||
|
||||
#if WEBKIT_CHECK_VERSION (1, 3, 8)
|
||||
entry = g_object_get_data (G_OBJECT (web_view), "FormHistoryPasswordEntry");
|
||||
if (entry)
|
||||
{
|
||||
const gchar* message = _("Remember password on this page?");
|
||||
view = midori_browser_get_current_tab (midori_app_get_browser (
|
||||
midori_extension_get_app (extension)));
|
||||
midori_view_add_info_bar (MIDORI_VIEW (view), GTK_MESSAGE_QUESTION, message,
|
||||
G_CALLBACK (formhistory_remember_password_response), entry,
|
||||
_("Remember"), GTK_RESPONSE_ACCEPT,
|
||||
_("Not now"), GTK_RESPONSE_IGNORE,
|
||||
_("Never for this page"), GTK_RESPONSE_CANCEL, NULL);
|
||||
g_object_set_data (G_OBJECT (web_view), "FormHistoryPasswordEntry", NULL);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if WEBKIT_CHECK_VERSION (1, 3, 8)
|
||||
static gchar*
|
||||
formhistory_decrypt (const gchar* data,
|
||||
const gchar* password)
|
||||
{
|
||||
/* TODO: Implement persistent storage/ keyring support */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
formhistory_fill_login_data (JSContextRef js_context,
|
||||
FormHistoryPriv* priv,
|
||||
const gchar* data)
|
||||
{
|
||||
gchar* decrypted_data = NULL;
|
||||
guint i = 0;
|
||||
GString *script;
|
||||
gchar** inputs;
|
||||
|
||||
/* Handle case that user dont want to store password */
|
||||
if (!strncmp (data, "never", 5))
|
||||
return;
|
||||
|
||||
#if 0
|
||||
if (!formhistory_check_master_password (NULL, priv))
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (!(decrypted_data = formhistory_decrypt (data, priv->master_password)))
|
||||
return;
|
||||
|
||||
script = g_string_new ("");
|
||||
inputs = g_strsplit (decrypted_data, "|||", 0);
|
||||
while (inputs[i] != NULL)
|
||||
{
|
||||
gchar** parts = g_strsplit (inputs[i], "|,|", 3);
|
||||
if (parts && parts[0] && parts[1] && parts[2])
|
||||
{
|
||||
g_string_append_printf (script, "node = null;"
|
||||
"node = document.getElementById ('%s');"
|
||||
"if (!node) { node = document.getElementsByName ('%s')[0]; }"
|
||||
"if (node && node.type == '%s') { node.value = '%s'; }",
|
||||
parts[0], parts[0], parts[2], parts[1]);
|
||||
}
|
||||
g_strfreev (parts);
|
||||
i++;
|
||||
}
|
||||
g_free (decrypted_data);
|
||||
g_strfreev (inputs);
|
||||
g_free (sokoke_js_script_eval (js_context, script->str, NULL));
|
||||
g_string_free (script, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
formhistory_frame_loaded_cb (WebKitWebView* web_view,
|
||||
WebKitWebFrame* web_frame,
|
||||
MidoriExtension* extension)
|
||||
{
|
||||
const gchar* page_uri;
|
||||
const gchar* count_request;
|
||||
FormHistoryPriv* priv;
|
||||
JSContextRef js_context;
|
||||
gchar* data;
|
||||
gchar* count;
|
||||
|
||||
page_uri = webkit_web_frame_get_uri (web_frame);
|
||||
if (!page_uri)
|
||||
return;
|
||||
|
||||
count_request = "document.querySelectorAll('input[type=password]').length";
|
||||
js_context = webkit_web_frame_get_global_context (web_frame);
|
||||
count = sokoke_js_script_eval (js_context, count_request, NULL);
|
||||
if (count && count[0] == '0')
|
||||
{
|
||||
g_free (count);
|
||||
return;
|
||||
}
|
||||
g_free (count);
|
||||
|
||||
priv = g_object_get_data (G_OBJECT (extension), "priv");
|
||||
data = formhistory_get_login_data (priv->db, webkit_web_frame_get_uri (web_frame));
|
||||
|
||||
if (!data)
|
||||
return;
|
||||
formhistory_fill_login_data (js_context, priv, data);
|
||||
g_free (data);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
formhistory_deactivate_cb (MidoriExtension* extension,
|
||||
MidoriBrowser* browser);
|
||||
|
||||
static void
|
||||
formhistory_add_tab_cb (MidoriBrowser* browser,
|
||||
MidoriView* view,
|
||||
MidoriExtension* extension)
|
||||
{
|
||||
GtkWidget* web_view = midori_view_get_web_view (view);
|
||||
|
||||
g_signal_connect (web_view, "window-object-cleared",
|
||||
G_CALLBACK (formhistory_window_object_cleared_cb), extension);
|
||||
g_signal_connect (web_view, "navigation-policy-decision-requested",
|
||||
G_CALLBACK (formhistory_navigation_decision_cb), extension);
|
||||
|
||||
#if WEBKIT_CHECK_VERSION (1, 3, 8)
|
||||
g_signal_connect (web_view, "onload-event",
|
||||
G_CALLBACK (formhistory_frame_loaded_cb), extension);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
formhistory_app_add_browser_cb (MidoriApp* app,
|
||||
MidoriBrowser* browser,
|
||||
MidoriExtension* extension)
|
||||
{
|
||||
|
||||
GtkAccelGroup* acg = gtk_accel_group_new ();
|
||||
GtkActionGroup* action_group = midori_browser_get_action_group (browser);
|
||||
GtkAction* action = gtk_action_new ("FormHistoryToggleState",
|
||||
_("Toggle form history state"),
|
||||
_("Activate or deactivate form history for the current tab."), NULL);
|
||||
gtk_window_add_accel_group (GTK_WINDOW (browser), acg);
|
||||
|
||||
g_object_set_data (G_OBJECT (browser), "FormHistoryExtension", extension);
|
||||
|
||||
g_signal_connect (action, "activate",
|
||||
G_CALLBACK (formhistory_toggle_state_cb), browser);
|
||||
|
||||
gtk_action_group_add_action_with_accel (action_group, action, "<Ctrl><Shift>F");
|
||||
gtk_action_set_accel_group (action, acg);
|
||||
gtk_action_connect_accelerator (action);
|
||||
|
||||
if (midori_extension_get_boolean (extension, "always-load"))
|
||||
{
|
||||
GList* tabs = midori_browser_get_tabs (browser);
|
||||
for (; tabs; tabs = g_list_next (tabs))
|
||||
formhistory_add_tab_cb (browser, tabs->data, extension);
|
||||
g_list_free (tabs);
|
||||
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_tab (MidoriView* view,
|
||||
MidoriExtension* extension)
|
||||
{
|
||||
GtkWidget* web_view = midori_view_get_web_view (view);
|
||||
|
||||
g_signal_handlers_disconnect_by_func (
|
||||
web_view, formhistory_window_object_cleared_cb, extension);
|
||||
g_signal_handlers_disconnect_by_func (
|
||||
web_view, formhistory_navigation_decision_cb, extension);
|
||||
#if WEBKIT_CHECK_VERSION (1, 3, 8)
|
||||
g_signal_handlers_disconnect_by_func (
|
||||
web_view, formhistory_frame_loaded_cb, extension);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
formhistory_deactivate_cb (MidoriExtension* extension,
|
||||
MidoriBrowser* browser)
|
||||
{
|
||||
MidoriApp* app = midori_extension_get_app (extension);
|
||||
FormHistoryPriv* priv = g_object_get_data (G_OBJECT (extension), "priv");
|
||||
|
||||
GtkActionGroup* action_group = midori_browser_get_action_group (browser);
|
||||
GtkAction* action;
|
||||
|
||||
g_signal_handlers_disconnect_by_func (
|
||||
browser, formhistory_add_tab_cb, extension);
|
||||
g_signal_handlers_disconnect_by_func (
|
||||
extension, formhistory_deactivate_cb, browser);
|
||||
g_signal_handlers_disconnect_by_func (
|
||||
app, formhistory_app_add_browser_cb, extension);
|
||||
GList* tabs = midori_browser_get_tabs (browser);
|
||||
for (; tabs; tabs = g_list_next (tabs))
|
||||
formhistory_deactivate_tab (tabs->data, extension);
|
||||
g_list_free (tabs);
|
||||
|
||||
g_object_set_data (G_OBJECT (browser), "FormHistoryExtension", NULL);
|
||||
action = gtk_action_group_get_action (action_group, "FormHistoryToggleState");
|
||||
if (action != NULL)
|
||||
{
|
||||
gtk_action_group_remove_action (action_group, action);
|
||||
g_object_unref (action);
|
||||
}
|
||||
|
||||
formhistory_private_destroy (priv);
|
||||
}
|
||||
|
||||
static FormHistoryPriv*
|
||||
formhistory_new (const gchar* config_dir)
|
||||
{
|
||||
gchar* filename;
|
||||
sqlite3* db;
|
||||
char* errmsg = NULL, *errmsg2 = NULL;
|
||||
FormHistoryPriv* priv = formhistory_private_new ();
|
||||
priv->master_password = NULL;
|
||||
priv->master_password_canceled = 0;
|
||||
formhistory_construct_popup_gui (priv);
|
||||
|
||||
filename = g_build_filename (config_dir, "forms.db", NULL);
|
||||
if (sqlite3_open (filename, &db) != SQLITE_OK)
|
||||
{
|
||||
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,
|
||||
/* "PRAGMA synchronous = OFF; PRAGMA temp_store = MEMORY" */
|
||||
"PRAGMA count_changes = OFF; PRAGMA journal_mode = TRUNCATE;",
|
||||
NULL, NULL, &errmsg);
|
||||
priv->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);
|
||||
}
|
||||
return priv;
|
||||
}
|
||||
|
||||
static void
|
||||
formhistory_activate_cb (MidoriExtension* extension,
|
||||
MidoriApp* app)
|
||||
{
|
||||
const gchar* config_dir = midori_extension_get_config_dir (extension);
|
||||
FormHistoryPriv* priv = formhistory_new (config_dir);
|
||||
KatzeArray* browsers = katze_object_get_object (app, "browsers");
|
||||
MidoriBrowser* browser;
|
||||
g_object_set_data (G_OBJECT (extension), "priv", priv);
|
||||
|
||||
KATZE_ARRAY_FOREACH_ITEM (browser, browsers)
|
||||
formhistory_app_add_browser_cb (app, browser, extension);
|
||||
g_signal_connect (app, "add-browser",
|
||||
G_CALLBACK (formhistory_app_add_browser_cb), extension);
|
||||
g_object_unref (browsers);
|
||||
}
|
||||
|
||||
static void
|
||||
formhistory_preferences_response_cb (GtkWidget* dialog,
|
||||
gint response_id,
|
||||
MidoriExtension* extension)
|
||||
{
|
||||
GtkWidget* checkbox;
|
||||
gboolean old_state;
|
||||
gboolean new_state;
|
||||
MidoriApp* app;
|
||||
KatzeArray* browsers;
|
||||
MidoriBrowser* browser;
|
||||
|
||||
if (response_id == GTK_RESPONSE_APPLY)
|
||||
{
|
||||
checkbox = g_object_get_data (G_OBJECT (dialog), "always-load-checkbox");
|
||||
new_state = !gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (checkbox));
|
||||
old_state = midori_extension_get_boolean (extension, "always-load");
|
||||
|
||||
if (old_state != new_state)
|
||||
{
|
||||
midori_extension_set_boolean (extension, "always-load", new_state);
|
||||
|
||||
app = midori_extension_get_app (extension);
|
||||
browsers = katze_object_get_object (app, "browsers");
|
||||
KATZE_ARRAY_FOREACH_ITEM (browser, browsers)
|
||||
{
|
||||
GList* tabs = midori_browser_get_tabs (browser);
|
||||
for (; tabs; tabs = g_list_next (tabs))
|
||||
formhistory_deactivate_tab (tabs->data, extension);
|
||||
g_signal_handlers_disconnect_by_func (
|
||||
browser, formhistory_add_tab_cb, extension);
|
||||
|
||||
if (new_state)
|
||||
{
|
||||
for (; tabs; tabs = g_list_next (tabs))
|
||||
formhistory_add_tab_cb (browser, tabs->data, extension);
|
||||
g_signal_connect (browser, "add-tab",
|
||||
G_CALLBACK (formhistory_add_tab_cb), extension);
|
||||
}
|
||||
g_list_free (tabs);
|
||||
}
|
||||
}
|
||||
}
|
||||
gtk_widget_destroy (dialog);
|
||||
}
|
||||
|
||||
static void
|
||||
formhistory_preferences_cb (MidoriExtension* extension)
|
||||
{
|
||||
GtkWidget* dialog;
|
||||
GtkWidget* content_area;
|
||||
GtkWidget* checkbox;
|
||||
|
||||
dialog = gtk_dialog_new ();
|
||||
|
||||
gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
|
||||
|
||||
gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
|
||||
gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_APPLY, GTK_RESPONSE_APPLY);
|
||||
|
||||
content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
|
||||
checkbox = gtk_check_button_new_with_label (_("Only activate form history via hotkey (Ctrl+Shift+F) per tab"));
|
||||
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbox),
|
||||
!midori_extension_get_boolean (extension, "always-load"));
|
||||
g_object_set_data (G_OBJECT (dialog), "always-load-checkbox", checkbox);
|
||||
gtk_container_add (GTK_CONTAINER (content_area), checkbox);
|
||||
/* FIXME: Add pref to disable password manager */
|
||||
|
||||
g_signal_connect (dialog,
|
||||
"response",
|
||||
G_CALLBACK (formhistory_preferences_response_cb),
|
||||
extension);
|
||||
gtk_widget_show_all (dialog);
|
||||
}
|
||||
|
||||
static void
|
||||
formhistory_toggle_state_cb (GtkAction* action,
|
||||
MidoriBrowser* browser)
|
||||
{
|
||||
MidoriView* view = MIDORI_VIEW (midori_browser_get_current_tab (browser));
|
||||
MidoriExtension* extension = g_object_get_data (G_OBJECT (browser), "FormHistoryExtension");
|
||||
GtkWidget* web_view = midori_view_get_web_view (view);
|
||||
|
||||
if (g_signal_handler_find (web_view, G_SIGNAL_MATCH_FUNC,
|
||||
g_signal_lookup ("window-object-cleared", MIDORI_TYPE_VIEW), 0, NULL,
|
||||
formhistory_window_object_cleared_cb, extension))
|
||||
{
|
||||
formhistory_deactivate_tab (view, extension);
|
||||
}
|
||||
else
|
||||
formhistory_add_tab_cb (browser, view, extension);
|
||||
}
|
||||
|
||||
static void
|
||||
test_formhistory_login (void)
|
||||
{
|
||||
gchar* config_dir = midori_paths_get_extension_config_dir ("formhistory");
|
||||
FormHistoryPriv* priv = formhistory_new (config_dir);
|
||||
g_free (formhistory_get_login_data (priv->db, "http://example.com"));
|
||||
g_free (formhistory_get_login_data (priv->db, "http://beispiel.de"));
|
||||
formhistory_update_database (priv->db, "http://example.com", "MidoriPasswordManager", "lalelu");
|
||||
formhistory_update_database (priv->db, NULL, "spam", "eggs");
|
||||
g_free (formhistory_get_login_data (priv->db, "http://example.com"));
|
||||
g_free (formhistory_get_login_data (priv->db, "http://beispiel.de"));
|
||||
g_free (config_dir);
|
||||
formhistory_private_destroy (priv);
|
||||
}
|
||||
|
||||
void
|
||||
extension_test (void)
|
||||
{
|
||||
g_test_add_func ("/extensions/formhistory/login", test_formhistory_login);
|
||||
}
|
||||
|
||||
MidoriExtension*
|
||||
extension_init (void)
|
||||
{
|
||||
MidoriExtension* extension = g_object_new (MIDORI_TYPE_EXTENSION,
|
||||
"name", _("Form history filler"),
|
||||
"description", _("Stores history of entered form data"),
|
||||
"version", "2.0" MIDORI_VERSION_SUFFIX,
|
||||
"authors", "Alexander V. Butenko <a.butenka@gmail.com>",
|
||||
NULL);
|
||||
|
||||
midori_extension_install_boolean (extension, "always-load", TRUE);
|
||||
g_signal_connect (extension, "activate",
|
||||
G_CALLBACK (formhistory_activate_cb), NULL);
|
||||
g_signal_connect (extension, "open-preferences",
|
||||
G_CALLBACK (formhistory_preferences_cb), NULL);
|
||||
|
||||
return extension;
|
||||
}
|
|
@ -18,6 +18,8 @@ namespace HistoryList {
|
|||
enum TabTreeCells {
|
||||
TREE_CELL_PIXBUF,
|
||||
TREE_CELL_STRING,
|
||||
TREE_CELL_FG,
|
||||
TREE_CELL_BG,
|
||||
TREE_CELL_POINTER,
|
||||
TREE_CELL_COUNT
|
||||
}
|
||||
|
@ -83,6 +85,8 @@ namespace HistoryList {
|
|||
store.append (out iter);
|
||||
store.set (iter, TabTreeCells.TREE_CELL_PIXBUF, icon,
|
||||
TabTreeCells.TREE_CELL_STRING, title,
|
||||
TabTreeCells.TREE_CELL_FG, view.fg_color,
|
||||
TabTreeCells.TREE_CELL_BG, view.bg_color,
|
||||
TabTreeCells.TREE_CELL_POINTER, view);
|
||||
}
|
||||
}
|
||||
|
@ -109,7 +113,8 @@ namespace HistoryList {
|
|||
this.hbox.pack_start (sw, true, true, 0);
|
||||
|
||||
var store = new Gtk.ListStore (TabTreeCells.TREE_CELL_COUNT,
|
||||
typeof (Gdk.Pixbuf), typeof (string), typeof (void*));
|
||||
typeof (Gdk.Pixbuf), typeof (string),
|
||||
typeof (Gdk.Color), typeof (Gdk.Color), typeof (void*));
|
||||
|
||||
this.insert_rows (store);
|
||||
|
||||
|
@ -123,18 +128,22 @@ namespace HistoryList {
|
|||
|
||||
this.treeview.insert_column_with_attributes (
|
||||
-1, "Icon",
|
||||
new CellRendererPixbuf (), "pixbuf", TabTreeCells.TREE_CELL_PIXBUF);
|
||||
new CellRendererPixbuf (), "pixbuf", TabTreeCells.TREE_CELL_PIXBUF,
|
||||
"cell-background-gdk", TabTreeCells.TREE_CELL_BG);
|
||||
this.treeview.insert_column_with_attributes (
|
||||
-1, "Title",
|
||||
new CellRendererText (), "text", TabTreeCells.TREE_CELL_STRING);
|
||||
new CellRendererText (), "text", TabTreeCells.TREE_CELL_STRING,
|
||||
"foreground-gdk", TabTreeCells.TREE_CELL_FG,
|
||||
"cell-background-gdk", TabTreeCells.TREE_CELL_BG);
|
||||
|
||||
this.show_all ();
|
||||
|
||||
Requisition requisition;
|
||||
int height;
|
||||
int max_lines = 10;
|
||||
#if HAVE_GTK3
|
||||
requisition = Requisition();
|
||||
this.treeview.get_preferred_width(out requisition.width, null);
|
||||
this.treeview.get_preferred_height(out requisition.height, null);
|
||||
this.treeview.get_preferred_size(out requisition, null);
|
||||
#else
|
||||
this.treeview.size_request (out requisition);
|
||||
#endif
|
||||
|
@ -145,8 +154,6 @@ namespace HistoryList {
|
|||
height = requisition.height + 2;
|
||||
}
|
||||
sw.set_size_request (320, height);
|
||||
|
||||
this.show_all ();
|
||||
}
|
||||
|
||||
public override void make_update () {
|
||||
|
@ -225,7 +232,7 @@ namespace HistoryList {
|
|||
}
|
||||
}
|
||||
|
||||
private class PreferencesDialog : Dialog {
|
||||
private class PreferencesDialog : Gtk.Dialog {
|
||||
protected Manager hl_manager;
|
||||
protected ComboBox closing_behavior;
|
||||
|
||||
|
@ -243,7 +250,7 @@ namespace HistoryList {
|
|||
this.response.connect (response_cb);
|
||||
}
|
||||
|
||||
private void response_cb (Dialog source, int response_id) {
|
||||
private void response_cb (Gtk.Dialog source, int response_id) {
|
||||
switch (response_id) {
|
||||
case ResponseType.APPLY:
|
||||
int value;
|
||||
|
@ -304,6 +311,12 @@ namespace HistoryList {
|
|||
|
||||
table.attach_defaults (this.closing_behavior, 1, 2, 0, 1);
|
||||
|
||||
#if !HAVE_WIN32
|
||||
var proxy = Katze.property_proxy (this.hl_manager.get_app ().settings, "flash-window-on-new-bg-tabs", null);
|
||||
(proxy as Gtk.Button).label = _("Flash window on background tabs");
|
||||
table.attach_defaults (proxy, 0, 2, 1, 2);
|
||||
#endif
|
||||
|
||||
#if HAVE_GTK3
|
||||
(get_content_area() as Gtk.Box).pack_start (table, false, true, 0);
|
||||
#else
|
||||
|
@ -331,15 +344,27 @@ namespace HistoryList {
|
|||
this.closing_behavior = this.get_integer ("TabClosingBehavior");
|
||||
}
|
||||
|
||||
public bool is_key_a_modifier (Gdk.EventKey event_key) {
|
||||
#if HAVE_WIN32
|
||||
/* On win is_modifier check does not seem to work */
|
||||
if (event_key.keyval == Gdk.keyval_from_name("Control_L"))
|
||||
return true;
|
||||
#else
|
||||
if (event_key.is_modifier > 0)
|
||||
return true;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool key_press (Gdk.EventKey event_key) {
|
||||
if (event_key.is_modifier > 0) {
|
||||
if (is_key_a_modifier (event_key)) {
|
||||
this.modifier_count++;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool key_release (Gdk.EventKey event_key, Browser browser) {
|
||||
if (event_key.is_modifier > 0) {
|
||||
if (is_key_a_modifier (event_key)) {
|
||||
this.modifier_count--;
|
||||
}
|
||||
if (this.modifier_count == 0 || event_key.keyval == this.escKeyval) {
|
||||
|
@ -462,7 +487,7 @@ namespace HistoryList {
|
|||
tab_added (browser, tab);
|
||||
browser.add_tab.connect (tab_added);
|
||||
browser.remove_tab.connect (tab_removed);
|
||||
browser.notify["tab"].connect (this.tab_changed);
|
||||
browser.switch_tab.connect (this.tab_changed);
|
||||
}
|
||||
|
||||
void browser_removed (Midori.Browser browser) {
|
||||
|
@ -491,7 +516,7 @@ namespace HistoryList {
|
|||
|
||||
browser.add_tab.disconnect (tab_added);
|
||||
browser.remove_tab.disconnect (tab_removed);
|
||||
browser.notify["tab"].disconnect (this.tab_changed);
|
||||
browser.switch_tab.disconnect (this.tab_changed);
|
||||
}
|
||||
|
||||
void tab_added (Midori.Browser browser, Midori.View view) {
|
||||
|
@ -505,6 +530,11 @@ namespace HistoryList {
|
|||
list.remove (view);
|
||||
list_new.remove (view);
|
||||
|
||||
Midori.View? current_view = browser.tab as Midori.View;
|
||||
|
||||
if (current_view != view)
|
||||
return;
|
||||
|
||||
if (this.closing_behavior == TabClosingBehavior.LAST || this.closing_behavior == TabClosingBehavior.NEW) {
|
||||
browser.set_data<Midori.View?> ("history-list-last-change", null);
|
||||
|
||||
|
@ -520,21 +550,18 @@ namespace HistoryList {
|
|||
}
|
||||
}
|
||||
|
||||
void tab_changed (GLib.Object window, GLib.ParamSpec pspec) {
|
||||
void tab_changed (Midori.View? old_view, Midori.View? new_view) {
|
||||
if(this.ignoreNextChange) {
|
||||
this.ignoreNextChange = false;
|
||||
} else {
|
||||
Midori.Browser browser = window as Midori.Browser;
|
||||
Midori.View view = null;
|
||||
Midori.View last_view = null;
|
||||
browser.get ("tab", ref view);
|
||||
|
||||
last_view = browser.get_data<Midori.View?> ("history-list-last-change");
|
||||
Midori.Browser? browser = Midori.Browser.get_for_widget (new_view);
|
||||
Midori.View? last_view
|
||||
= browser.get_data<Midori.View?> ("history-list-last-change");
|
||||
|
||||
if (last_view != null) {
|
||||
this.tab_list_resort (browser, last_view);
|
||||
}
|
||||
browser.set_data<Midori.View?> ("history-list-last-change", view);
|
||||
browser.set_data<Midori.View?> ("history-list-last-change", new_view);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,49 +11,207 @@
|
|||
*/
|
||||
|
||||
#include <midori/midori.h>
|
||||
#include <math.h>
|
||||
|
||||
typedef struct _MouseGesture MouseGesture;
|
||||
typedef enum _MouseButton MouseButton;
|
||||
|
||||
enum _MouseButton {
|
||||
enum _MouseButton
|
||||
{
|
||||
MOUSE_BUTTON_LEFT = 1,
|
||||
MOUSE_BUTTON_RIGHT = 3,
|
||||
MOUSE_BUTTON_MIDDLE = 2,
|
||||
MOUSE_BUTTON_UNSET = 0
|
||||
};
|
||||
|
||||
struct MouseGestureNode {
|
||||
/* equivalent to the angle measured anticlockwise from east, divided by 45 or pi/4 */
|
||||
typedef enum
|
||||
{
|
||||
STROKE_EAST = 0,
|
||||
STROKE_NORTHEAST,
|
||||
STROKE_NORTH,
|
||||
STROKE_NORTHWEST,
|
||||
STROKE_WEST,
|
||||
STROKE_SOUTHWEST,
|
||||
STROKE_SOUTH,
|
||||
STROKE_SOUTHEAST,
|
||||
STROKE_NONE,
|
||||
} MouseGestureDirection;
|
||||
|
||||
static const gchar* direction_names[]=
|
||||
{
|
||||
"E",
|
||||
"NE",
|
||||
"N",
|
||||
"NW",
|
||||
"W",
|
||||
"SW",
|
||||
"S",
|
||||
"SE",
|
||||
"NONE",
|
||||
};
|
||||
|
||||
#define N_DIRECTIONS 8
|
||||
|
||||
#define DEVIANCE (15 * M_PI / 180)
|
||||
#define MINLENGTH 30
|
||||
|
||||
char** config_actions = NULL;
|
||||
MouseGestureDirection** config_gestures = NULL;
|
||||
|
||||
const char* default_actions[]=
|
||||
{
|
||||
"TabClose",
|
||||
"Reload",
|
||||
"TabNew",
|
||||
"Stop",
|
||||
"Forward",
|
||||
"Back",
|
||||
NULL
|
||||
};
|
||||
|
||||
const MouseGestureDirection default_gesture_strokes[] =
|
||||
{
|
||||
STROKE_SOUTH, STROKE_EAST, STROKE_NONE,
|
||||
STROKE_SOUTH, STROKE_WEST, STROKE_NONE,
|
||||
STROKE_SOUTH, STROKE_NONE,
|
||||
STROKE_NORTH, STROKE_NONE,
|
||||
STROKE_EAST, STROKE_NONE,
|
||||
STROKE_WEST, STROKE_NONE,
|
||||
STROKE_NONE,
|
||||
};
|
||||
|
||||
const MouseGestureDirection* default_gestures[] =
|
||||
{
|
||||
&default_gesture_strokes[0],
|
||||
&default_gesture_strokes[3],
|
||||
&default_gesture_strokes[6],
|
||||
&default_gesture_strokes[8],
|
||||
&default_gesture_strokes[10],
|
||||
&default_gesture_strokes[12],
|
||||
&default_gesture_strokes[14],
|
||||
};
|
||||
|
||||
static gboolean
|
||||
parse_direction (const char* str, MouseGestureDirection* dir)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < N_DIRECTIONS; i++)
|
||||
{
|
||||
if(!strcmp(str, direction_names[i]))
|
||||
{
|
||||
*dir = i;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
strokes_equal (const MouseGestureDirection* a, const MouseGestureDirection* b)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; a[i] != STROKE_NONE && b[i] != STROKE_NONE; i++)
|
||||
{
|
||||
if(a[i] != b[i])
|
||||
return FALSE;
|
||||
}
|
||||
return a[i] == b[i];
|
||||
}
|
||||
|
||||
struct MouseGestureNode
|
||||
{
|
||||
double x;
|
||||
double y;
|
||||
};
|
||||
|
||||
struct _MouseGesture {
|
||||
static guint
|
||||
dist_sqr (guint x1, guint y1, guint x2, guint y2)
|
||||
{
|
||||
guint xdiff = abs(x1 - x2);
|
||||
guint ydiff = abs(y1 - y2);
|
||||
return xdiff * xdiff + ydiff * ydiff;
|
||||
}
|
||||
|
||||
static float
|
||||
get_angle_for_direction (MouseGestureDirection direction)
|
||||
{
|
||||
return direction * 2 * M_PI / N_DIRECTIONS;
|
||||
}
|
||||
|
||||
static MouseGestureDirection
|
||||
nearest_direction_for_angle (float angle)
|
||||
{
|
||||
/* move halfway to the next direction so we can floor to round */
|
||||
angle += M_PI / N_DIRECTIONS;
|
||||
|
||||
/* ensure we stay within [0, 2pi) */
|
||||
if (angle >= 2 * M_PI)
|
||||
angle -= 2 * M_PI;
|
||||
|
||||
return (MouseGestureDirection)((angle * N_DIRECTIONS) / (2* M_PI));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
vector_follows_direction (float angle, float distance, MouseGestureDirection direction)
|
||||
{
|
||||
if (direction == STROKE_NONE)
|
||||
return distance < MINLENGTH / 2;
|
||||
|
||||
float dir_angle = get_angle_for_direction (direction);
|
||||
if (fabsf(angle - dir_angle) < DEVIANCE || fabsf(angle - dir_angle + 2 * M_PI) < DEVIANCE)
|
||||
return TRUE;
|
||||
|
||||
if(distance < MINLENGTH / 2)
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* returns the angle in the range [0, 2pi) (anticlockwise from east) from point 1 to 2 */
|
||||
static float
|
||||
get_angle_between_points (guint x1, guint y1, guint x2, guint y2)
|
||||
{
|
||||
float distance = sqrtf (dist_sqr (x1, y1, x2, y2));
|
||||
|
||||
/* compute the angle of the vector from a to b */
|
||||
float cval=((signed int)x2 - (signed int)x1) / distance;
|
||||
float angle = acosf (cval);
|
||||
if(y2 > y1)
|
||||
angle = 2 * M_PI - angle;
|
||||
|
||||
return angle;
|
||||
}
|
||||
|
||||
#define N_NODES 8
|
||||
|
||||
struct _MouseGesture
|
||||
{
|
||||
MouseButton button;
|
||||
struct MouseGestureNode start;
|
||||
struct MouseGestureNode middle;
|
||||
struct MouseGestureNode end;
|
||||
MouseGestureDirection strokes[N_NODES + 1];
|
||||
struct MouseGestureNode locations[N_NODES];
|
||||
struct MouseGestureNode last_pos;
|
||||
float last_distance;
|
||||
/* the index of the location to be filled next */
|
||||
guint count;
|
||||
MouseButton last;
|
||||
};
|
||||
|
||||
#define DEVIANCE 20
|
||||
#define MINLENGTH 50
|
||||
|
||||
MouseGesture *gesture = NULL;
|
||||
|
||||
void mouse_gesture_clear (MouseGesture *g)
|
||||
static 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;
|
||||
memset(g->locations, 0, sizeof(g->locations));
|
||||
g->strokes[0] = STROKE_NONE;
|
||||
g->count = 0;
|
||||
g->last_distance = 0;
|
||||
g->last = MOUSE_BUTTON_UNSET;
|
||||
}
|
||||
|
||||
MouseGesture* mouse_gesture_new (void)
|
||||
{
|
||||
MouseGesture* g = g_new (MouseGesture, 1);
|
||||
MouseGesture* g = g_slice_new (MouseGesture);
|
||||
mouse_gesture_clear (g);
|
||||
|
||||
return g;
|
||||
|
@ -68,10 +226,11 @@ mouse_gestures_button_press_event_cb (GtkWidget* web_view,
|
|||
{
|
||||
/* If the gesture was previously cleaned,
|
||||
start a new gesture and coordinates. */
|
||||
if (gesture->last == MOUSE_BUTTON_UNSET)
|
||||
if (gesture->count == MOUSE_BUTTON_UNSET)
|
||||
{
|
||||
gesture->start.x = event->button.x;
|
||||
gesture->start.y = event->button.y;
|
||||
gesture->locations[gesture->count].x = event->button.x;
|
||||
gesture->locations[gesture->count].y = event->button.y;
|
||||
gesture->last_pos = gesture->locations[gesture->count];
|
||||
gesture->last = event->button.button;
|
||||
}
|
||||
return TRUE;
|
||||
|
@ -85,27 +244,58 @@ mouse_gestures_motion_notify_event_cb (GtkWidget* web_view,
|
|||
GdkEvent* event,
|
||||
MidoriBrowser* browser)
|
||||
{
|
||||
/* wait until a button has been pressed */
|
||||
if (gesture->last != MOUSE_BUTTON_UNSET)
|
||||
{
|
||||
guint x, y;
|
||||
guint x, y, oldx, oldy;
|
||||
float angle, distance;
|
||||
MouseGestureDirection old_direction, new_direction;
|
||||
|
||||
x = event->motion.x;
|
||||
y = event->motion.y;
|
||||
oldx = gesture->locations[gesture->count].x;
|
||||
oldy = gesture->locations[gesture->count].y;
|
||||
|
||||
if ((gesture->start.x - x < DEVIANCE && gesture->start.x - x > -DEVIANCE) ||
|
||||
(gesture->start.y - y < DEVIANCE && gesture->start.y - y > -DEVIANCE))
|
||||
old_direction = gesture->strokes[gesture->count];
|
||||
|
||||
angle = get_angle_between_points (oldx, oldy, x, y);
|
||||
distance = sqrtf (dist_sqr (oldx, oldy, x, y));
|
||||
|
||||
/* wait until minimum distance has been reached to set an initial direction. */
|
||||
if (old_direction == STROKE_NONE)
|
||||
{
|
||||
gesture->middle.x = x;
|
||||
gesture->middle.y = y;
|
||||
return TRUE;
|
||||
if (distance >= MINLENGTH)
|
||||
{
|
||||
gesture->strokes[gesture->count] = nearest_direction_for_angle (angle);
|
||||
if(midori_debug ("adblock:match"))
|
||||
g_debug ("detected %s\n", direction_names[gesture->strokes[gesture->count]]);
|
||||
}
|
||||
}
|
||||
else if ((gesture->middle.x - x < DEVIANCE && gesture->middle.x - x > -DEVIANCE) ||
|
||||
(gesture->middle.y - y < DEVIANCE && gesture->middle.y - y > -DEVIANCE))
|
||||
else if (!vector_follows_direction (angle, distance, old_direction)
|
||||
|| distance < gesture->last_distance)
|
||||
{
|
||||
gesture->end.x = x;
|
||||
gesture->end.y = y;
|
||||
return TRUE;
|
||||
/* if path curves or we've reversed our movement, try to detect a new direction */
|
||||
angle = get_angle_between_points (gesture->last_pos.x, gesture->last_pos.y, x, y);
|
||||
new_direction = nearest_direction_for_angle (angle);
|
||||
|
||||
if (new_direction != old_direction && gesture->count + 1 < N_NODES)
|
||||
{
|
||||
/* record this node and return to an indeterminate direction */
|
||||
gesture->count++;
|
||||
gesture->strokes[gesture->count] = STROKE_NONE;
|
||||
gesture->locations[gesture->count].x = x;
|
||||
gesture->locations[gesture->count].y = y;
|
||||
gesture->last_distance = 0;
|
||||
}
|
||||
}
|
||||
else if(distance > gesture->last_distance)
|
||||
{
|
||||
/* if following the same direction, store the progress along it for later divergence checks */
|
||||
gesture->last_pos.x = x;
|
||||
gesture->last_pos.y = y;
|
||||
gesture->last_distance = distance;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
|
@ -125,68 +315,30 @@ mouse_gestures_button_release_event_cb (GtkWidget* web_view,
|
|||
GdkEventButton* event,
|
||||
MidoriView* view)
|
||||
{
|
||||
/* All mouse gestures will use this mouse button */
|
||||
if (gesture->last == gesture->button)
|
||||
int i;
|
||||
|
||||
if (gesture->strokes[gesture->count] != STROKE_NONE)
|
||||
{
|
||||
/* 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 */
|
||||
return mouse_gestures_activate_action (view, "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 */
|
||||
return mouse_gestures_activate_action (view, "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 */
|
||||
return mouse_gestures_activate_action (view, "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 */
|
||||
return mouse_gestures_activate_action (view, "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 */
|
||||
return mouse_gestures_activate_action (view, "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 */
|
||||
return mouse_gestures_activate_action (view, "Back");
|
||||
}
|
||||
}
|
||||
mouse_gesture_clear (gesture);
|
||||
gesture->count++;
|
||||
gesture->strokes[gesture->count] = STROKE_NONE;
|
||||
}
|
||||
|
||||
const MouseGestureDirection** gestures = config_gestures ?
|
||||
(const MouseGestureDirection**)config_gestures :
|
||||
default_gestures;
|
||||
const gchar** actions = config_actions ? (const char**)config_actions : default_actions;
|
||||
|
||||
for(i = 0; gestures[i][0] != STROKE_NONE; i++)
|
||||
{
|
||||
if(strokes_equal (gesture->strokes, gestures[i]))
|
||||
{
|
||||
mouse_gesture_clear (gesture);
|
||||
return mouse_gestures_activate_action (view, actions[i]);
|
||||
}
|
||||
}
|
||||
|
||||
mouse_gesture_clear (gesture);
|
||||
|
||||
if (MIDORI_EVENT_CONTEXT_MENU (event))
|
||||
{
|
||||
GtkWidget* menu = gtk_menu_new ();
|
||||
|
@ -199,6 +351,62 @@ mouse_gestures_button_release_event_cb (GtkWidget* web_view,
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
mouse_gestures_load_config (MidoriExtension* extension)
|
||||
{
|
||||
int i;
|
||||
gchar* config_file;
|
||||
gsize n_keys;
|
||||
gchar** keys;
|
||||
GKeyFile* keyfile;
|
||||
|
||||
config_file = g_build_filename (midori_extension_get_config_dir (extension),
|
||||
"gestures", NULL);
|
||||
keyfile = g_key_file_new ();
|
||||
g_key_file_load_from_file (keyfile, config_file, G_KEY_FILE_NONE, NULL);
|
||||
g_free (config_file);
|
||||
|
||||
if (!keyfile)
|
||||
return;
|
||||
|
||||
keys = g_key_file_get_keys (keyfile, "gestures", &n_keys, NULL);
|
||||
if (!keys)
|
||||
return;
|
||||
|
||||
if(config_gestures)
|
||||
{
|
||||
g_strfreev ((gchar**)config_gestures);
|
||||
g_strfreev (config_actions);
|
||||
}
|
||||
config_gestures = g_malloc ((n_keys + 1) * sizeof (MouseGestureDirection*));
|
||||
config_actions = g_malloc (n_keys * sizeof (gchar*));
|
||||
|
||||
for(i = 0; keys[i]; i++)
|
||||
{
|
||||
gsize n_strokes;
|
||||
int j;
|
||||
gchar** stroke_strings = g_key_file_get_string_list (keyfile, "gestures", keys[i], &n_strokes,
|
||||
NULL);
|
||||
|
||||
config_gestures[i] = g_malloc ((n_strokes + 1) * sizeof (MouseGestureDirection));
|
||||
|
||||
for (j = 0; j < n_strokes; j++)
|
||||
{
|
||||
if (!parse_direction (stroke_strings[j], &config_gestures[i][j]))
|
||||
g_warning ("mouse-gestures: failed to parse direction \"%s\"\n", stroke_strings[j]);
|
||||
}
|
||||
config_gestures[i][j] = STROKE_NONE;
|
||||
|
||||
config_actions[i] = keys[i];
|
||||
g_strfreev (stroke_strings);
|
||||
}
|
||||
config_gestures[i] = g_malloc (sizeof (MouseGestureDirection));
|
||||
config_gestures[i][0] = STROKE_NONE;
|
||||
|
||||
g_free (keys);
|
||||
g_key_file_free (keyfile);
|
||||
}
|
||||
|
||||
static void
|
||||
mouse_gestures_add_tab_cb (MidoriBrowser* browser,
|
||||
MidoriView* view,
|
||||
|
@ -220,21 +428,15 @@ 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);
|
||||
GList* tabs = midori_browser_get_tabs (browser);
|
||||
for (; tabs; tabs = g_list_next (tabs))
|
||||
mouse_gestures_add_tab_cb (browser, tabs->data, extension);
|
||||
g_list_free (tabs);
|
||||
g_signal_connect (browser, "add-tab",
|
||||
G_CALLBACK (mouse_gestures_add_tab_cb), extension);
|
||||
g_signal_connect (extension, "deactivate",
|
||||
|
@ -269,10 +471,19 @@ mouse_gestures_deactivate_cb (MidoriExtension* extension,
|
|||
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);
|
||||
GList* tabs = midori_browser_get_tabs (browser);
|
||||
for (; tabs; tabs = g_list_next (tabs))
|
||||
mouse_gestures_deactivate_tabs (tabs->data, browser);
|
||||
g_list_free (tabs);
|
||||
g_slice_free (MouseGesture, gesture);
|
||||
if(config_gestures)
|
||||
{
|
||||
g_strfreev ((gchar**)config_gestures);
|
||||
config_gestures = NULL;
|
||||
g_strfreev (config_actions);
|
||||
config_actions = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -284,6 +495,7 @@ mouse_gestures_activate_cb (MidoriExtension* extension,
|
|||
|
||||
gesture = mouse_gesture_new ();
|
||||
gesture->button = midori_extension_get_integer (extension, "button");
|
||||
mouse_gestures_load_config (extension);
|
||||
|
||||
browsers = katze_object_get_object (app, "browsers");
|
||||
KATZE_ARRAY_FOREACH_ITEM (browser, browsers)
|
||||
|
@ -300,9 +512,10 @@ extension_init (void)
|
|||
MidoriExtension* extension = g_object_new (MIDORI_TYPE_EXTENSION,
|
||||
"name", _("Mouse Gestures"),
|
||||
"description", _("Control Midori by moving the mouse"),
|
||||
"version", "0.1" MIDORI_VERSION_SUFFIX,
|
||||
"version", "0.2" MIDORI_VERSION_SUFFIX,
|
||||
"authors", "Matthias Kruk <mkruk@matthiaskruk.de>", NULL);
|
||||
midori_extension_install_integer (extension, "button", MOUSE_BUTTON_RIGHT);
|
||||
midori_extension_install_integer (extension, "actions", MOUSE_BUTTON_RIGHT);
|
||||
|
||||
g_signal_connect (extension, "activate",
|
||||
G_CALLBACK (mouse_gestures_activate_cb), NULL);
|
||||
|
|
77
extensions/nsplugin-manager.vala
Normal file
77
extensions/nsplugin-manager.vala
Normal file
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
Copyright (C) 2012 André Stösel <andre@stoesel.de>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
See the file COPYING for the full license text.
|
||||
*/
|
||||
|
||||
#if HAVE_WEBKIT_1_3_8
|
||||
namespace NSPlugins {
|
||||
private int active_plugins = 0;
|
||||
|
||||
private class Extension : Midori.Extension {
|
||||
protected WebKit.WebPlugin plugin;
|
||||
|
||||
void activated (Midori.App app) {
|
||||
active_plugins += 1;
|
||||
this.plugin.set_enabled (true);
|
||||
app.settings.enable_plugins = active_plugins > 0;
|
||||
}
|
||||
|
||||
void deactivated () {
|
||||
Midori.App app = this.get_app ();
|
||||
active_plugins -= 1;
|
||||
this.plugin.set_enabled (false);
|
||||
app.settings.enable_plugins = active_plugins > 0;
|
||||
}
|
||||
|
||||
internal Extension (WebKit.WebPlugin plugin) {
|
||||
string desc = plugin.get_description ();
|
||||
try {
|
||||
var regex = new Regex ("<a.+href.+>(.+)</a>");
|
||||
desc = regex.replace (desc, -1, 0, "<u>\\1</u>");
|
||||
desc = desc.replace ("<br>", "\n");
|
||||
}
|
||||
catch (Error error) { }
|
||||
GLib.Object (stock_id: Midori.Stock.PLUGINS,
|
||||
name: plugin.get_name (),
|
||||
description: desc,
|
||||
use_markup: true,
|
||||
key: GLib.Path.get_basename (plugin.get_path ()),
|
||||
version: "(%s)".printf ("Netscape plugins"),
|
||||
authors: "");
|
||||
|
||||
this.plugin = plugin;
|
||||
this.plugin.set_enabled (false);
|
||||
|
||||
this.activate.connect (activated);
|
||||
this.deactivate.connect (deactivated);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
public Katze.Array? extension_init () {
|
||||
#if HAVE_WEBKIT_1_3_8
|
||||
if (!Midori.WebSettings.has_plugin_support ())
|
||||
return null;
|
||||
|
||||
var extensions = new Katze.Array( typeof (Midori.Extension));
|
||||
WebKit.WebPluginDatabase pdb = WebKit.get_web_plugin_database ();
|
||||
SList<WebKit.WebPlugin> plugins = pdb.get_plugins ();
|
||||
|
||||
foreach (WebKit.WebPlugin plugin in plugins) {
|
||||
if (Midori.WebSettings.skip_plugin (plugin.get_path ()))
|
||||
continue;
|
||||
extensions.add_item (new NSPlugins.Extension (plugin));
|
||||
}
|
||||
return extensions;
|
||||
#else
|
||||
return null;
|
||||
#endif
|
||||
}
|
||||
|
|
@ -137,14 +137,6 @@ shortcuts_hotkey_for_action (GtkAction* action,
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
shortcuts_preferences_response_cb (GtkWidget* dialog,
|
||||
gint response,
|
||||
gpointer data)
|
||||
{
|
||||
gtk_widget_destroy (dialog);
|
||||
}
|
||||
|
||||
static GtkWidget*
|
||||
shortcuts_get_preferences_dialog (MidoriExtension* extension)
|
||||
{
|
||||
|
@ -180,13 +172,11 @@ shortcuts_get_preferences_dialog (MidoriExtension* extension)
|
|||
GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
|
||||
#endif
|
||||
NULL);
|
||||
g_signal_connect (dialog, "destroy",
|
||||
G_CALLBACK (gtk_widget_destroyed), &dialog);
|
||||
gtk_window_set_icon_name (GTK_WINDOW (dialog), GTK_STOCK_PROPERTIES);
|
||||
sokoke_widget_get_text_size (dialog, "M", &width, &height);
|
||||
gtk_window_set_default_size (GTK_WINDOW (dialog), width * 52, height * 24);
|
||||
g_signal_connect (dialog, "response",
|
||||
G_CALLBACK (shortcuts_preferences_response_cb), NULL);
|
||||
g_signal_connect_swapped (dialog, "response",
|
||||
G_CALLBACK (gtk_widget_destroy), dialog);
|
||||
|
||||
dialog_vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
|
||||
if ((xfce_heading = sokoke_xfce_header_new (
|
||||
|
@ -282,7 +272,7 @@ shortcuts_browser_populate_tool_menu_cb (MidoriBrowser* browser,
|
|||
{
|
||||
GtkWidget* menuitem;
|
||||
|
||||
menuitem = gtk_menu_item_new_with_mnemonic (_("Customize Sh_ortcuts..."));
|
||||
menuitem = gtk_menu_item_new_with_mnemonic (_("Customize Sh_ortcuts…"));
|
||||
g_signal_connect (menuitem, "activate",
|
||||
G_CALLBACK (shortcuts_menu_configure_shortcuts_activate_cb), extension);
|
||||
gtk_widget_show (menuitem);
|
||||
|
|
|
@ -43,23 +43,26 @@ clock_set_timeout (MidoriBrowser* browser,
|
|||
static gboolean
|
||||
clock_set_current_time (MidoriBrowser* browser)
|
||||
{
|
||||
MidoriExtension* extension;
|
||||
GtkWidget* label;
|
||||
const gchar* format;
|
||||
struct tm *tm;
|
||||
time_t rawtime;
|
||||
char datestring[60];
|
||||
guint interval;
|
||||
MidoriExtension* extension = g_object_get_data (G_OBJECT (browser), "clock-extension");
|
||||
GtkWidget* label = g_object_get_data (G_OBJECT (browser), "clock-label");
|
||||
const gchar* format = midori_extension_get_string (extension, "format");
|
||||
|
||||
extension = g_object_get_data (G_OBJECT (browser), "clock-extension");
|
||||
label = g_object_get_data (G_OBJECT (browser), "clock-label");
|
||||
format = midori_extension_get_string (extension, "format");
|
||||
|
||||
rawtime = time (NULL);
|
||||
tm = localtime (&rawtime);
|
||||
|
||||
strftime (datestring, 60, format, tm);
|
||||
gtk_label_set_label (GTK_LABEL (label), datestring);
|
||||
#if GLIB_CHECK_VERSION (2, 26, 0)
|
||||
GDateTime* date = g_date_time_new_now_local ();
|
||||
gint seconds = g_date_time_get_seconds (date);
|
||||
gchar* pretty = g_date_time_format (date, format);
|
||||
gtk_label_set_label (GTK_LABEL (label), pretty);
|
||||
g_free (pretty);
|
||||
g_date_time_unref (date);
|
||||
#else
|
||||
time_t rawtime = time (NULL);
|
||||
struct tm *tm = localtime (&rawtime);
|
||||
gint seconds = tm->tm_sec;
|
||||
char date_fmt[512];
|
||||
strftime (date_fmt, sizeof (date_fmt), format, tm);
|
||||
gtk_label_set_label (GTK_LABEL (label), date_fmt);
|
||||
#endif
|
||||
|
||||
if (g_strstr_len (format, -1, "%c")
|
||||
|| g_strstr_len (format, -1, "%N")
|
||||
|
@ -71,7 +74,7 @@ clock_set_current_time (MidoriBrowser* browser)
|
|||
interval = 1;
|
||||
else
|
||||
/* FIXME: Occasionally there are more than 60 seconds in a minute. */
|
||||
interval = MAX (60 - tm->tm_sec, 1);
|
||||
interval = MAX (60 - seconds, 1);
|
||||
|
||||
clock_set_timeout (browser, interval);
|
||||
|
||||
|
|
|
@ -66,11 +66,14 @@ statusbar_features_browser_notify_tab_cb (MidoriBrowser* browser,
|
|||
GtkWidget* combobox)
|
||||
{
|
||||
MidoriView* view = MIDORI_VIEW (midori_browser_get_current_tab (browser));
|
||||
gchar* zoom_level_text = g_strdup_printf ("%d%%",
|
||||
(gint)(midori_view_get_zoom_level (view) * 100));
|
||||
gtk_entry_set_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (combobox))),
|
||||
zoom_level_text);
|
||||
g_free (zoom_level_text);
|
||||
gchar* text;
|
||||
|
||||
if (view == NULL)
|
||||
return;
|
||||
|
||||
text = g_strdup_printf ("%d%%", (gint)(midori_view_get_zoom_level (view) * 100));
|
||||
gtk_entry_set_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (combobox))), text);
|
||||
g_free (text);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -104,6 +107,81 @@ statusbar_features_zoom_level_changed_cb (GtkWidget* combobox,
|
|||
midori_view_set_zoom_level (view, zoom_level / 100.0);
|
||||
}
|
||||
|
||||
GtkWidget*
|
||||
statusbar_features_property_proxy (MidoriWebSettings* settings,
|
||||
const gchar* property,
|
||||
GtkWidget* toolbar)
|
||||
{
|
||||
const gchar* kind = NULL;
|
||||
GtkWidget* button;
|
||||
GtkWidget* image;
|
||||
if (!strcmp (property, "auto-load-images")
|
||||
|| !strcmp (property, "enable-javascript")
|
||||
|| !strcmp (property, "enable-plugins"))
|
||||
kind = "toggle";
|
||||
else if (!strcmp (property, "identify-as"))
|
||||
kind = "custom-user-agent";
|
||||
else if (strstr (property, "font") != NULL)
|
||||
kind = "font";
|
||||
else if (!strcmp (property, "zoom-level"))
|
||||
{
|
||||
MidoriBrowser* browser = midori_browser_get_for_widget (toolbar);
|
||||
gint i;
|
||||
button = gtk_combo_box_text_new_with_entry ();
|
||||
gtk_entry_set_width_chars (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (button))), 4);
|
||||
for (i = 0; i < G_N_ELEMENTS (zoom_levels); i++)
|
||||
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (button), zoom_levels[i].label);
|
||||
g_signal_connect (button, "changed",
|
||||
G_CALLBACK (statusbar_features_zoom_level_changed_cb), browser);
|
||||
g_signal_connect (browser, "notify::tab",
|
||||
G_CALLBACK (statusbar_features_browser_notify_tab_cb), button);
|
||||
statusbar_features_browser_notify_tab_cb (browser, NULL, button);
|
||||
return button;
|
||||
}
|
||||
|
||||
button = katze_property_proxy (settings, property, kind);
|
||||
if (GTK_IS_BIN (button))
|
||||
{
|
||||
GtkWidget* label = gtk_bin_get_child (GTK_BIN (button));
|
||||
if (GTK_IS_LABEL (label))
|
||||
gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END);
|
||||
}
|
||||
|
||||
if (!strcmp (property, "auto-load-images"))
|
||||
{
|
||||
g_object_set_data (G_OBJECT (button), "feature-label", _("Images"));
|
||||
image = gtk_image_new_from_stock (STOCK_IMAGE, GTK_ICON_SIZE_MENU);
|
||||
gtk_button_set_image (GTK_BUTTON (button), image);
|
||||
gtk_widget_set_tooltip_text (button, _("Load images automatically"));
|
||||
statusbar_features_toolbar_notify_toolbar_style_cb (toolbar, NULL, button);
|
||||
g_signal_connect (toolbar, "notify::toolbar-style",
|
||||
G_CALLBACK (statusbar_features_toolbar_notify_toolbar_style_cb), button);
|
||||
}
|
||||
if (!strcmp (property, "enable-javascript"))
|
||||
{
|
||||
g_object_set_data (G_OBJECT (button), "feature-label", _("Scripts"));
|
||||
image = gtk_image_new_from_stock (STOCK_SCRIPT, GTK_ICON_SIZE_MENU);
|
||||
gtk_button_set_image (GTK_BUTTON (button), image);
|
||||
gtk_widget_set_tooltip_text (button, _("Enable scripts"));
|
||||
statusbar_features_toolbar_notify_toolbar_style_cb (toolbar, NULL, button);
|
||||
g_signal_connect (toolbar, "notify::toolbar-style",
|
||||
G_CALLBACK (statusbar_features_toolbar_notify_toolbar_style_cb), button);
|
||||
}
|
||||
else if (!strcmp (property, "enable-plugins"))
|
||||
{
|
||||
if (!midori_web_settings_has_plugin_support ())
|
||||
gtk_widget_hide (button);
|
||||
g_object_set_data (G_OBJECT (button), "feature-label", _("Netscape plugins"));
|
||||
image = gtk_image_new_from_stock (MIDORI_STOCK_PLUGINS, GTK_ICON_SIZE_MENU);
|
||||
gtk_button_set_image (GTK_BUTTON (button), image);
|
||||
gtk_widget_set_tooltip_text (button, _("Enable Netscape plugins"));
|
||||
statusbar_features_toolbar_notify_toolbar_style_cb (toolbar, NULL, button);
|
||||
g_signal_connect (toolbar, "notify::toolbar-style",
|
||||
G_CALLBACK (statusbar_features_toolbar_notify_toolbar_style_cb), button);
|
||||
}
|
||||
return button;
|
||||
}
|
||||
|
||||
static void
|
||||
statusbar_features_app_add_browser_cb (MidoriApp* app,
|
||||
MidoriBrowser* browser,
|
||||
|
@ -114,8 +192,8 @@ statusbar_features_app_add_browser_cb (MidoriApp* app,
|
|||
MidoriWebSettings* settings;
|
||||
GtkWidget* toolbar;
|
||||
GtkWidget* button;
|
||||
GtkWidget* image;
|
||||
gsize i;
|
||||
gchar** filters;
|
||||
|
||||
/* FIXME: Monitor each view and modify its settings individually
|
||||
instead of merely replicating the global preferences. */
|
||||
|
@ -124,48 +202,37 @@ statusbar_features_app_add_browser_cb (MidoriApp* app,
|
|||
bbox = gtk_hbox_new (FALSE, 0);
|
||||
settings = midori_browser_get_settings (browser);
|
||||
toolbar = katze_object_get_object (browser, "navigationbar");
|
||||
button = katze_property_proxy (settings, "auto-load-images", "toggle");
|
||||
g_object_set_data (G_OBJECT (button), "feature-label", _("Images"));
|
||||
image = gtk_image_new_from_stock (STOCK_IMAGE, GTK_ICON_SIZE_MENU);
|
||||
gtk_button_set_image (GTK_BUTTON (button), image);
|
||||
gtk_widget_set_tooltip_text (button, _("Load images automatically"));
|
||||
statusbar_features_toolbar_notify_toolbar_style_cb (toolbar, NULL, button);
|
||||
g_signal_connect (toolbar, "notify::toolbar-style",
|
||||
G_CALLBACK (statusbar_features_toolbar_notify_toolbar_style_cb), button);
|
||||
gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 2);
|
||||
button = katze_property_proxy (settings, "enable-scripts", "toggle");
|
||||
g_object_set_data (G_OBJECT (button), "feature-label", _("Scripts"));
|
||||
image = gtk_image_new_from_stock (STOCK_SCRIPTS, GTK_ICON_SIZE_MENU);
|
||||
gtk_button_set_image (GTK_BUTTON (button), image);
|
||||
gtk_widget_set_tooltip_text (button, _("Enable scripts"));
|
||||
statusbar_features_toolbar_notify_toolbar_style_cb (toolbar, NULL, button);
|
||||
g_signal_connect (toolbar, "notify::toolbar-style",
|
||||
G_CALLBACK (statusbar_features_toolbar_notify_toolbar_style_cb), button);
|
||||
gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 2);
|
||||
button = katze_property_proxy (settings, "enable-plugins", "toggle");
|
||||
g_object_set_data (G_OBJECT (button), "feature-label", _("Netscape plugins"));
|
||||
image = gtk_image_new_from_stock (STOCK_PLUGINS, GTK_ICON_SIZE_MENU);
|
||||
gtk_button_set_image (GTK_BUTTON (button), image);
|
||||
gtk_widget_set_tooltip_text (button, _("Enable Netscape plugins"));
|
||||
statusbar_features_toolbar_notify_toolbar_style_cb (toolbar, NULL, button);
|
||||
g_signal_connect (toolbar, "notify::toolbar-style",
|
||||
G_CALLBACK (statusbar_features_toolbar_notify_toolbar_style_cb), button);
|
||||
gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 2);
|
||||
button = katze_property_proxy (settings, "identify-as", "custom-user-agent");
|
||||
gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 2);
|
||||
button = gtk_combo_box_text_new_with_entry ();
|
||||
gtk_entry_set_width_chars (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (button))), 4);
|
||||
for (i = 0; i < G_N_ELEMENTS (zoom_levels); i++)
|
||||
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (button), zoom_levels[i].label);
|
||||
gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 2);
|
||||
g_signal_connect (button, "changed",
|
||||
G_CALLBACK (statusbar_features_zoom_level_changed_cb), browser);
|
||||
g_signal_connect (browser, "notify::tab",
|
||||
G_CALLBACK (statusbar_features_browser_notify_tab_cb), button);
|
||||
gtk_widget_show_all (bbox);
|
||||
gtk_box_pack_start (GTK_BOX (statusbar), bbox, FALSE, FALSE, 3);
|
||||
g_object_unref (statusbar);
|
||||
|
||||
filters = midori_extension_get_string_list (extension, "items", NULL);
|
||||
if (filters && *filters)
|
||||
{
|
||||
i = 0;
|
||||
while (filters[i] != NULL)
|
||||
{
|
||||
button = statusbar_features_property_proxy (settings, filters[i], toolbar);
|
||||
gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 2);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
button = statusbar_features_property_proxy (settings, "auto-load-images", toolbar);
|
||||
gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 2);
|
||||
button = statusbar_features_property_proxy (settings, "enable-javascript", toolbar);
|
||||
gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 2);
|
||||
button = statusbar_features_property_proxy (settings, "enable-plugins", toolbar);
|
||||
gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 2);
|
||||
button = statusbar_features_property_proxy (settings, "identify-as", toolbar);
|
||||
gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 2);
|
||||
button = statusbar_features_property_proxy (settings, "zoom-level", toolbar);
|
||||
gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 2);
|
||||
}
|
||||
gtk_widget_show_all (bbox);
|
||||
gtk_box_pack_end (GTK_BOX (statusbar), bbox, FALSE, FALSE, 3);
|
||||
g_object_unref (statusbar);
|
||||
g_object_unref (toolbar);
|
||||
|
||||
g_strfreev (filters);
|
||||
g_signal_connect (extension, "deactivate",
|
||||
G_CALLBACK (statusbar_features_deactivate_cb), bbox);
|
||||
}
|
||||
|
@ -194,6 +261,7 @@ extension_init (void)
|
|||
"version", "0.1" MIDORI_VERSION_SUFFIX,
|
||||
"authors", "Christian Dywan <christian@twotoasts.de>",
|
||||
NULL);
|
||||
midori_extension_install_string_list (extension, "items", NULL, G_MAXSIZE);
|
||||
|
||||
g_signal_connect (extension, "activate",
|
||||
G_CALLBACK (statusbar_features_activate_cb), NULL);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright (C) 2008-2009 Christian Dywan <christian@twotoasts.de>
|
||||
Copyright (C) 2008-2013 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
|
||||
|
@ -39,12 +39,11 @@ tab_panel_browser_notify_tab_cb (MidoriBrowser* browser,
|
|||
GtkTreeView* treeview);
|
||||
static void
|
||||
tab_panel_browser_move_tab_cb (MidoriBrowser* browser,
|
||||
GtkNotebook* notebook,
|
||||
GtkWidget* notebook,
|
||||
gint cur_pos,
|
||||
gint new_pos,
|
||||
gpointer user_data);
|
||||
|
||||
|
||||
static void
|
||||
tab_panel_view_notify_minimized_cb (GtkWidget* view,
|
||||
GParamSpec* pspec,
|
||||
|
@ -104,13 +103,19 @@ tab_panel_deactivate_cb (MidoriExtension* extension,
|
|||
GtkWidget* treeview)
|
||||
{
|
||||
MidoriApp* app = midori_extension_get_app (extension);
|
||||
GtkTreeModel* model;
|
||||
MidoriBrowser* browser;
|
||||
|
||||
browser = midori_browser_get_for_widget (treeview);
|
||||
g_object_set (browser, "show-tabs", TRUE, NULL);
|
||||
model = tab_panel_get_model_for_browser (browser);
|
||||
g_object_unref (model);
|
||||
MidoriBrowser* browser = midori_browser_get_for_widget (treeview);
|
||||
GtkTreeModel* model = tab_panel_get_model_for_browser (browser);
|
||||
GList* tabs = midori_browser_get_tabs (browser);
|
||||
for (; tabs; tabs = g_list_next (tabs))
|
||||
{
|
||||
g_signal_handlers_disconnect_by_func (
|
||||
tabs->data, tab_panel_view_notify_minimized_cb, extension);
|
||||
g_signal_handlers_disconnect_by_func (
|
||||
tabs->data, tab_panel_view_notify_icon_cb, extension);
|
||||
g_signal_handlers_disconnect_by_func (
|
||||
tabs->data, tab_panel_view_notify_title_cb, extension);
|
||||
}
|
||||
g_list_free (tabs);
|
||||
|
||||
g_signal_handlers_disconnect_by_func (
|
||||
extension, tab_panel_deactivate_cb, treeview);
|
||||
|
@ -124,16 +129,14 @@ tab_panel_deactivate_cb (MidoriExtension* extension,
|
|||
browser, tab_panel_browser_notify_tab_cb, treeview);
|
||||
g_signal_handlers_disconnect_by_func (
|
||||
browser, tab_panel_settings_notify_cb, model);
|
||||
g_signal_handlers_disconnect_by_func (
|
||||
browser, tab_panel_view_notify_minimized_cb, extension);
|
||||
g_signal_handlers_disconnect_by_func (
|
||||
browser, tab_panel_view_notify_icon_cb, extension);
|
||||
g_signal_handlers_disconnect_by_func (
|
||||
browser, tab_panel_view_notify_title_cb, extension);
|
||||
g_signal_handlers_disconnect_by_func (
|
||||
browser, tab_panel_browser_move_tab_cb, NULL);
|
||||
|
||||
gtk_widget_destroy (treeview);
|
||||
g_object_unref (model);
|
||||
g_object_set_data (G_OBJECT (browser), "tab-panel-ext-model", NULL);
|
||||
g_object_set (browser, "show-tabs", TRUE, NULL);
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -143,7 +146,6 @@ midori_extension_cursor_or_row_changed_cb (GtkTreeView* treeview,
|
|||
/* Nothing to do */
|
||||
}
|
||||
|
||||
#if GTK_CHECK_VERSION (2, 12, 0)
|
||||
static gboolean
|
||||
tab_panel_treeview_query_tooltip_cb (GtkWidget* treeview,
|
||||
gint x,
|
||||
|
@ -171,7 +173,6 @@ tab_panel_treeview_query_tooltip_cb (GtkWidget* treeview,
|
|||
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
midori_extension_row_activated_cb (GtkTreeView* treeview,
|
||||
|
@ -231,12 +232,12 @@ midori_extension_button_release_event_cb (GtkWidget* widget,
|
|||
if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget),
|
||||
event->x, event->y, NULL, &column, NULL, NULL)
|
||||
&& column == gtk_tree_view_get_column (GTK_TREE_VIEW (widget), 1))
|
||||
gtk_widget_destroy (view);
|
||||
midori_browser_close_tab (browser, view);
|
||||
else
|
||||
midori_browser_set_current_tab (browser, view);
|
||||
}
|
||||
else if (event->button == 2)
|
||||
gtk_widget_destroy (view);
|
||||
midori_browser_close_tab (midori_browser_get_for_widget (widget), view);
|
||||
else
|
||||
tab_panel_popup (widget, event, view);
|
||||
|
||||
|
@ -353,13 +354,14 @@ tab_panel_view_notify_icon_cb (GtkWidget* view,
|
|||
{
|
||||
GtkTreeModel* model = tab_panel_get_model_for_browser (browser);
|
||||
GtkTreeIter iter;
|
||||
GtkWidget* label = midori_view_get_proxy_tab_label (MIDORI_VIEW (view));
|
||||
GtkStyle* style = gtk_widget_get_style (label);
|
||||
GdkColor* fg = midori_tab_get_fg_color (MIDORI_TAB (view));
|
||||
GdkColor* bg = midori_tab_get_bg_color (MIDORI_TAB (view));
|
||||
|
||||
if (tab_panel_get_iter_for_view (model, &iter, view))
|
||||
gtk_tree_store_set (GTK_TREE_STORE (model), &iter,
|
||||
3, icon,
|
||||
6, &style->bg[GTK_STATE_NORMAL],
|
||||
7, &style->fg[GTK_STATE_NORMAL],
|
||||
6, bg,
|
||||
7, fg,
|
||||
-1);
|
||||
}
|
||||
}
|
||||
|
@ -382,11 +384,15 @@ tab_panel_view_notify_title_cb (GtkWidget* view,
|
|||
{
|
||||
GtkTreeModel* model = tab_panel_get_model_for_browser (browser);
|
||||
GtkTreeIter iter;
|
||||
GdkColor* fg = midori_tab_get_fg_color (MIDORI_TAB (view));
|
||||
GdkColor* bg = midori_tab_get_bg_color (MIDORI_TAB (view));
|
||||
if (tab_panel_get_iter_for_view (model, &iter, view))
|
||||
{
|
||||
gtk_tree_store_set (GTK_TREE_STORE (model), &iter,
|
||||
4, title,
|
||||
5, midori_view_get_label_ellipsize (MIDORI_VIEW (view)),
|
||||
6, bg,
|
||||
7, fg,
|
||||
-1);
|
||||
}
|
||||
}
|
||||
|
@ -419,8 +425,7 @@ tab_panel_browser_add_tab_cb (MidoriBrowser* browser,
|
|||
GtkWidget* view,
|
||||
MidoriExtension* extension)
|
||||
{
|
||||
GtkWidget* notebook = katze_object_get_object (browser, "notebook");
|
||||
gint page = gtk_notebook_page_num (GTK_NOTEBOOK (notebook), view);
|
||||
gint page = midori_browser_page_num (browser, view);
|
||||
MidoriWebSettings* settings = midori_browser_get_settings (browser);
|
||||
gboolean minimized = katze_object_get_boolean (view, "minimized");
|
||||
GdkPixbuf* icon = midori_view_get_icon (MIDORI_VIEW (view));
|
||||
|
@ -449,10 +454,12 @@ tab_panel_browser_add_tab_cb (MidoriBrowser* browser,
|
|||
GtkTreeIter iter;
|
||||
gboolean buttons = katze_object_get_boolean (settings, "close-buttons-on-tabs");
|
||||
gint ellipsize = midori_view_get_label_ellipsize (MIDORI_VIEW (view));
|
||||
GdkColor* fg = midori_tab_get_fg_color (MIDORI_TAB (view));
|
||||
GdkColor* bg = midori_tab_get_bg_color (MIDORI_TAB (view));
|
||||
|
||||
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, 6, NULL, 7, NULL, -1);
|
||||
3, icon, 4, title, 5, ellipsize, 6, bg, 7, fg, -1);
|
||||
}
|
||||
|
||||
if (!g_signal_handler_find (view, G_SIGNAL_MATCH_FUNC,
|
||||
|
@ -468,16 +475,6 @@ tab_panel_browser_add_tab_cb (MidoriBrowser* browser,
|
|||
g_signal_connect (view, "notify::title",
|
||||
G_CALLBACK (tab_panel_view_notify_title_cb), extension);
|
||||
}
|
||||
|
||||
g_object_unref (notebook);
|
||||
}
|
||||
|
||||
static void
|
||||
tab_panel_browser_foreach_cb (GtkWidget* view,
|
||||
MidoriExtension* extension)
|
||||
{
|
||||
tab_panel_browser_add_tab_cb (midori_browser_get_for_widget (view),
|
||||
view, extension);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -537,11 +534,9 @@ tab_panel_app_add_browser_cb (MidoriApp* app,
|
|||
treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
|
||||
gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
|
||||
gtk_tree_view_set_show_expanders (GTK_TREE_VIEW (treeview), FALSE);
|
||||
#if GTK_CHECK_VERSION (2, 12, 0)
|
||||
g_signal_connect (treeview, "query-tooltip",
|
||||
G_CALLBACK (tab_panel_treeview_query_tooltip_cb), NULL);
|
||||
gtk_widget_set_has_tooltip (treeview, TRUE);
|
||||
#endif
|
||||
column = gtk_tree_view_column_new ();
|
||||
renderer_pixbuf = gtk_cell_renderer_pixbuf_new ();
|
||||
gtk_tree_view_column_pack_start (column, renderer_pixbuf, FALSE);
|
||||
|
@ -598,8 +593,10 @@ tab_panel_app_add_browser_cb (MidoriApp* app,
|
|||
midori_panel_set_current_page (MIDORI_PANEL (panel), i);
|
||||
g_object_unref (panel);
|
||||
|
||||
midori_browser_foreach (browser,
|
||||
(GtkCallback)tab_panel_browser_foreach_cb, treeview);
|
||||
GList* tabs = midori_browser_get_tabs (browser);
|
||||
for (; tabs; tabs = g_list_next (tabs))
|
||||
tab_panel_browser_add_tab_cb (browser, tabs->data, extension);
|
||||
g_list_free (tabs);
|
||||
|
||||
g_signal_connect_after (browser, "add-tab",
|
||||
G_CALLBACK (tab_panel_browser_add_tab_cb), extension);
|
||||
|
@ -630,7 +627,7 @@ tab_panel_activate_cb (MidoriExtension* extension,
|
|||
|
||||
static void
|
||||
tab_panel_browser_move_tab_cb (MidoriBrowser* browser,
|
||||
GtkNotebook* notebook,
|
||||
GtkWidget* notebook,
|
||||
gint cur_pos,
|
||||
gint new_pos,
|
||||
gpointer user_data)
|
||||
|
@ -639,7 +636,7 @@ tab_panel_browser_move_tab_cb (MidoriBrowser* browser,
|
|||
gint last_page;
|
||||
GtkTreeModel *model;
|
||||
|
||||
last_page = gtk_notebook_get_n_pages (notebook) - 1;
|
||||
last_page = midori_browser_get_n_pages (browser) - 1;
|
||||
model = tab_panel_get_model_for_browser (browser);
|
||||
|
||||
gtk_tree_model_iter_nth_child (model, &cur, NULL, cur_pos);
|
||||
|
|
|
@ -46,8 +46,6 @@ static const GtkTargetEntry tb_editor_dnd_targets[] =
|
|||
};
|
||||
static const gint tb_editor_dnd_targets_len = G_N_ELEMENTS(tb_editor_dnd_targets);
|
||||
|
||||
static void tb_editor_browser_populate_tool_menu_cb(MidoriBrowser *browser, GtkWidget *menu, MidoriExtension *ext);
|
||||
|
||||
static void tb_editor_browser_populate_toolbar_menu_cb(MidoriBrowser *browser, GtkWidget *menu,
|
||||
MidoriExtension *ext);
|
||||
|
||||
|
@ -58,7 +56,6 @@ static void tb_editor_deactivate_cb(MidoriExtension *extension, MidoriBrowser *b
|
|||
{
|
||||
MidoriApp *app = midori_extension_get_app(extension);
|
||||
|
||||
g_signal_handlers_disconnect_by_func(browser, tb_editor_browser_populate_tool_menu_cb, extension);
|
||||
g_signal_handlers_disconnect_by_func(browser, tb_editor_browser_populate_toolbar_menu_cb, extension);
|
||||
g_signal_handlers_disconnect_by_func(extension, tb_editor_deactivate_cb, browser);
|
||||
g_signal_handlers_disconnect_by_func(app, tb_editor_app_add_browser_cb, extension);
|
||||
|
@ -107,7 +104,12 @@ static GSList *tb_editor_array_to_list(const gchar **items)
|
|||
name = items;
|
||||
while (*name != NULL)
|
||||
{
|
||||
#ifdef HAVE_GRANITE
|
||||
/* A "new tab" button is already part of the notebook */
|
||||
if (*name[0] != '\0' && strcmp (*name, "TabNew"))
|
||||
#else
|
||||
if (*name[0] != '\0')
|
||||
#endif
|
||||
list = g_slist_append(list, g_strdup(*name));
|
||||
name++;
|
||||
}
|
||||
|
@ -274,16 +276,15 @@ static void tb_editor_drag_data_rcvd_cb(GtkWidget *widget, GdkDragContext *conte
|
|||
gint x, gint y, GtkSelectionData *data, guint info,
|
||||
guint ltime, TBEditorWidget *tbw)
|
||||
{
|
||||
#if !GTK_CHECK_VERSION(3,0,0) /* TODO */
|
||||
GtkTreeView *tree = GTK_TREE_VIEW(widget);
|
||||
gboolean del = FALSE;
|
||||
|
||||
if (data->length >= 0 && data->format == 8)
|
||||
if (gtk_selection_data_get_length (data) >= 0 && gtk_selection_data_get_format (data) == 8)
|
||||
{
|
||||
gboolean is_sep;
|
||||
gchar *text = NULL;
|
||||
|
||||
text = (gchar*) data->data;
|
||||
text = (gchar*) gtk_selection_data_get_data (data);
|
||||
|
||||
/* We allow re-ordering the Location item but not removing it from the list. */
|
||||
if (g_strcmp0(text, "Location") == 0 && widget != tbw->drag_source)
|
||||
|
@ -332,7 +333,6 @@ static void tb_editor_drag_data_rcvd_cb(GtkWidget *widget, GdkDragContext *conte
|
|||
tbw->drag_source = NULL; /* reset the value just to be sure */
|
||||
tb_editor_free_path(tbw);
|
||||
gtk_drag_finish(context, TRUE, del, ltime);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -394,11 +394,7 @@ static TBEditorWidget *tb_editor_create_dialog(MidoriBrowser *parent)
|
|||
GTK_WINDOW(parent),
|
||||
GTK_DIALOG_DESTROY_WITH_PARENT,
|
||||
GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL);
|
||||
#if !GTK_CHECK_VERSION(3,0,0)
|
||||
vbox = (GTK_DIALOG(dialog))->vbox;
|
||||
#else
|
||||
vbox = GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog)));
|
||||
#endif
|
||||
vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
|
||||
gtk_box_set_spacing(GTK_BOX(vbox), 6);
|
||||
gtk_widget_set_name(dialog, "GeanyDialog");
|
||||
gtk_window_set_default_size(GTK_WINDOW(dialog), -1, 400);
|
||||
|
@ -410,7 +406,7 @@ static TBEditorWidget *tb_editor_create_dialog(MidoriBrowser *parent)
|
|||
G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
|
||||
|
||||
label = gtk_label_new(
|
||||
_("Select items to be displayed on the toolbar. Items can be reodered by drag and drop."));
|
||||
_("Select items to be displayed on the toolbar. Items can be reordered by drag and drop."));
|
||||
gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
|
||||
|
||||
tree_available = gtk_tree_view_new();
|
||||
|
@ -578,17 +574,6 @@ static void tb_editor_menu_configure_toolbar_activate_cb(GtkWidget *menuitem, Mi
|
|||
g_free(tbw);
|
||||
}
|
||||
|
||||
static void tb_editor_browser_populate_tool_menu_cb(MidoriBrowser *browser, GtkWidget *menu, MidoriExtension *ext)
|
||||
{
|
||||
GtkWidget *menuitem;
|
||||
|
||||
menuitem = gtk_menu_item_new_with_mnemonic (_("Customize _Toolbar..."));
|
||||
g_signal_connect (menuitem, "activate",
|
||||
G_CALLBACK (tb_editor_menu_configure_toolbar_activate_cb), browser);
|
||||
gtk_widget_show (menuitem);
|
||||
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
|
||||
}
|
||||
|
||||
static void tb_editor_browser_populate_toolbar_menu_cb(MidoriBrowser *browser, GtkWidget *menu,
|
||||
MidoriExtension *ext)
|
||||
{
|
||||
|
@ -598,7 +583,7 @@ static void tb_editor_browser_populate_toolbar_menu_cb(MidoriBrowser *browser, G
|
|||
separator = gtk_separator_menu_item_new ();
|
||||
gtk_widget_show (separator);
|
||||
gtk_menu_shell_append (GTK_MENU_SHELL (menu), separator);
|
||||
menuitem = gtk_menu_item_new_with_mnemonic (_("_Customize..."));
|
||||
menuitem = gtk_menu_item_new_with_mnemonic (_("_Customize Toolbar…"));
|
||||
g_signal_connect (menuitem, "activate",
|
||||
G_CALLBACK (tb_editor_menu_configure_toolbar_activate_cb), browser);
|
||||
gtk_widget_show (menuitem);
|
||||
|
@ -607,7 +592,6 @@ static void tb_editor_browser_populate_toolbar_menu_cb(MidoriBrowser *browser, G
|
|||
|
||||
static void tb_editor_app_add_browser_cb(MidoriApp *app, MidoriBrowser *browser, MidoriExtension *ext)
|
||||
{
|
||||
g_signal_connect(browser, "populate-tool-menu", G_CALLBACK(tb_editor_browser_populate_tool_menu_cb), ext);
|
||||
g_signal_connect(browser, "populate-toolbar-menu", G_CALLBACK(tb_editor_browser_populate_toolbar_menu_cb), ext);
|
||||
g_signal_connect(ext, "deactivate", G_CALLBACK(tb_editor_deactivate_cb), browser);
|
||||
}
|
||||
|
|
530
extensions/transfers.vala
Normal file
530
extensions/transfers.vala
Normal file
|
@ -0,0 +1,530 @@
|
|||
/*
|
||||
Copyright (C) 2009-2013 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.
|
||||
*/
|
||||
|
||||
namespace Gtk {
|
||||
extern static void widget_size_request (Gtk.Widget widget, out Gtk.Requisition requisition);
|
||||
}
|
||||
|
||||
namespace Sokoke {
|
||||
extern static bool show_uri (Gdk.Screen screen, string uri, uint32 timestamp) throws Error;
|
||||
extern static void widget_get_text_size (Gtk.Widget widget, string sample, out int width, out int height);
|
||||
}
|
||||
|
||||
namespace Transfers {
|
||||
private class Transfer : GLib.Object {
|
||||
internal WebKit.Download download;
|
||||
|
||||
internal signal void changed ();
|
||||
internal signal void remove ();
|
||||
internal signal void removed ();
|
||||
|
||||
internal int action { get {
|
||||
return Midori.Download.get_type (download);
|
||||
} }
|
||||
internal double progress { get {
|
||||
return Midori.Download.get_progress (download);
|
||||
} }
|
||||
#if HAVE_WEBKIT2
|
||||
public bool succeeded { get; protected set; default = false; }
|
||||
public bool finished { get; protected set; default = false; }
|
||||
internal string destination { get {
|
||||
return download.destination;
|
||||
} }
|
||||
#else
|
||||
internal bool succeeded { get {
|
||||
return download.status == WebKit.DownloadStatus.FINISHED;
|
||||
} }
|
||||
internal bool finished { get {
|
||||
return Midori.Download.is_finished (download);
|
||||
} }
|
||||
internal string destination { get {
|
||||
return download.destination_uri;
|
||||
} }
|
||||
#endif
|
||||
|
||||
internal Transfer (WebKit.Download download) {
|
||||
this.download = download;
|
||||
#if HAVE_WEBKIT2
|
||||
download.notify["estimated-progress"].connect (transfer_changed);
|
||||
download.finished.connect (() => {
|
||||
succeeded = finished = true;
|
||||
changed ();
|
||||
});
|
||||
download.failed.connect (() => {
|
||||
succeeded = false;
|
||||
finished = true;
|
||||
changed ();
|
||||
});
|
||||
#else
|
||||
download.notify["status"].connect (transfer_changed);
|
||||
download.notify["progress"].connect (transfer_changed);
|
||||
#endif
|
||||
}
|
||||
|
||||
void transfer_changed (GLib.ParamSpec pspec) {
|
||||
changed ();
|
||||
}
|
||||
}
|
||||
|
||||
static bool pending_transfers (Katze.Array array) {
|
||||
foreach (GLib.Object item in array.get_items ()) {
|
||||
var transfer = item as Transfer;
|
||||
if (!transfer.finished)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private class Sidebar : Gtk.VBox, Midori.Viewable {
|
||||
Gtk.Toolbar? toolbar = null;
|
||||
Gtk.ToolButton clear;
|
||||
Gtk.ListStore store = new Gtk.ListStore (1, typeof (Transfer));
|
||||
Gtk.TreeView treeview;
|
||||
Katze.Array array;
|
||||
|
||||
public unowned string get_stock_id () {
|
||||
return Midori.Stock.TRANSFER;
|
||||
}
|
||||
|
||||
public unowned string get_label () {
|
||||
return _("Transfers");
|
||||
}
|
||||
|
||||
public Gtk.Widget get_toolbar () {
|
||||
if (toolbar == null) {
|
||||
toolbar = new Gtk.Toolbar ();
|
||||
toolbar.set_icon_size (Gtk.IconSize.BUTTON);
|
||||
toolbar.insert (new Gtk.ToolItem (), -1);
|
||||
var separator = new Gtk.SeparatorToolItem ();
|
||||
separator.draw = false;
|
||||
separator.set_expand (true);
|
||||
toolbar.insert (separator, -1);
|
||||
clear = new Gtk.ToolButton.from_stock (Gtk.STOCK_CLEAR);
|
||||
clear.label = _("Clear All");
|
||||
clear.is_important = true;
|
||||
clear.clicked.connect (clear_clicked);
|
||||
clear.sensitive = !array.is_empty ();
|
||||
toolbar.insert (clear, -1);
|
||||
toolbar.show_all ();
|
||||
}
|
||||
return toolbar;
|
||||
}
|
||||
|
||||
void clear_clicked () {
|
||||
foreach (GLib.Object item in array.get_items ()) {
|
||||
var transfer = item as Transfer;
|
||||
if (transfer.finished)
|
||||
transfer.remove ();
|
||||
}
|
||||
}
|
||||
|
||||
public Sidebar (Katze.Array array) {
|
||||
Gtk.TreeViewColumn column;
|
||||
|
||||
treeview = new Gtk.TreeView.with_model (store);
|
||||
treeview.headers_visible = false;
|
||||
|
||||
store.set_sort_column_id (0, Gtk.SortType.ASCENDING);
|
||||
store.set_sort_func (0, tree_sort_func);
|
||||
|
||||
column = new Gtk.TreeViewColumn ();
|
||||
Gtk.CellRendererPixbuf renderer_icon = new Gtk.CellRendererPixbuf ();
|
||||
column.pack_start (renderer_icon, false);
|
||||
column.set_cell_data_func (renderer_icon, on_render_icon);
|
||||
treeview.append_column (column);
|
||||
|
||||
column = new Gtk.TreeViewColumn ();
|
||||
column.set_sizing (Gtk.TreeViewColumnSizing.AUTOSIZE);
|
||||
Gtk.CellRendererProgress renderer_progress = new Gtk.CellRendererProgress ();
|
||||
column.pack_start (renderer_progress, true);
|
||||
column.set_expand (true);
|
||||
column.set_cell_data_func (renderer_progress, on_render_text);
|
||||
treeview.append_column (column);
|
||||
|
||||
column = new Gtk.TreeViewColumn ();
|
||||
Gtk.CellRendererPixbuf renderer_button = new Gtk.CellRendererPixbuf ();
|
||||
column.pack_start (renderer_button, false);
|
||||
column.set_cell_data_func (renderer_button, on_render_button);
|
||||
treeview.append_column (column);
|
||||
|
||||
treeview.row_activated.connect (row_activated);
|
||||
treeview.button_release_event.connect (button_released);
|
||||
treeview.popup_menu.connect (menu_popup);
|
||||
treeview.show ();
|
||||
pack_start (treeview, true, true, 0);
|
||||
|
||||
this.array = array;
|
||||
array.add_item.connect (transfer_added);
|
||||
array.remove_item.connect_after (transfer_removed);
|
||||
foreach (GLib.Object item in array.get_items ())
|
||||
transfer_added (item);
|
||||
}
|
||||
|
||||
void row_activated (Gtk.TreePath path, Gtk.TreeViewColumn column) {
|
||||
Gtk.TreeIter iter;
|
||||
if (store.get_iter (out iter, path)) {
|
||||
Transfer transfer;
|
||||
store.get (iter, 0, out transfer);
|
||||
|
||||
if (Midori.Download.action_clear (transfer.download, treeview))
|
||||
transfer.remove ();
|
||||
}
|
||||
}
|
||||
|
||||
bool button_released (Gdk.EventButton event) {
|
||||
if (event.button == 3)
|
||||
return show_popup_menu (event);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool menu_popup () {
|
||||
return show_popup_menu (null);
|
||||
}
|
||||
|
||||
bool show_popup_menu (Gdk.EventButton? event) {
|
||||
Gtk.TreeIter iter;
|
||||
if (treeview.get_selection ().get_selected (null, out iter)) {
|
||||
Transfer transfer;
|
||||
store.get (iter, 0, out transfer);
|
||||
|
||||
var menu = new Gtk.Menu ();
|
||||
var menuitem = new Gtk.ImageMenuItem.from_stock (Gtk.STOCK_OPEN, null);
|
||||
menuitem.activate.connect (() => {
|
||||
Midori.Download.open (transfer.download, treeview);
|
||||
});
|
||||
menuitem.sensitive = transfer.succeeded;
|
||||
menu.append (menuitem);
|
||||
menuitem = new Gtk.ImageMenuItem.with_mnemonic (_("Open Destination _Folder"));
|
||||
menuitem.image = new Gtk.Image.from_stock (Gtk.STOCK_DIRECTORY, Gtk.IconSize.MENU);
|
||||
menuitem.activate.connect (() => {
|
||||
var folder = GLib.File.new_for_uri (transfer.destination);
|
||||
Sokoke.show_uri (get_screen (), folder.get_parent ().get_uri (), 0);
|
||||
});
|
||||
menu.append (menuitem);
|
||||
menuitem = new Gtk.ImageMenuItem.with_mnemonic (_("Copy Link Loc_ation"));
|
||||
menuitem.activate.connect (() => {
|
||||
string uri = transfer.destination;
|
||||
get_clipboard (Gdk.SELECTION_PRIMARY).set_text (uri, -1);
|
||||
get_clipboard (Gdk.SELECTION_CLIPBOARD).set_text (uri, -1);
|
||||
});
|
||||
menuitem.image = new Gtk.Image.from_stock (Gtk.STOCK_COPY, Gtk.IconSize.MENU);
|
||||
menu.append (menuitem);
|
||||
menu.show_all ();
|
||||
Katze.widget_popup (treeview, menu, null, Katze.MenuPos.CURSOR);
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int tree_sort_func (Gtk.TreeModel model, Gtk.TreeIter a, Gtk.TreeIter b) {
|
||||
Transfer transfer1, transfer2;
|
||||
model.get (a, 0, out transfer1);
|
||||
model.get (b, 0, out transfer2);
|
||||
return (transfer1.finished ? 1 : 0) - (transfer2.finished ? 1 : 0);
|
||||
}
|
||||
|
||||
void transfer_changed () {
|
||||
treeview.queue_draw ();
|
||||
}
|
||||
|
||||
void transfer_added (GLib.Object item) {
|
||||
var transfer = item as Transfer;
|
||||
Gtk.TreeIter iter;
|
||||
store.append (out iter);
|
||||
store.set (iter, 0, transfer);
|
||||
transfer.changed.connect (transfer_changed);
|
||||
clear.sensitive = true;
|
||||
}
|
||||
|
||||
void transfer_removed (GLib.Object item) {
|
||||
var transfer = item as Transfer;
|
||||
transfer.changed.disconnect (transfer_changed);
|
||||
Gtk.TreeIter iter;
|
||||
if (store.iter_children (out iter, null)) {
|
||||
do {
|
||||
Transfer found;
|
||||
store.get (iter, 0, out found);
|
||||
if (transfer == found) {
|
||||
store.remove (iter);
|
||||
break;
|
||||
}
|
||||
} while (store.iter_next (ref iter));
|
||||
}
|
||||
if (array.is_empty ())
|
||||
clear.sensitive = false;
|
||||
}
|
||||
|
||||
void on_render_icon (Gtk.CellLayout column, Gtk.CellRenderer renderer,
|
||||
Gtk.TreeModel model, Gtk.TreeIter iter) {
|
||||
|
||||
Transfer transfer;
|
||||
model.get (iter, 0, out transfer);
|
||||
string content_type = Midori.Download.get_content_type (transfer.download, null);
|
||||
var icon = GLib.ContentType.get_icon (content_type) as ThemedIcon;
|
||||
icon.append_name ("text-html");
|
||||
renderer.set ("gicon", icon,
|
||||
"stock-size", Gtk.IconSize.DND,
|
||||
"xpad", 1, "ypad", 12);
|
||||
}
|
||||
|
||||
void on_render_text (Gtk.CellLayout column, Gtk.CellRenderer renderer,
|
||||
Gtk.TreeModel model, Gtk.TreeIter iter) {
|
||||
|
||||
Transfer transfer;
|
||||
model.get (iter, 0, out transfer);
|
||||
string tooltip = Midori.Download.get_tooltip (transfer.download);
|
||||
renderer.set ("text", tooltip,
|
||||
"value", (int)(transfer.progress * 100));
|
||||
}
|
||||
|
||||
void on_render_button (Gtk.CellLayout column, Gtk.CellRenderer renderer,
|
||||
Gtk.TreeModel model, Gtk.TreeIter iter) {
|
||||
|
||||
Transfer transfer;
|
||||
model.get (iter, 0, out transfer);
|
||||
string stock_id = Midori.Download.action_stock_id (transfer.download);
|
||||
renderer.set ("stock-id", stock_id,
|
||||
"stock-size", Gtk.IconSize.MENU);
|
||||
}
|
||||
}
|
||||
|
||||
private class TransferButton : Gtk.ToolItem {
|
||||
Transfer transfer;
|
||||
Gtk.ProgressBar progress;
|
||||
Gtk.Image icon;
|
||||
Gtk.Button button;
|
||||
|
||||
public TransferButton (Transfer transfer) {
|
||||
this.transfer = transfer;
|
||||
|
||||
var box = new Gtk.HBox (false, 0);
|
||||
progress = new Gtk.ProgressBar ();
|
||||
#if HAVE_GTK3
|
||||
progress.show_text = true;
|
||||
#endif
|
||||
progress.ellipsize = Pango.EllipsizeMode.MIDDLE;
|
||||
string filename = Path.get_basename (transfer.destination);
|
||||
progress.text = filename;
|
||||
int width;
|
||||
Sokoke.widget_get_text_size (progress, "M", out width, null);
|
||||
progress.set_size_request (width * 10, 1);
|
||||
box.pack_start (progress, false, false, 0);
|
||||
|
||||
icon = new Gtk.Image ();
|
||||
button = new Gtk.Button ();
|
||||
button.relief = Gtk.ReliefStyle.NONE;
|
||||
button.focus_on_click = false;
|
||||
button.clicked.connect (button_clicked);
|
||||
button.add (icon);
|
||||
box.pack_start (button, false, false, 0);
|
||||
|
||||
add (box);
|
||||
show_all ();
|
||||
|
||||
transfer.changed.connect (transfer_changed);
|
||||
transfer_changed ();
|
||||
transfer.removed.connect (transfer_removed);
|
||||
}
|
||||
|
||||
void button_clicked () {
|
||||
if (Midori.Download.action_clear (transfer.download, button))
|
||||
transfer.remove ();
|
||||
}
|
||||
|
||||
void transfer_changed () {
|
||||
progress.fraction = Midori.Download.get_progress (transfer.download);
|
||||
progress.tooltip_text = Midori.Download.get_tooltip (transfer.download);
|
||||
string stock_id = Midori.Download.action_stock_id (transfer.download);
|
||||
icon.set_from_stock (stock_id, Gtk.IconSize.MENU);
|
||||
}
|
||||
|
||||
void transfer_removed () {
|
||||
destroy ();
|
||||
}
|
||||
}
|
||||
|
||||
private class Toolbar : Gtk.Toolbar {
|
||||
Katze.Array array;
|
||||
Gtk.ToolButton clear;
|
||||
|
||||
void clear_clicked () {
|
||||
foreach (GLib.Object item in array.get_items ()) {
|
||||
var transfer = item as Transfer;
|
||||
if (transfer.finished)
|
||||
array.remove_item (item);
|
||||
}
|
||||
}
|
||||
|
||||
public Toolbar (Katze.Array array) {
|
||||
set_icon_size (Gtk.IconSize.BUTTON);
|
||||
set_style (Gtk.ToolbarStyle.BOTH_HORIZ);
|
||||
show_arrow = false;
|
||||
|
||||
clear = new Gtk.ToolButton.from_stock (Gtk.STOCK_CLEAR);
|
||||
clear.label = _("Clear All");
|
||||
clear.is_important = true;
|
||||
clear.clicked.connect (clear_clicked);
|
||||
clear.sensitive = !array.is_empty ();
|
||||
insert (clear, -1);
|
||||
clear.show ();
|
||||
clear.sensitive = false;
|
||||
|
||||
this.array = array;
|
||||
array.add_item.connect (transfer_added);
|
||||
array.remove_item.connect_after (transfer_removed);
|
||||
foreach (GLib.Object item in array.get_items ())
|
||||
transfer_added (item);
|
||||
}
|
||||
|
||||
void transfer_added (GLib.Object item) {
|
||||
var transfer = item as Transfer;
|
||||
/* Newest item on the left */
|
||||
insert (new TransferButton (transfer), 0);
|
||||
clear.sensitive = true;
|
||||
show ();
|
||||
|
||||
Gtk.Requisition req;
|
||||
Gtk.widget_size_request (parent, out req);
|
||||
int reqwidth = req.width;
|
||||
int winwidth;
|
||||
(get_toplevel () as Gtk.Window).get_size (out winwidth, null);
|
||||
if (reqwidth > winwidth)
|
||||
clear_clicked ();
|
||||
}
|
||||
|
||||
void transfer_removed (GLib.Object item) {
|
||||
clear.sensitive = pending_transfers (array);
|
||||
if (array.is_empty ())
|
||||
hide ();
|
||||
}
|
||||
}
|
||||
|
||||
private class Manager : Midori.Extension {
|
||||
internal Katze.Array array;
|
||||
internal GLib.List<Gtk.Widget> widgets;
|
||||
|
||||
void download_added (WebKit.Download download) {
|
||||
var transfer = new Transfer (download);
|
||||
transfer.remove.connect (transfer_remove);
|
||||
transfer.changed.connect (transfer_changed);
|
||||
array.remove_item.connect (transfer_removed);
|
||||
array.add_item (transfer);
|
||||
}
|
||||
|
||||
void transfer_changed (Transfer transfer) {
|
||||
if (transfer.succeeded) {
|
||||
/* FIXME: The following 2 blocks ought to be done in core */
|
||||
if (transfer.action == Midori.DownloadType.OPEN) {
|
||||
if (Midori.Download.action_clear (transfer.download, widgets.nth_data (0)))
|
||||
transfer.remove ();
|
||||
}
|
||||
|
||||
string uri = transfer.destination;
|
||||
string filename = Path.get_basename (uri);
|
||||
var item = new Katze.Item ();
|
||||
item.uri = uri;
|
||||
item.name = filename;
|
||||
Midori.Browser.update_history (item, "download", "create");
|
||||
if (!Midori.Download.has_wrong_checksum (transfer.download))
|
||||
Gtk.RecentManager.get_default ().add_item (uri);
|
||||
|
||||
string msg = _("The file '<b>%s</b>' has been downloaded.").printf (filename);
|
||||
get_app ().send_notification (_("Transfer completed"), msg);
|
||||
}
|
||||
}
|
||||
|
||||
void transfer_remove (Transfer transfer) {
|
||||
array.remove_item (transfer);
|
||||
}
|
||||
|
||||
void transfer_removed (GLib.Object item) {
|
||||
var transfer = item as Transfer;
|
||||
transfer.removed ();
|
||||
}
|
||||
|
||||
#if HAVE_GTK3
|
||||
bool browser_closed (Gtk.Widget widget, Gdk.EventAny event) {
|
||||
#else
|
||||
bool browser_closed (Gtk.Widget widget, Gdk.Event event) {
|
||||
#endif
|
||||
var browser = widget as Midori.Browser;
|
||||
if (pending_transfers (array)) {
|
||||
var dialog = new Gtk.MessageDialog (browser,
|
||||
Gtk.DialogFlags.DESTROY_WITH_PARENT,
|
||||
Gtk.MessageType.WARNING, Gtk.ButtonsType.NONE,
|
||||
_("Some files are being downloaded"));
|
||||
dialog.title = _("Some files are being downloaded");
|
||||
dialog.add_buttons (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
|
||||
_("_Quit Midori"), Gtk.ResponseType.ACCEPT);
|
||||
dialog.format_secondary_text (
|
||||
_("The transfers will be cancelled if Midori quits."));
|
||||
bool cancel = dialog.run () != Gtk.ResponseType.ACCEPT;
|
||||
dialog.destroy ();
|
||||
return cancel;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void browser_added (Midori.Browser browser) {
|
||||
var viewable = new Sidebar (array);
|
||||
viewable.show ();
|
||||
browser.panel.append_page (viewable);
|
||||
widgets.append (viewable);
|
||||
var toolbar = new Toolbar (array);
|
||||
#if HAVE_GTK3
|
||||
browser.statusbar.pack_end (toolbar, false, false);
|
||||
#else
|
||||
browser.statusbar.pack_start (toolbar, false, false);
|
||||
#endif
|
||||
widgets.append (toolbar);
|
||||
// TODO: popover
|
||||
// TODO: progress in dock item
|
||||
browser.add_download.connect (download_added);
|
||||
browser.delete_event.connect (browser_closed);
|
||||
}
|
||||
|
||||
void activated (Midori.App app) {
|
||||
array = new Katze.Array (typeof (Transfer));
|
||||
widgets = new GLib.List<Gtk.Widget> ();
|
||||
foreach (var browser in app.get_browsers ())
|
||||
browser_added (browser);
|
||||
app.add_browser.connect (browser_added);
|
||||
}
|
||||
|
||||
void deactivated () {
|
||||
var app = get_app ();
|
||||
app.add_browser.disconnect (browser_added);
|
||||
foreach (var browser in app.get_browsers ()) {
|
||||
browser.add_download.disconnect (download_added);
|
||||
browser.delete_event.disconnect (browser_closed);
|
||||
}
|
||||
foreach (var widget in widgets)
|
||||
widget.destroy ();
|
||||
array.remove_item.disconnect (transfer_removed);
|
||||
}
|
||||
|
||||
internal Manager () {
|
||||
GLib.Object (name: _("Transfer Manager"),
|
||||
description: _("View downloaded files"),
|
||||
version: "0.1" + Midori.VERSION_SUFFIX,
|
||||
authors: "Christian Dywan <christian@twotoasts.de>");
|
||||
|
||||
this.activate.connect (activated);
|
||||
this.deactivate.connect (deactivated);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Midori.Extension extension_init () {
|
||||
return new Transfers.Manager ();
|
||||
}
|
||||
|
|
@ -28,8 +28,7 @@ web_cache_get_cache_dir (void)
|
|||
{
|
||||
static gchar* cache_dir = NULL;
|
||||
if (!cache_dir)
|
||||
cache_dir = g_build_filename (g_get_user_cache_dir (),
|
||||
PACKAGE_NAME, "web", NULL);
|
||||
cache_dir = g_build_filename (midori_paths_get_cache_dir (), "web", NULL);
|
||||
return cache_dir;
|
||||
}
|
||||
|
||||
|
@ -448,7 +447,7 @@ web_cache_activate_cb (MidoriExtension* extension,
|
|||
static void
|
||||
web_cache_clear_cache_cb (void)
|
||||
{
|
||||
sokoke_remove_path (web_cache_get_cache_dir (), TRUE);
|
||||
midori_paths_remove_path (web_cache_get_cache_dir ());
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -468,7 +467,7 @@ extension_init (void)
|
|||
g_signal_connect (extension, "activate",
|
||||
G_CALLBACK (web_cache_activate_cb), NULL);
|
||||
|
||||
sokoke_register_privacy_item ("web-cache", _("Web Cache"),
|
||||
midori_private_data_register_item ("web-cache", _("Web Cache"),
|
||||
G_CALLBACK (web_cache_clear_cache_cb));
|
||||
|
||||
return extension;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
# WAF build script for midori
|
||||
# This file is licensed under the terms of the expat license, see the file EXPAT.
|
||||
|
||||
import Options
|
||||
import os
|
||||
|
||||
extensions = os.listdir ('extensions')
|
||||
|
@ -12,9 +13,7 @@ for extension in extensions:
|
|||
target = extension
|
||||
source = ''
|
||||
for fila in files:
|
||||
if fila[-2:] == '.c':
|
||||
source += ' ' + extension + os.sep + fila
|
||||
elif 'VALAC' in bld.env and fila[-5:] == '.vala':
|
||||
if fila[-2:] == '.c' or fila[-5:] == '.vala':
|
||||
source += ' ' + extension + os.sep + fila
|
||||
if not source:
|
||||
Utils.pprint ('RED', folder + ': No source files found')
|
||||
|
@ -22,23 +21,36 @@ for extension in extensions:
|
|||
else:
|
||||
if extension[-2:] == '.c':
|
||||
target = extension[:-2]
|
||||
elif 'VALAC' in bld.env and extension[-5:] == '.vala':
|
||||
elif extension[-5:] == '.vala':
|
||||
target = extension[:-5]
|
||||
else:
|
||||
continue
|
||||
source = extension
|
||||
|
||||
# FIXME
|
||||
if bld.env['HAVE_WEBKIT2'] and target in ['external-download-manager', 'nsplugin-manager', 'formhistory', 'adblock', 'cookie-permissions', 'addons', 'cookie-manager']:
|
||||
continue
|
||||
|
||||
obj = bld.new_task_gen ('cc', 'shlib')
|
||||
obj.target = target
|
||||
obj.includes = '..'
|
||||
obj.includes = '.. ../katze ../midori'
|
||||
obj.source = source
|
||||
obj.uselib = 'UNIQUE LIBSOUP GIO GTK SQLITE WEBKIT LIBXML HILDON'
|
||||
obj.vapi_dirs = '../midori'
|
||||
obj.packages = 'glib-2.0 gio-2.0 libsoup-2.4 midori'
|
||||
if bld.env['HAVE_GTK3']:
|
||||
obj.packages += ' gtk+-3.0 webkitgtk-3.0'
|
||||
else:
|
||||
obj.packages += ' gtk+-2.0 webkit-1.0 unique-1.0'
|
||||
obj.uselib = 'UNIQUE LIBSOUP GIO GTK SQLITE WEBKIT LIBXML GRANITE'
|
||||
if 'vala' in source:
|
||||
obj.env.append_value ('CCFLAGS', '-w')
|
||||
obj.vapi_dirs = '../midori ../katze'
|
||||
obj.packages = 'glib-2.0 gio-2.0 libsoup-2.4 sqlite3 midori midori-core katze'
|
||||
if bld.env['HAVE_GTK3']:
|
||||
obj.packages += ' gtk+-3.0'
|
||||
else:
|
||||
obj.packages += ' gtk+-2.0'
|
||||
if bld.env['HAVE_WEBKIT2']:
|
||||
obj.packages += ' webkit2gtk-3.0'
|
||||
else:
|
||||
obj.packages += ' webkitgtk-3.0'
|
||||
if bld.env['HAVE_GRANITE']:
|
||||
obj.packages += ' granite'
|
||||
obj.install_path = '${LIBDIR}/midori'
|
||||
# See LINKFLAGS in wscript: w/ o it we get several "undefined reference" errors
|
||||
if bld.env['platform'] == 'win32':
|
||||
obj.uselib_local = 'midori'
|
||||
|
|
Before Width: | Height: | Size: 832 B After Width: | Height: | Size: 832 B |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
@ -41,4 +41,4 @@ def add_image (bld, category, name):
|
|||
|
||||
add_image (bld, 'categories', 'extension')
|
||||
add_image (bld, 'apps', 'midori')
|
||||
add_image (bld, 'status', 'news-feed')
|
||||
add_image (bld, 'status', 'internet-news-reader')
|
||||
|
|
|
@ -1,6 +1,17 @@
|
|||
/*
|
||||
Copyright (C) 2011-2012 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/gtk3-compat.h"
|
||||
|
||||
#if !GTK_CHECK_VERSION (3, 2, 0) && !defined (HAVE_HILDON_2_2)
|
||||
#if !GTK_CHECK_VERSION (3, 2, 0)
|
||||
static void
|
||||
sokoke_widget_set_pango_font_style (GtkWidget* widget,
|
||||
PangoStyle style)
|
||||
|
@ -27,9 +38,9 @@ sokoke_on_entry_focus_in_event (GtkEntry* entry,
|
|||
g_object_get_data (G_OBJECT (entry), "sokoke_has_default"));
|
||||
if (has_default)
|
||||
{
|
||||
gtk_entry_set_text (entry, "");
|
||||
g_object_set_data (G_OBJECT (entry), "sokoke_has_default",
|
||||
GINT_TO_POINTER (0));
|
||||
gtk_entry_set_text (entry, "");
|
||||
sokoke_widget_set_pango_font_style (GTK_WIDGET (entry),
|
||||
PANGO_STYLE_NORMAL);
|
||||
}
|
||||
|
@ -46,9 +57,9 @@ sokoke_on_entry_focus_out_event (GtkEntry* entry,
|
|||
{
|
||||
const gchar* default_text = (const gchar*)g_object_get_data (
|
||||
G_OBJECT (entry), "sokoke_default_text");
|
||||
gtk_entry_set_text (entry, default_text);
|
||||
g_object_set_data (G_OBJECT (entry),
|
||||
"sokoke_has_default", GINT_TO_POINTER (1));
|
||||
gtk_entry_set_text (entry, default_text);
|
||||
sokoke_widget_set_pango_font_style (GTK_WIDGET (entry),
|
||||
PANGO_STYLE_ITALIC);
|
||||
}
|
||||
|
@ -71,14 +82,15 @@ gtk_entry_set_placeholder_text (GtkEntry* entry,
|
|||
const gchar* default_text)
|
||||
{
|
||||
/* Note: The default text initially overwrites any previous text */
|
||||
gchar* old_value = g_object_get_data (G_OBJECT (entry),
|
||||
"sokoke_default_text");
|
||||
if (!old_value)
|
||||
gchar* old_value = g_object_get_data (G_OBJECT (entry), "sokoke_default_text");
|
||||
g_object_set_data (G_OBJECT (entry), "sokoke_default_text", (gpointer)default_text);
|
||||
|
||||
if (default_text == NULL)
|
||||
g_object_set_data (G_OBJECT (entry), "sokoke_has_default", GINT_TO_POINTER (0));
|
||||
else if (!old_value)
|
||||
{
|
||||
g_object_set_data (G_OBJECT (entry), "sokoke_has_default",
|
||||
GINT_TO_POINTER (1));
|
||||
sokoke_widget_set_pango_font_style (GTK_WIDGET (entry),
|
||||
PANGO_STYLE_ITALIC);
|
||||
g_object_set_data (G_OBJECT (entry), "sokoke_has_default", GINT_TO_POINTER (1));
|
||||
sokoke_widget_set_pango_font_style (GTK_WIDGET (entry), PANGO_STYLE_ITALIC);
|
||||
gtk_entry_set_text (entry, default_text);
|
||||
g_signal_connect (entry, "drag-data-received",
|
||||
G_CALLBACK (sokoke_on_entry_drag_data_received), NULL);
|
||||
|
@ -89,55 +101,19 @@ gtk_entry_set_placeholder_text (GtkEntry* entry,
|
|||
}
|
||||
else if (!gtk_widget_has_focus (GTK_WIDGET (entry)))
|
||||
{
|
||||
gint has_default = GPOINTER_TO_INT (
|
||||
g_object_get_data (G_OBJECT (entry), "sokoke_has_default"));
|
||||
gint has_default = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (entry), "sokoke_has_default"));
|
||||
if (has_default)
|
||||
{
|
||||
gtk_entry_set_text (entry, default_text);
|
||||
sokoke_widget_set_pango_font_style (GTK_WIDGET (entry),
|
||||
PANGO_STYLE_ITALIC);
|
||||
sokoke_widget_set_pango_font_style (GTK_WIDGET (entry), PANGO_STYLE_ITALIC);
|
||||
}
|
||||
}
|
||||
g_object_set_data (G_OBJECT (entry), "sokoke_default_text",
|
||||
(gpointer)default_text);
|
||||
}
|
||||
|
||||
const gchar*
|
||||
gtk_entry_get_placeholder_text (GtkEntry* entry)
|
||||
{
|
||||
return g_object_get_data (G_OBJECT (entry), "sokoke_default_text");
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !GTK_CHECK_VERSION (2, 12, 0)
|
||||
|
||||
void
|
||||
gtk_widget_set_has_tooltip (GtkWidget* widget,
|
||||
gboolean has_tooltip)
|
||||
{
|
||||
/* Do nothing */
|
||||
}
|
||||
|
||||
void
|
||||
gtk_widget_set_tooltip_text (GtkWidget* widget,
|
||||
const gchar* text)
|
||||
{
|
||||
if (text && *text)
|
||||
{
|
||||
static GtkTooltips* tooltips = NULL;
|
||||
if (G_UNLIKELY (!tooltips))
|
||||
tooltips = gtk_tooltips_new ();
|
||||
gtk_tooltips_set_tip (tooltips, widget, text, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gtk_tool_item_set_tooltip_text (GtkToolItem* toolitem,
|
||||
const gchar* text)
|
||||
{
|
||||
if (text && *text)
|
||||
{
|
||||
static GtkTooltips* tooltips = NULL;
|
||||
if (G_UNLIKELY (!tooltips))
|
||||
tooltips = gtk_tooltips_new ();
|
||||
|
||||
gtk_tool_item_set_tooltip (toolitem, tooltips, text, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -1,3 +1,14 @@
|
|||
/*
|
||||
Copyright (C) 2011-2012 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 <gtk/gtk.h>
|
||||
#include <gdk/gdkkeysyms.h>
|
||||
|
||||
|
@ -6,7 +17,7 @@
|
|||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#if GTK_CHECK_VERSION (3, 2, 0)
|
||||
#if GTK_CHECK_VERSION (3, 2, 0) && defined (GTK_DISABLE_DEPRECATED)
|
||||
#define GTK_TYPE_VBOX GTK_TYPE_BOX
|
||||
#define GtkVBox GtkBox
|
||||
#define GtkVBoxClass GtkBoxClass
|
||||
|
@ -39,25 +50,6 @@ G_BEGIN_DECLS
|
|||
#define g_format_size(sz) g_format_size_for_display ((goffset)sz)
|
||||
#endif
|
||||
|
||||
#if !GTK_CHECK_VERSION (2, 14, 0)
|
||||
#define gtk_dialog_get_content_area(dlg) dlg->vbox
|
||||
#define gtk_dialog_get_action_area(dlg) dlg->action_area
|
||||
#define gtk_widget_get_window(wdgt) wdgt->window
|
||||
#define gtk_adjustment_get_page_size(adj) adj->page_size
|
||||
#define gtk_adjustment_get_upper(adj) adj->upper
|
||||
#define gtk_adjustment_get_lower(adj) adj->lower
|
||||
#define gtk_adjustment_get_value(adj) adj->value
|
||||
#endif
|
||||
|
||||
#if !GTK_CHECK_VERSION (2, 16, 0)
|
||||
#define GTK_ACTIVATABLE GTK_WIDGET
|
||||
#define gtk_activatable_get_related_action gtk_widget_get_action
|
||||
#define gtk_menu_item_set_label(menuitem, label) \
|
||||
gtk_label_set_label (GTK_LABEL (GTK_BIN (menuitem)->child), \
|
||||
label ? label : "");
|
||||
#define gtk_image_menu_item_set_always_show_image(menuitem, yesno) ()
|
||||
#endif
|
||||
|
||||
#if !GTK_CHECK_VERSION (2, 18, 0)
|
||||
#define gtk_widget_is_toplevel(widget) GTK_WIDGET_TOPLEVEL (widget)
|
||||
#define gtk_widget_has_focus(widget) GTK_WIDGET_HAS_FOCUS (widget)
|
||||
|
@ -87,26 +79,9 @@ G_BEGIN_DECLS
|
|||
#define GTK_DIALOG_NO_SEPARATOR 0
|
||||
#endif
|
||||
|
||||
#if !GTK_CHECK_VERSION (3, 2, 0) && defined (HAVE_HILDON_2_2)
|
||||
#define gtk_entry_set_placeholder_text hildon_gtk_entry_set_placeholder_text
|
||||
#elif !GTK_CHECK_VERSION (3, 2, 0)
|
||||
#define gtk_entry_set_placeholder_text sokoke_entry_set_default_text
|
||||
#endif
|
||||
|
||||
#if !GTK_CHECK_VERSION(2, 12, 0)
|
||||
|
||||
void
|
||||
gtk_widget_set_has_tooltip (GtkWidget* widget,
|
||||
gboolean has_tooltip);
|
||||
|
||||
void
|
||||
gtk_widget_set_tooltip_text (GtkWidget* widget,
|
||||
const gchar* text);
|
||||
|
||||
void
|
||||
gtk_tool_item_set_tooltip_text (GtkToolItem* toolitem,
|
||||
const gchar* text);
|
||||
|
||||
#if !GTK_CHECK_VERSION (3, 2, 0)
|
||||
void gtk_entry_set_placeholder_text (GtkEntry* entry, const gchar* text);
|
||||
const gchar* gtk_entry_get_placeholder_text (GtkEntry* entry);
|
||||
#endif
|
||||
|
||||
#if !GTK_CHECK_VERSION (2, 24 ,0)
|
||||
|
@ -149,6 +124,13 @@ gtk_tool_item_set_tooltip_text (GtkToolItem* toolitem,
|
|||
#define GDK_KEY_Return GDK_Return
|
||||
#endif
|
||||
|
||||
#ifdef GDK_WINDOWING_X11
|
||||
#include <gdk/gdkx.h>
|
||||
#ifndef GDK_IS_X11_DISPLAY
|
||||
#define GDK_IS_X11_DISPLAY(display) TRUE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
||||
|
|
|
@ -74,6 +74,13 @@ GList* kalistglobal;
|
|||
static void
|
||||
katze_array_finalize (GObject* object);
|
||||
|
||||
static void
|
||||
_katze_array_update (KatzeArray* array)
|
||||
{
|
||||
g_object_set_data (G_OBJECT (array), "last-update",
|
||||
GINT_TO_POINTER (time (NULL)));
|
||||
}
|
||||
|
||||
static void
|
||||
_katze_array_add_item (KatzeArray* array,
|
||||
gpointer item)
|
||||
|
@ -84,6 +91,7 @@ _katze_array_add_item (KatzeArray* array,
|
|||
katze_item_set_parent (item, array);
|
||||
|
||||
array->items = g_list_append (array->items, item);
|
||||
_katze_array_update (array);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -95,6 +103,7 @@ _katze_array_remove_item (KatzeArray* array,
|
|||
if (KATZE_IS_ITEM (item))
|
||||
katze_item_set_parent (item, NULL);
|
||||
g_object_unref (item);
|
||||
_katze_array_update (array);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -104,6 +113,7 @@ _katze_array_move_item (KatzeArray* array,
|
|||
{
|
||||
array->items = g_list_remove (array->items, item);
|
||||
array->items = g_list_insert (array->items, item, position);
|
||||
_katze_array_update (array);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -112,9 +122,10 @@ _katze_array_clear (KatzeArray* array)
|
|||
GObject* item;
|
||||
|
||||
while ((item = g_list_nth_data (array->items, 0)))
|
||||
katze_array_remove_item (array, item);
|
||||
g_signal_emit (array, signals[REMOVE_ITEM], 0, item);
|
||||
g_list_free (array->items);
|
||||
array->items = NULL;
|
||||
_katze_array_update (array);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -192,7 +203,7 @@ katze_array_class_init (KatzeArrayClass* class)
|
|||
"update",
|
||||
G_TYPE_FROM_CLASS (class),
|
||||
(GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
|
||||
0,
|
||||
G_STRUCT_OFFSET (KatzeArrayClass, update),
|
||||
0,
|
||||
NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
|
@ -205,6 +216,7 @@ katze_array_class_init (KatzeArrayClass* class)
|
|||
class->remove_item = _katze_array_remove_item;
|
||||
class->move_item = _katze_array_move_item;
|
||||
class->clear = _katze_array_clear;
|
||||
class->update = _katze_array_update;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -217,14 +229,11 @@ katze_array_init (KatzeArray* array)
|
|||
static void
|
||||
katze_array_finalize (GObject* object)
|
||||
{
|
||||
KatzeArray* array;
|
||||
guint i;
|
||||
gpointer item;
|
||||
KatzeArray* array = KATZE_ARRAY (object);
|
||||
GList* items;
|
||||
|
||||
array = KATZE_ARRAY (object);
|
||||
i = 0;
|
||||
while ((item = g_list_nth_data (array->items, i++)))
|
||||
g_object_unref (item);
|
||||
for (items = array->items; items; items = g_list_next (items))
|
||||
g_object_unref (items->data);
|
||||
g_list_free (array->items);
|
||||
|
||||
G_OBJECT_CLASS (katze_array_parent_class)->finalize (object);
|
||||
|
@ -364,37 +373,44 @@ katze_array_get_item_index (KatzeArray* array,
|
|||
/**
|
||||
* katze_array_find_token:
|
||||
* @array: a #KatzeArray
|
||||
* @token: a token string
|
||||
* @token: a token string, or "token keywords" string
|
||||
*
|
||||
* Looks up an item in the array which has the specified token.
|
||||
*
|
||||
* This function will silently fail if the type of the list
|
||||
* is not based on #GObject and only #KatzeItem children
|
||||
* are checked for their token, any other objects are skipped.
|
||||
* This function will fail if the type of the list
|
||||
* is not based on #KatzeItem children.
|
||||
*
|
||||
* Note that @token is by definition unique to one item.
|
||||
*
|
||||
* Since 0.4.4 @token can be a "token keywords" string.
|
||||
*
|
||||
* Return value: an item, or %NULL
|
||||
**/
|
||||
gpointer
|
||||
katze_array_find_token (KatzeArray* array,
|
||||
const gchar* token)
|
||||
{
|
||||
guint i;
|
||||
gpointer item;
|
||||
goffset token_length;
|
||||
GList* items;
|
||||
|
||||
g_return_val_if_fail (KATZE_IS_ARRAY (array), NULL);
|
||||
g_return_val_if_fail (katze_array_is_a (array, KATZE_TYPE_ITEM), NULL);
|
||||
g_return_val_if_fail (token != NULL, NULL);
|
||||
|
||||
i = 0;
|
||||
while ((item = g_list_nth_data (array->items, i++)))
|
||||
token_length = strchr (token, ' ') - token;
|
||||
if (token_length < 1)
|
||||
token_length = strlen (token);
|
||||
|
||||
for (items = array->items; items; items = g_list_next (items))
|
||||
{
|
||||
const gchar* found_token;
|
||||
const gchar* found_token = ((KatzeItem*)items->data)->token;
|
||||
if (found_token != NULL)
|
||||
{
|
||||
guint bigger_item = strlen (found_token) > token_length ? strlen (found_token) : token_length;
|
||||
|
||||
if (!KATZE_IS_ITEM (item))
|
||||
continue;
|
||||
found_token = ((KatzeItem*)item)->token;
|
||||
if (!g_strcmp0 (found_token, token))
|
||||
return item;
|
||||
if (strncmp (token, found_token, bigger_item) == 0)
|
||||
return items->data;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
@ -406,9 +422,8 @@ katze_array_find_token (KatzeArray* array,
|
|||
*
|
||||
* Looks up an item in the array which has the specified URI.
|
||||
*
|
||||
* This function will silently fail if the type of the list
|
||||
* is not based on #GObject and only #KatzeItem children
|
||||
* are checked for their token, any other objects are skipped.
|
||||
* This function will fail if the type of the list
|
||||
* is not based on #KatzeItem children.
|
||||
*
|
||||
* Return value: an item, or %NULL
|
||||
*
|
||||
|
@ -418,19 +433,17 @@ gpointer
|
|||
katze_array_find_uri (KatzeArray* array,
|
||||
const gchar* uri)
|
||||
{
|
||||
guint i;
|
||||
gpointer item;
|
||||
GList* items;
|
||||
|
||||
i = 0;
|
||||
while ((item = g_list_nth_data (array->items, i++)))
|
||||
g_return_val_if_fail (KATZE_IS_ARRAY (array), NULL);
|
||||
g_return_val_if_fail (katze_array_is_a (array, KATZE_TYPE_ITEM), NULL);
|
||||
g_return_val_if_fail (uri != NULL, NULL);
|
||||
|
||||
for (items = array->items; items; items = g_list_next (items))
|
||||
{
|
||||
const gchar* found_uri;
|
||||
|
||||
if (!KATZE_IS_ITEM (item))
|
||||
continue;
|
||||
found_uri = ((KatzeItem*)item)->uri;
|
||||
if (!g_strcmp0 (found_uri, uri))
|
||||
return item;
|
||||
const gchar* found_uri = ((KatzeItem*)items->data)->uri;
|
||||
if (found_uri != NULL && !strcmp (found_uri, uri))
|
||||
return items->data;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -355,11 +355,16 @@ katze_array_action_generate_menu (KatzeArrayAction* array_action,
|
|||
gint summand;
|
||||
KatzeItem* item;
|
||||
GtkWidget* menuitem;
|
||||
const gchar* icon_name;
|
||||
GdkPixbuf* icon;
|
||||
GtkWidget* image;
|
||||
GtkWidget* submenu;
|
||||
|
||||
g_return_if_fail (KATZE_IS_ARRAY_ACTION (array_action));
|
||||
g_return_if_fail (KATZE_IS_ITEM (array));
|
||||
g_return_if_fail (GTK_IS_MENU_SHELL (menu));
|
||||
g_return_if_fail (GTK_IS_TOOL_ITEM (proxy)
|
||||
|| GTK_IS_MENU_ITEM (proxy)
|
||||
|| GTK_IS_WINDOW (proxy));
|
||||
|
||||
if (!KATZE_IS_ARRAY (array))
|
||||
return;
|
||||
|
||||
|
@ -385,18 +390,7 @@ katze_array_action_generate_menu (KatzeArrayAction* array_action,
|
|||
}
|
||||
menuitem = katze_image_menu_item_new_ellipsized (
|
||||
katze_item_get_name (item));
|
||||
if ((icon_name = katze_item_get_icon (item)) && *icon_name)
|
||||
image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_MENU);
|
||||
else
|
||||
{
|
||||
if (KATZE_ITEM_IS_FOLDER (item))
|
||||
icon = gtk_widget_render_icon (menuitem,
|
||||
GTK_STOCK_DIRECTORY, GTK_ICON_SIZE_MENU, NULL);
|
||||
else
|
||||
icon = katze_load_cached_icon (katze_item_get_uri (item), proxy);
|
||||
image = gtk_image_new_from_pixbuf (icon);
|
||||
g_object_unref (icon);
|
||||
}
|
||||
image = katze_item_get_image (item, menuitem);
|
||||
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), image);
|
||||
gtk_image_menu_item_set_always_show_image (
|
||||
GTK_IMAGE_MENU_ITEM (menuitem), TRUE);
|
||||
|
@ -406,8 +400,13 @@ katze_array_action_generate_menu (KatzeArrayAction* array_action,
|
|||
{
|
||||
submenu = gtk_menu_new ();
|
||||
gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), submenu);
|
||||
/* Make sure menu appears to contain items */
|
||||
gtk_menu_shell_append (GTK_MENU_SHELL (submenu),
|
||||
gtk_separator_menu_item_new ());
|
||||
g_signal_connect (menuitem, "select",
|
||||
G_CALLBACK (katze_array_action_menu_item_select_cb), array_action);
|
||||
g_signal_connect (menuitem, "activate",
|
||||
G_CALLBACK (katze_array_action_menu_item_select_cb), array_action);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -421,21 +420,39 @@ katze_array_action_generate_menu (KatzeArrayAction* array_action,
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
katze_array_action_menu_item_select_cb (GtkWidget* proxy,
|
||||
KatzeArrayAction* array_action)
|
||||
static gboolean
|
||||
katze_array_action_menu_item_need_update (KatzeArrayAction* array_action,
|
||||
GtkWidget* proxy)
|
||||
{
|
||||
GtkWidget* menu;
|
||||
KatzeArray* array;
|
||||
gint last_array_update, last_proxy_update;
|
||||
gboolean handled;
|
||||
|
||||
array = g_object_get_data (G_OBJECT (proxy), "KatzeItem");
|
||||
/* last-update is set on all arrays; consider public API */
|
||||
last_array_update = GPOINTER_TO_INT (
|
||||
g_object_get_data (G_OBJECT (array), "last-update"));
|
||||
last_proxy_update = GPOINTER_TO_INT (
|
||||
g_object_get_data (G_OBJECT (proxy), "last-update"));
|
||||
if (last_proxy_update > last_array_update)
|
||||
return FALSE;
|
||||
|
||||
menu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (proxy));
|
||||
gtk_container_foreach (GTK_CONTAINER (menu),
|
||||
(GtkCallback)(gtk_widget_destroy), NULL);
|
||||
|
||||
array = g_object_get_data (G_OBJECT (proxy), "KatzeItem");
|
||||
katze_array_action_generate_menu (array_action, array, GTK_MENU_SHELL (menu), proxy);
|
||||
g_signal_emit (array_action, signals[POPULATE_FOLDER], 0, menu, array, &handled);
|
||||
g_object_set_data (G_OBJECT (proxy), "last-update",
|
||||
GINT_TO_POINTER (time (NULL)));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
katze_array_action_menu_item_select_cb (GtkWidget* proxy,
|
||||
KatzeArrayAction* array_action)
|
||||
{
|
||||
katze_array_action_menu_item_need_update (array_action, proxy);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -458,20 +475,21 @@ katze_array_action_proxy_clicked_cb (GtkWidget* proxy,
|
|||
KatzeArray* array;
|
||||
gboolean handled = FALSE;
|
||||
|
||||
array = (KatzeArray*)g_object_get_data (G_OBJECT (proxy), "KatzeItem");
|
||||
if (GTK_IS_MENU_ITEM (proxy))
|
||||
{
|
||||
g_object_set_data (G_OBJECT (proxy), "KatzeItem", array_action->array);
|
||||
katze_array_action_menu_item_select_cb (proxy, array_action);
|
||||
g_signal_emit (array_action, signals[POPULATE_FOLDER], 0,
|
||||
gtk_menu_item_get_submenu (GTK_MENU_ITEM (proxy)),
|
||||
array_action->array, &handled);
|
||||
if (!handled)
|
||||
g_signal_emit (array_action, signals[POPULATE_POPUP], 0,
|
||||
gtk_menu_item_get_submenu (GTK_MENU_ITEM (proxy)));
|
||||
if (katze_array_action_menu_item_need_update (array_action, proxy))
|
||||
{
|
||||
g_signal_emit (array_action, signals[POPULATE_FOLDER], 0,
|
||||
gtk_menu_item_get_submenu (GTK_MENU_ITEM (proxy)),
|
||||
array, &handled);
|
||||
if (!handled)
|
||||
g_signal_emit (array_action, signals[POPULATE_POPUP], 0,
|
||||
gtk_menu_item_get_submenu (GTK_MENU_ITEM (proxy)));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
array = (KatzeArray*)g_object_get_data (G_OBJECT (proxy), "KatzeArray");
|
||||
if (KATZE_IS_ITEM (array) && katze_item_get_uri ((KatzeItem*)array))
|
||||
{
|
||||
katze_array_action_activate_item (array_action, KATZE_ITEM (array), 1);
|
||||
|
@ -493,14 +511,8 @@ katze_array_action_proxy_clicked_cb (GtkWidget* proxy,
|
|||
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
|
||||
gtk_menu_shell_select_first (GTK_MENU_SHELL (menu), TRUE);
|
||||
g_object_set_data (G_OBJECT (menu), "KatzeArrayAction", array_action);
|
||||
g_signal_connect (menu, "deactivate",
|
||||
|
@ -552,7 +564,6 @@ katze_array_action_item_notify_cb (KatzeItem* item,
|
|||
const gchar* property;
|
||||
const gchar* title;
|
||||
const gchar* desc;
|
||||
GdkPixbuf* icon;
|
||||
GtkWidget* image;
|
||||
|
||||
if (!G_IS_PARAM_SPEC_STRING (pspec))
|
||||
|
@ -579,17 +590,12 @@ katze_array_action_item_notify_cb (KatzeItem* item,
|
|||
}
|
||||
else if (KATZE_ITEM_IS_BOOKMARK (item) && !strcmp (property, "uri"))
|
||||
{
|
||||
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);
|
||||
image = katze_item_get_image (item, GTK_WIDGET (toolitem));
|
||||
gtk_tool_button_set_icon_widget (GTK_TOOL_BUTTON (toolitem), image);
|
||||
}
|
||||
else if (!strcmp (property, "icon"))
|
||||
{
|
||||
image = gtk_image_new_from_icon_name (katze_item_get_icon (item),
|
||||
GTK_ICON_SIZE_MENU);
|
||||
gtk_widget_show (image);
|
||||
image = katze_item_get_image (item, GTK_WIDGET (toolitem));
|
||||
gtk_tool_button_set_icon_widget (GTK_TOOL_BUTTON (toolitem), image);
|
||||
}
|
||||
}
|
||||
|
@ -600,25 +606,12 @@ katze_array_action_proxy_create_menu_proxy_cb (GtkWidget* proxy,
|
|||
{
|
||||
KatzeArrayAction* array_action;
|
||||
GtkWidget* menuitem;
|
||||
const gchar* icon_name;
|
||||
GtkWidget* image;
|
||||
GdkPixbuf* icon;
|
||||
|
||||
array_action = g_object_get_data (G_OBJECT (proxy), "KatzeArrayAction");
|
||||
menuitem = katze_image_menu_item_new_ellipsized (
|
||||
katze_item_get_name (item));
|
||||
if ((icon_name = katze_item_get_icon (item)) && *icon_name)
|
||||
image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_MENU);
|
||||
else
|
||||
{
|
||||
if (KATZE_ITEM_IS_FOLDER (item))
|
||||
icon = gtk_widget_render_icon (menuitem,
|
||||
GTK_STOCK_DIRECTORY, GTK_ICON_SIZE_MENU, NULL);
|
||||
else
|
||||
icon = katze_load_cached_icon (katze_item_get_uri (item), proxy);
|
||||
image = gtk_image_new_from_pixbuf (icon);
|
||||
g_object_unref (icon);
|
||||
}
|
||||
image = katze_item_get_image (item, menuitem);
|
||||
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), image);
|
||||
gtk_image_menu_item_set_always_show_image (
|
||||
GTK_IMAGE_MENU_ITEM (menuitem), TRUE);
|
||||
|
@ -674,7 +667,6 @@ katze_array_action_create_tool_item_for (KatzeArrayAction* array_action,
|
|||
const gchar* uri;
|
||||
const gchar* desc;
|
||||
GtkToolItem* toolitem;
|
||||
GdkPixbuf* icon;
|
||||
GtkWidget* image;
|
||||
GtkWidget* label;
|
||||
|
||||
|
@ -686,21 +678,12 @@ katze_array_action_create_tool_item_for (KatzeArrayAction* array_action,
|
|||
return gtk_separator_tool_item_new ();
|
||||
|
||||
if (KATZE_ITEM_IS_FOLDER (item))
|
||||
{
|
||||
toolitem = gtk_toggle_tool_button_new ();
|
||||
icon = gtk_widget_render_icon (GTK_WIDGET (toolitem),
|
||||
GTK_STOCK_DIRECTORY, GTK_ICON_SIZE_MENU, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
toolitem = gtk_tool_button_new (NULL, "");
|
||||
icon = katze_load_cached_icon (uri, GTK_WIDGET (toolitem));
|
||||
}
|
||||
g_signal_connect (toolitem, "create-menu-proxy",
|
||||
G_CALLBACK (katze_array_action_proxy_create_menu_proxy_cb), item);
|
||||
image = gtk_image_new_from_pixbuf (icon);
|
||||
g_object_unref (icon);
|
||||
gtk_widget_show (image);
|
||||
image = katze_item_get_image (item, GTK_WIDGET (toolitem));
|
||||
gtk_tool_button_set_icon_widget (GTK_TOOL_BUTTON (toolitem), image);
|
||||
label = gtk_label_new (NULL);
|
||||
/* FIXME: Should text direction be respected here? */
|
||||
|
@ -739,6 +722,9 @@ static void
|
|||
katze_array_action_connect_proxy (GtkAction* action,
|
||||
GtkWidget* proxy)
|
||||
{
|
||||
KatzeArrayAction* array_action = KATZE_ARRAY_ACTION (action);
|
||||
g_object_set_data (G_OBJECT (proxy), "KatzeItem", array_action->array);
|
||||
|
||||
GTK_ACTION_CLASS (katze_array_action_parent_class)->connect_proxy (
|
||||
action, proxy);
|
||||
|
||||
|
@ -750,9 +736,10 @@ katze_array_action_connect_proxy (GtkAction* action,
|
|||
else if (GTK_IS_MENU_ITEM (proxy))
|
||||
{
|
||||
gtk_menu_item_set_submenu (GTK_MENU_ITEM (proxy), gtk_menu_new ());
|
||||
/* FIXME: 'select' doesn't cover all ways of selection */
|
||||
g_signal_connect (proxy, "select",
|
||||
G_CALLBACK (katze_array_action_proxy_clicked_cb), action);
|
||||
g_signal_connect (proxy, "activate",
|
||||
G_CALLBACK (katze_array_action_proxy_clicked_cb), action);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
#include <sqlite3.h>
|
||||
|
||||
#define QUERY_ALL "SELECT id, name, value, host, path, expiry, lastAccessed, isSecure, isHttpOnly FROM moz_cookies;"
|
||||
#define CREATE_TABLE "CREATE TABLE moz_cookies (id INTEGER PRIMARY KEY, name TEXT, value TEXT, host TEXT, path TEXT,expiry INTEGER, lastAccessed INTEGER, isSecure INTEGER, isHttpOnly INTEGER)"
|
||||
#define CREATE_TABLE "CREATE TABLE IF NOT EXISTS moz_cookies (id INTEGER PRIMARY KEY, name TEXT, value TEXT, host TEXT, path TEXT,expiry INTEGER, lastAccessed INTEGER, isSecure INTEGER, isHttpOnly INTEGER)"
|
||||
#define QUERY_INSERT "INSERT INTO moz_cookies VALUES(NULL, %Q, %Q, %Q, %Q, %d, NULL, %d, %d);"
|
||||
#define QUERY_DELETE "DELETE FROM moz_cookies WHERE name=%Q AND host=%Q;"
|
||||
|
||||
|
@ -71,80 +71,6 @@ G_DEFINE_TYPE_WITH_CODE (KatzeHttpCookiesSqlite, katze_http_cookies_sqlite, G_TY
|
|||
Copyright (C) 2009 Collabora Ltd.
|
||||
Mostly copied from libSoup 2.30, coding style retained */
|
||||
|
||||
static void
|
||||
try_create_table (sqlite3 *db)
|
||||
{
|
||||
char *error = NULL;
|
||||
|
||||
if (sqlite3_exec (db, CREATE_TABLE, NULL, NULL, &error)) {
|
||||
g_warning ("Failed to execute query: %s", error);
|
||||
sqlite3_free (error);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
exec_query_with_try_create_table (sqlite3* db,
|
||||
const char* sql,
|
||||
int (*callback)(void*,int,char**,char**),
|
||||
void *argument)
|
||||
{
|
||||
char *error = NULL;
|
||||
gboolean try_create = TRUE;
|
||||
|
||||
try_exec:
|
||||
if (sqlite3_exec (db, sql, callback, argument, &error)) {
|
||||
if (try_create) {
|
||||
try_create = FALSE;
|
||||
try_create_table (db);
|
||||
sqlite3_free (error);
|
||||
error = NULL;
|
||||
goto try_exec;
|
||||
} else {
|
||||
g_warning ("Failed to execute query: %s", error);
|
||||
sqlite3_free (error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
callback (void *data, int argc, char **argv, char **colname)
|
||||
{
|
||||
SoupCookie *cookie = NULL;
|
||||
SoupCookieJar *jar = SOUP_COOKIE_JAR (data);
|
||||
|
||||
char *name, *value, *host, *path;
|
||||
gint64 expire_time;
|
||||
time_t now;
|
||||
int max_age;
|
||||
gboolean http_only = FALSE, secure = FALSE;
|
||||
|
||||
now = time (NULL);
|
||||
|
||||
name = argv[COL_NAME];
|
||||
value = argv[COL_VALUE];
|
||||
host = argv[COL_HOST];
|
||||
path = argv[COL_PATH];
|
||||
expire_time = g_ascii_strtoull (argv[COL_EXPIRY], NULL, 10);
|
||||
|
||||
if (now >= expire_time)
|
||||
return 0;
|
||||
max_age = (expire_time - now <= G_MAXINT ? expire_time - now : G_MAXINT);
|
||||
|
||||
http_only = (g_strcmp0 (argv[COL_HTTP_ONLY], "1") == 0);
|
||||
secure = (g_strcmp0 (argv[COL_SECURE], "1") == 0);
|
||||
|
||||
cookie = soup_cookie_new (name, value, host, path, max_age);
|
||||
|
||||
if (secure)
|
||||
soup_cookie_set_secure (cookie, TRUE);
|
||||
if (http_only)
|
||||
soup_cookie_set_http_only (cookie, TRUE);
|
||||
|
||||
soup_cookie_jar_add_cookie (jar, cookie);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Follows sqlite3 convention; returns TRUE on error */
|
||||
static gboolean
|
||||
katze_http_cookies_sqlite_open_db (KatzeHttpCookiesSqlite* http_cookies)
|
||||
|
@ -157,23 +83,91 @@ katze_http_cookies_sqlite_open_db (KatzeHttpCookiesSqlite* http_cookies)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
if (sqlite3_exec (http_cookies->db, "PRAGMA synchronous = OFF; PRAGMA secure_delete = 1;", NULL, NULL, &error)) {
|
||||
if (sqlite3_exec (http_cookies->db, CREATE_TABLE, NULL, NULL, &error)) {
|
||||
g_warning ("Failed to execute query: %s", error);
|
||||
sqlite3_free (error);
|
||||
}
|
||||
|
||||
if (sqlite3_exec (http_cookies->db, "PRAGMA secure_delete = 1;",
|
||||
NULL, NULL, &error)) {
|
||||
g_warning ("Failed to execute query: %s", error);
|
||||
sqlite3_free (error);
|
||||
}
|
||||
|
||||
sqlite3_exec (http_cookies->db,
|
||||
/* Arguably cookies are like a cache, so performance over integrity */
|
||||
"PRAGMA synchronous = OFF; PRAGMA temp_store = MEMORY;"
|
||||
"PRAGMA count_changes = OFF; PRAGMA journal_mode = TRUNCATE;",
|
||||
NULL, NULL, &error);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
katze_http_cookies_sqlite_load (KatzeHttpCookiesSqlite* http_cookies)
|
||||
{
|
||||
const char *name, *value, *host, *path;
|
||||
sqlite3_stmt* stmt;
|
||||
SoupCookie *cookie = NULL;
|
||||
gint64 expire_time;
|
||||
time_t now;
|
||||
int max_age;
|
||||
gboolean http_only = FALSE, secure = FALSE;
|
||||
char *query;
|
||||
int result;
|
||||
|
||||
if (http_cookies->db == NULL) {
|
||||
if (katze_http_cookies_sqlite_open_db (http_cookies))
|
||||
return;
|
||||
}
|
||||
|
||||
exec_query_with_try_create_table (http_cookies->db, QUERY_ALL, callback, http_cookies->jar);
|
||||
sqlite3_prepare_v2 (http_cookies->db, QUERY_ALL, strlen (QUERY_ALL) + 1, &stmt, NULL);
|
||||
result = sqlite3_step (stmt);
|
||||
if (result != SQLITE_ROW)
|
||||
{
|
||||
if (result == SQLITE_ERROR)
|
||||
g_print (_("Failed to load cookies\n"));
|
||||
sqlite3_reset (stmt);
|
||||
return;
|
||||
}
|
||||
|
||||
while (result == SQLITE_ROW)
|
||||
{
|
||||
now = time (NULL);
|
||||
name = (const char*)sqlite3_column_text (stmt, COL_NAME);
|
||||
value = (const char*)sqlite3_column_text (stmt, COL_VALUE);
|
||||
host = (const char*)sqlite3_column_text (stmt, COL_HOST);
|
||||
path = (const char*)sqlite3_column_text (stmt, COL_PATH);
|
||||
expire_time = sqlite3_column_int64 (stmt,COL_EXPIRY);
|
||||
secure = sqlite3_column_int (stmt, COL_SECURE);
|
||||
http_only = sqlite3_column_int (stmt, COL_HTTP_ONLY);
|
||||
|
||||
if (now >= expire_time)
|
||||
{
|
||||
/* Cookie expired, remove it from database */
|
||||
query = sqlite3_mprintf (QUERY_DELETE, name, host);
|
||||
sqlite3_exec (http_cookies->db, QUERY_DELETE, NULL, NULL, NULL);
|
||||
sqlite3_free (query);
|
||||
result = sqlite3_step (stmt);
|
||||
continue;
|
||||
}
|
||||
max_age = (expire_time - now <= G_MAXINT ? expire_time - now : G_MAXINT);
|
||||
cookie = soup_cookie_new (name, value, host, path, max_age);
|
||||
|
||||
if (secure)
|
||||
soup_cookie_set_secure (cookie, TRUE);
|
||||
if (http_only)
|
||||
soup_cookie_set_http_only (cookie, TRUE);
|
||||
|
||||
soup_cookie_jar_add_cookie (http_cookies->jar, cookie);
|
||||
result = sqlite3_step (stmt);
|
||||
}
|
||||
|
||||
if (stmt)
|
||||
{
|
||||
sqlite3_reset (stmt);
|
||||
sqlite3_clear_bindings (stmt);
|
||||
}
|
||||
}
|
||||
static void
|
||||
katze_http_cookies_sqlite_jar_changed_cb (SoupCookieJar* jar,
|
||||
|
@ -213,14 +207,14 @@ katze_http_cookies_sqlite_jar_changed_cb (SoupCookieJar* jar,
|
|||
}
|
||||
}
|
||||
|
||||
if (g_getenv ("MIDORI_COOKIES_DEBUG") != NULL)
|
||||
if (!g_strcmp0 (g_getenv ("MIDORI_DEBUG"), "cookies"))
|
||||
http_cookies->counter++;
|
||||
|
||||
if (old_cookie) {
|
||||
query = sqlite3_mprintf (QUERY_DELETE,
|
||||
old_cookie->name,
|
||||
old_cookie->domain);
|
||||
exec_query_with_try_create_table (http_cookies->db, query, NULL, NULL);
|
||||
sqlite3_exec (http_cookies->db, query, NULL, NULL, NULL);
|
||||
sqlite3_free (query);
|
||||
}
|
||||
|
||||
|
@ -234,7 +228,7 @@ katze_http_cookies_sqlite_jar_changed_cb (SoupCookieJar* jar,
|
|||
expires,
|
||||
new_cookie->secure,
|
||||
new_cookie->http_only);
|
||||
exec_query_with_try_create_table (http_cookies->db, query, NULL, NULL);
|
||||
sqlite3_exec (http_cookies->db, query, NULL, NULL, NULL);
|
||||
sqlite3_free (query);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#endif
|
||||
|
||||
#include "katze-http-cookies.h"
|
||||
#include "midori/midori-core.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
|
@ -211,7 +212,7 @@ katze_http_cookies_update_jar (KatzeHttpCookies* http_cookies)
|
|||
goto failed;
|
||||
g_free (temporary_filename);
|
||||
|
||||
if (g_getenv ("MIDORI_COOKIES_DEBUG") != NULL)
|
||||
if (!g_strcmp0 (g_getenv ("MIDORI_DEBUG"), "cookies"))
|
||||
{
|
||||
g_print ("KatzeHttpCookies: %d cookies changed\n", http_cookies->counter);
|
||||
http_cookies->counter = 0;
|
||||
|
@ -223,7 +224,7 @@ failed:
|
|||
fclose (f);
|
||||
g_unlink (temporary_filename);
|
||||
g_free (temporary_filename);
|
||||
if (g_getenv ("MIDORI_COOKIES_DEBUG") != NULL)
|
||||
if (!g_strcmp0 (g_getenv ("MIDORI_DEBUG"), "cookies"))
|
||||
g_print ("KatzeHttpCookies: Failed to write '%s'\n",
|
||||
http_cookies->filename);
|
||||
return FALSE;
|
||||
|
@ -263,12 +264,12 @@ katze_http_cookies_jar_changed_cb (SoupCookieJar* jar,
|
|||
}
|
||||
}
|
||||
|
||||
if (g_getenv ("MIDORI_COOKIES_DEBUG") != NULL)
|
||||
if (!g_strcmp0 (g_getenv ("MIDORI_DEBUG"), "cookies"))
|
||||
http_cookies->counter++;
|
||||
|
||||
if (!http_cookies->timeout && (old_cookie || new_cookie->expires))
|
||||
http_cookies->timeout = g_timeout_add_seconds (5,
|
||||
(GSourceFunc)katze_http_cookies_update_jar, http_cookies);
|
||||
if (!http_cookies->timeout && (old_cookie || (new_cookie && new_cookie->expires)))
|
||||
http_cookies->timeout = midori_timeout_add_seconds (
|
||||
5, (GSourceFunc)katze_http_cookies_update_jar, http_cookies, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -10,11 +10,13 @@
|
|||
*/
|
||||
|
||||
#include "katze-item.h"
|
||||
|
||||
#include "katze-utils.h"
|
||||
#include "midori/midori-core.h"
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "katze/katze.h"
|
||||
|
||||
/**
|
||||
* SECTION:katze-item
|
||||
* @short_description: A useful item
|
||||
|
@ -315,6 +317,8 @@ katze_item_set_name (KatzeItem* item,
|
|||
g_return_if_fail (KATZE_IS_ITEM (item));
|
||||
|
||||
katze_assign (item->name, g_strdup (name));
|
||||
if (item->parent)
|
||||
katze_array_update ((KatzeArray*)item->parent);
|
||||
g_object_notify (G_OBJECT (item), "name");
|
||||
}
|
||||
|
||||
|
@ -380,6 +384,9 @@ katze_item_set_uri (KatzeItem* item,
|
|||
{
|
||||
g_return_if_fail (KATZE_IS_ITEM (item));
|
||||
|
||||
if (!g_strcmp0 (item->uri, uri))
|
||||
return;
|
||||
|
||||
katze_assign (item->uri, g_strdup (uri));
|
||||
g_object_notify (G_OBJECT (item), "uri");
|
||||
}
|
||||
|
@ -414,9 +421,128 @@ katze_item_set_icon (KatzeItem* item,
|
|||
g_return_if_fail (KATZE_IS_ITEM (item));
|
||||
|
||||
katze_item_set_meta_string (item, "icon", icon);
|
||||
if (item->parent)
|
||||
katze_array_update ((KatzeArray*)item->parent);
|
||||
g_object_notify (G_OBJECT (item), "icon");
|
||||
}
|
||||
|
||||
/**
|
||||
* katze_item_get_pixbuf:
|
||||
* @item: a #KatzeItem
|
||||
* @widget: a #GtkWidget, or %NULL
|
||||
*
|
||||
* Retrieves a #GdkPixbuf fit to display @item.
|
||||
*
|
||||
* Return value: the icon of the item
|
||||
*
|
||||
* Since: 0.4.6
|
||||
**/
|
||||
GdkPixbuf*
|
||||
katze_item_get_pixbuf (KatzeItem* item,
|
||||
GtkWidget* widget)
|
||||
{
|
||||
GdkPixbuf* pixbuf;
|
||||
|
||||
g_return_val_if_fail (KATZE_IS_ITEM (item), NULL);
|
||||
|
||||
if (widget && KATZE_ITEM_IS_FOLDER (item))
|
||||
return gtk_widget_render_icon (widget, GTK_STOCK_DIRECTORY, GTK_ICON_SIZE_MENU, NULL);
|
||||
if ((pixbuf = midori_paths_get_icon (katze_item_get_icon (item), NULL)))
|
||||
return pixbuf;
|
||||
if ((pixbuf = midori_paths_get_icon (item->uri, widget)))
|
||||
return pixbuf;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
katze_item_image_destroyed_cb (GtkWidget* image,
|
||||
KatzeItem* item);
|
||||
#ifndef HAVE_WEBKIT2
|
||||
#if WEBKIT_CHECK_VERSION (1, 3, 13)
|
||||
static void
|
||||
#if WEBKIT_CHECK_VERSION (1, 8, 0)
|
||||
katze_item_icon_loaded_cb (WebKitFaviconDatabase* database,
|
||||
#elif WEBKIT_CHECK_VERSION (1, 3, 13)
|
||||
katze_item_icon_loaded_cb (WebKitIconDatabase* database,
|
||||
WebKitWebFrame* web_frame,
|
||||
#endif
|
||||
const gchar* frame_uri,
|
||||
GtkWidget* image)
|
||||
{
|
||||
KatzeItem* item = g_object_get_data (G_OBJECT (image), "KatzeItem");
|
||||
GdkPixbuf* pixbuf;
|
||||
if (!strcmp (frame_uri, item->uri)
|
||||
&& (pixbuf = midori_paths_get_icon (frame_uri, image)))
|
||||
{
|
||||
gtk_image_set_from_pixbuf (GTK_IMAGE (image), pixbuf);
|
||||
g_object_unref (pixbuf);
|
||||
/* This signal fires extremely often (WebKit bug?)
|
||||
we must throttle it (disconnect) once we have an icon */
|
||||
katze_item_image_destroyed_cb (image, g_object_ref (item));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static void
|
||||
katze_item_image_destroyed_cb (GtkWidget* image,
|
||||
KatzeItem* item)
|
||||
{
|
||||
#ifndef HAVE_WEBKIT2
|
||||
#if WEBKIT_CHECK_VERSION (1, 8, 0)
|
||||
g_signal_handlers_disconnect_by_func (webkit_get_favicon_database (),
|
||||
katze_item_icon_loaded_cb, image);
|
||||
#elif WEBKIT_CHECK_VERSION (1, 3, 13)
|
||||
g_signal_handlers_disconnect_by_func (webkit_get_icon_database (),
|
||||
katze_item_icon_loaded_cb, image);
|
||||
#endif
|
||||
#endif
|
||||
g_object_unref (item);
|
||||
}
|
||||
|
||||
/**
|
||||
* katze_item_get_image:
|
||||
* @item: a #KatzeItem
|
||||
* @widget: a #GtkWidget, or %NULL
|
||||
*
|
||||
* Retrieves a #GtkImage fit to display @item.
|
||||
*
|
||||
* Return value: the icon of the item
|
||||
*
|
||||
* Since: 0.4.4
|
||||
* Since 0.4.8 a @widget was added and the image is visible.
|
||||
**/
|
||||
GtkWidget*
|
||||
katze_item_get_image (KatzeItem* item,
|
||||
GtkWidget* widget)
|
||||
{
|
||||
GtkWidget* image;
|
||||
GdkPixbuf* pixbuf;
|
||||
|
||||
g_return_val_if_fail (KATZE_IS_ITEM (item), NULL);
|
||||
|
||||
pixbuf = katze_item_get_pixbuf (item, widget);
|
||||
image = gtk_image_new_from_pixbuf (pixbuf);
|
||||
gtk_widget_show (image);
|
||||
if (pixbuf != NULL)
|
||||
g_object_unref (pixbuf);
|
||||
if (KATZE_ITEM_IS_FOLDER (item))
|
||||
return image;
|
||||
g_object_set_data (G_OBJECT (image), "KatzeItem", g_object_ref (item));
|
||||
g_signal_connect (image, "destroy",
|
||||
G_CALLBACK (katze_item_image_destroyed_cb), item);
|
||||
#ifndef HAVE_WEBKIT2
|
||||
#if WEBKIT_CHECK_VERSION (1, 8, 0)
|
||||
g_signal_connect (webkit_get_favicon_database (), "icon-loaded",
|
||||
G_CALLBACK (katze_item_icon_loaded_cb), image);
|
||||
#elif WEBKIT_CHECK_VERSION (1, 3, 13)
|
||||
g_signal_connect (webkit_get_icon_database (), "icon-loaded",
|
||||
G_CALLBACK (katze_item_icon_loaded_cb), image);
|
||||
#endif
|
||||
#endif
|
||||
return image;
|
||||
}
|
||||
|
||||
/**
|
||||
* katze_item_get_token:
|
||||
* @item: a #KatzeItem
|
||||
|
@ -527,17 +653,22 @@ katze_item_set_meta_data_value (KatzeItem* item,
|
|||
* Return value: a string, or %NULL
|
||||
*
|
||||
* Since: 0.1.8
|
||||
*
|
||||
* Since 0.4.4 "" is treated like %NULL.
|
||||
**/
|
||||
const gchar*
|
||||
katze_item_get_meta_string (KatzeItem* item,
|
||||
const gchar* key)
|
||||
{
|
||||
const gchar* value;
|
||||
|
||||
g_return_val_if_fail (KATZE_IS_ITEM (item), NULL);
|
||||
g_return_val_if_fail (key != NULL, NULL);
|
||||
|
||||
if (g_str_has_prefix (key, "midori:"))
|
||||
key = &key[7];
|
||||
return g_hash_table_lookup (item->metadata, key);
|
||||
value = g_hash_table_lookup (item->metadata, key);
|
||||
return value && *value ? value : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#ifndef __KATZE_ITEM_H__
|
||||
#define __KATZE_ITEM_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
@ -91,6 +91,14 @@ void
|
|||
katze_item_set_icon (KatzeItem* item,
|
||||
const gchar* icon);
|
||||
|
||||
GdkPixbuf*
|
||||
katze_item_get_pixbuf (KatzeItem* item,
|
||||
GtkWidget* widget);
|
||||
|
||||
GtkWidget*
|
||||
katze_item_get_image (KatzeItem* item,
|
||||
GtkWidget* widget);
|
||||
|
||||
const gchar*
|
||||
katze_item_get_token (KatzeItem* item);
|
||||
|
||||
|
|
|
@ -22,14 +22,10 @@
|
|||
|
||||
#include <glib/gstdio.h>
|
||||
#include <libsoup/soup.h>
|
||||
#include <webkit/webkit.h>
|
||||
|
||||
struct _KatzeNet
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
gchar* cache_path;
|
||||
guint cache_size;
|
||||
};
|
||||
|
||||
struct _KatzeNetClass
|
||||
|
@ -54,37 +50,14 @@ katze_net_class_init (KatzeNetClass* class)
|
|||
static void
|
||||
katze_net_init (KatzeNet* net)
|
||||
{
|
||||
net->cache_path = g_build_filename (g_get_user_cache_dir (),
|
||||
PACKAGE_NAME, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
katze_net_finalize (GObject* object)
|
||||
{
|
||||
KatzeNet* net = KATZE_NET (object);
|
||||
|
||||
katze_assign (net->cache_path, NULL);
|
||||
|
||||
G_OBJECT_CLASS (katze_net_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static KatzeNet*
|
||||
katze_net_new (void)
|
||||
{
|
||||
static KatzeNet* net = NULL;
|
||||
|
||||
if (!net)
|
||||
{
|
||||
net = g_object_new (KATZE_TYPE_NET, NULL);
|
||||
/* Since this is a "singleton", keep an extra reference */
|
||||
g_object_ref (net);
|
||||
}
|
||||
else
|
||||
g_object_ref (net);
|
||||
|
||||
return net;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
KatzeNetStatusCb status_cb;
|
||||
|
@ -104,36 +77,40 @@ katze_net_priv_free (KatzeNetPriv* priv)
|
|||
g_slice_free (KatzeNetPriv, priv);
|
||||
}
|
||||
|
||||
#if !WEBKIT_CHECK_VERSION (1, 3, 13)
|
||||
gchar*
|
||||
katze_net_get_cached_path (KatzeNet* net,
|
||||
const gchar* uri,
|
||||
const gchar* subfolder)
|
||||
{
|
||||
gchar* cache_path;
|
||||
gchar* checksum;
|
||||
gchar* extension;
|
||||
gchar* cached_filename;
|
||||
gchar* cached_path;
|
||||
|
||||
net = katze_net_new ();
|
||||
if (uri == NULL)
|
||||
return NULL;
|
||||
|
||||
if (subfolder)
|
||||
cache_path = g_build_filename (net->cache_path, subfolder, NULL);
|
||||
else
|
||||
cache_path = net->cache_path;
|
||||
katze_mkdir_with_parents (cache_path, 0700);
|
||||
checksum = g_compute_checksum_for_string (G_CHECKSUM_MD5, uri, -1);
|
||||
|
||||
extension = g_strrstr (uri, ".");
|
||||
cached_filename = g_strdup_printf ("%s%s", checksum,
|
||||
extension ? extension : "");
|
||||
g_free (checksum);
|
||||
cached_path = g_build_filename (cache_path, cached_filename, NULL);
|
||||
g_free (cached_filename);
|
||||
|
||||
if (subfolder)
|
||||
{
|
||||
gchar* cache_path = g_build_filename (midori_paths_get_cache_dir_for_reading (), subfolder, NULL);
|
||||
katze_mkdir_with_parents (cache_path, 0700);
|
||||
cached_path = g_build_filename (cache_path, cached_filename, NULL);
|
||||
g_free (cache_path);
|
||||
}
|
||||
else
|
||||
cached_path = g_build_filename (midori_paths_get_cache_dir (), cached_filename, NULL);
|
||||
|
||||
g_free (cached_filename);
|
||||
return cached_path;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
katze_net_got_body_cb (SoupMessage* msg,
|
||||
|
@ -143,6 +120,7 @@ static void
|
|||
katze_net_got_headers_cb (SoupMessage* msg,
|
||||
KatzeNetPriv* priv)
|
||||
{
|
||||
#ifndef HAVE_WEBKIT2
|
||||
KatzeNetRequest* request = priv->request;
|
||||
|
||||
switch (msg->status_code)
|
||||
|
@ -163,6 +141,7 @@ katze_net_got_headers_cb (SoupMessage* msg,
|
|||
g_signal_handlers_disconnect_by_func (msg, katze_net_got_body_cb, priv);
|
||||
soup_session_cancel_message (webkit_get_default_session (), msg, 1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -264,6 +243,7 @@ katze_net_load_uri (KatzeNet* net,
|
|||
KatzeNetTransferCb transfer_cb,
|
||||
gpointer user_data)
|
||||
{
|
||||
#ifndef HAVE_WEBKIT2
|
||||
KatzeNetRequest* request;
|
||||
KatzeNetPriv* priv;
|
||||
SoupMessage* msg;
|
||||
|
@ -303,5 +283,6 @@ katze_net_load_uri (KatzeNet* net,
|
|||
g_idle_add ((GSourceFunc)katze_net_local_cb, priv);
|
||||
else
|
||||
g_idle_add ((GSourceFunc)katze_net_default_cb, priv);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -12,10 +12,13 @@
|
|||
#ifndef __KATZE_NET_H__
|
||||
#define __KATZE_NET_H__
|
||||
|
||||
#ifndef HAVE_WEBKIT2
|
||||
#include <webkit/webkit.h>
|
||||
#else
|
||||
#include <webkit2/webkit2.h>
|
||||
#endif
|
||||
#include "katze-utils.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define KATZE_TYPE_NET \
|
||||
|
@ -68,10 +71,12 @@ katze_net_load_uri (KatzeNet* net,
|
|||
KatzeNetTransferCb transfer_cb,
|
||||
gpointer user_data);
|
||||
|
||||
#if !WEBKIT_CHECK_VERSION (1, 3, 13)
|
||||
gchar*
|
||||
katze_net_get_cached_path (KatzeNet* net,
|
||||
const gchar* uri,
|
||||
const gchar* subfolder);
|
||||
#endif
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
|
|
@ -15,9 +15,11 @@
|
|||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_HILDON
|
||||
#include "katze-scrolled.h"
|
||||
#include <hildon/hildon.h>
|
||||
#ifdef HAVE_GRANITE
|
||||
#if HAVE_OSX
|
||||
#error FIXME granite on OSX is not implemented
|
||||
#endif
|
||||
#include <granite.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
@ -25,13 +27,6 @@
|
|||
|
||||
struct _KatzePreferencesPrivate
|
||||
{
|
||||
#if HAVE_HILDON
|
||||
GtkWidget* scrolled;
|
||||
GtkSizeGroup* sizegroup;
|
||||
GtkSizeGroup* sizegroup2;
|
||||
GtkWidget* box;
|
||||
GtkWidget* hbox;
|
||||
#else
|
||||
GtkWidget* notebook;
|
||||
GtkWidget* toolbar;
|
||||
GtkWidget* toolbutton;
|
||||
|
@ -41,7 +36,6 @@ struct _KatzePreferencesPrivate
|
|||
GtkWidget* frame;
|
||||
GtkWidget* box;
|
||||
GtkWidget* hbox;
|
||||
#endif
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (KatzePreferences, katze_preferences, GTK_TYPE_DIALOG);
|
||||
|
@ -66,19 +60,6 @@ katze_preferences_response_cb (KatzePreferences* preferences,
|
|||
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)
|
||||
{
|
||||
|
@ -103,18 +84,11 @@ katze_preferences_init (KatzePreferences* preferences)
|
|||
gtk_dialog_add_buttons (GTK_DIALOG (preferences),
|
||||
GTK_STOCK_HELP, GTK_RESPONSE_HELP,
|
||||
NULL);
|
||||
#if GTK_CHECK_VERSION (3, 0, 0)
|
||||
gtk_style_context_add_class (gtk_widget_get_style_context (
|
||||
gtk_dialog_get_widget_for_response (GTK_DIALOG (preferences),
|
||||
GTK_RESPONSE_HELP)), "help_button");
|
||||
#endif
|
||||
katze_widget_add_class (gtk_dialog_get_widget_for_response (
|
||||
GTK_DIALOG (preferences), GTK_RESPONSE_HELP), "help_button");
|
||||
|
||||
gtk_dialog_add_buttons (GTK_DIALOG (preferences),
|
||||
#if HAVE_HILDON
|
||||
GTK_STOCK_SAVE, GTK_RESPONSE_APPLY,
|
||||
#else
|
||||
GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
|
||||
#endif
|
||||
NULL);
|
||||
#endif
|
||||
|
||||
|
@ -122,12 +96,6 @@ katze_preferences_init (KatzePreferences* 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
|
||||
|
@ -183,26 +151,12 @@ 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_get_content_area (GTK_DIALOG (preferences))),
|
||||
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);
|
||||
#ifdef HAVE_GRANITE
|
||||
/* FIXME: granite: should return GtkWidget* like GTK+ */
|
||||
priv->notebook = (GtkWidget*)granite_widgets_static_notebook_new (FALSE);
|
||||
#else
|
||||
priv->notebook = gtk_notebook_new ();
|
||||
#endif
|
||||
gtk_container_set_border_width (GTK_CONTAINER (priv->notebook), 6);
|
||||
|
||||
#if HAVE_OSX
|
||||
|
@ -229,7 +183,6 @@ katze_preferences_prepare (KatzePreferences* preferences)
|
|||
|
||||
g_signal_connect (priv->notebook, "destroy",
|
||||
G_CALLBACK (gtk_widget_destroyed), &priv->notebook);
|
||||
#endif
|
||||
|
||||
#if HAVE_OSX
|
||||
GtkWidget* icon;
|
||||
|
@ -271,24 +224,6 @@ katze_preferences_add_category (KatzePreferences* preferences,
|
|||
|
||||
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);
|
||||
|
||||
|
@ -296,8 +231,14 @@ katze_preferences_add_category (KatzePreferences* preferences,
|
|||
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);
|
||||
#ifdef HAVE_GRANITE
|
||||
granite_widgets_static_notebook_append_page (
|
||||
GRANITE_WIDGETS_STATIC_NOTEBOOK (priv->notebook),
|
||||
priv->page, GTK_LABEL (gtk_label_new (label)));
|
||||
#else
|
||||
gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook),
|
||||
priv->page, gtk_label_new (label));
|
||||
#endif
|
||||
#if HAVE_OSX
|
||||
priv->toolbutton = GTK_WIDGET (priv->toolbutton ?
|
||||
gtk_radio_tool_button_new_from_widget (
|
||||
|
@ -313,12 +254,10 @@ katze_preferences_add_category (KatzePreferences* preferences,
|
|||
if (priv->toolbutton)
|
||||
g_object_set_data (G_OBJECT (priv->toolbutton), "notebook", priv->notebook);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return priv->page;
|
||||
}
|
||||
|
||||
#if !HAVE_HILDON
|
||||
static GtkWidget*
|
||||
katze_hig_frame_new (const gchar* title)
|
||||
{
|
||||
|
@ -336,7 +275,6 @@ katze_hig_frame_new (const gchar* title)
|
|||
#endif
|
||||
return frame;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* katze_preferences_add_group:
|
||||
|
@ -353,7 +291,6 @@ void
|
|||
katze_preferences_add_group (KatzePreferences* preferences,
|
||||
const gchar* label)
|
||||
{
|
||||
#if !HAVE_HILDON
|
||||
KatzePreferencesPrivate* priv;
|
||||
|
||||
g_return_if_fail (KATZE_IS_PREFERENCES (preferences));
|
||||
|
@ -368,7 +305,6 @@ katze_preferences_add_group (KatzePreferences* preferences,
|
|||
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
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -402,10 +338,6 @@ katze_preferences_add_widget (KatzePreferences* preferences,
|
|||
|
||||
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"))
|
||||
{
|
||||
|
@ -421,11 +353,7 @@ katze_preferences_add_widget (KatzePreferences* preferences,
|
|||
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);
|
||||
}
|
||||
|
@ -439,9 +367,4 @@ katze_preferences_add_widget (KatzePreferences* preferences,
|
|||
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
|
||||
}
|
||||
|
|
|
@ -1,906 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2007 Henrik Hedberg <hhedberg@innologies.fi>
|
||||
Copyright (C) 2009 Nadav Wiener <nadavwr@yahoo.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
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "katze-scrolled.h"
|
||||
#include "katze-utils.h"
|
||||
|
||||
#define DEFAULT_INTERVAL 50
|
||||
#define DEFAULT_DECELERATION 0.7
|
||||
#define DEFAULT_DRAGGING_STOPPED_DELAY 100
|
||||
|
||||
/**
|
||||
* SECTION:katze-scrolled
|
||||
* @short_description: Implements drag scrolling and kinetic scrolling
|
||||
* @see_also: #GtkScrolledWindow
|
||||
*
|
||||
* A scrolled window derived from #GtkScrolledWindow that implements
|
||||
* drag scrolling and kinetic scrolling. Can be used as a drop-in replacement
|
||||
* for the existing #GtkScrolledWindow.
|
||||
*
|
||||
* If a direct child of the #KatzeScrolled has its own window
|
||||
* (InputOnly is enough for events), it is automatically activated when added
|
||||
* as a child. All motion events in that area will be used to scroll.
|
||||
*
|
||||
* If some descendant widgets capture button press, button release and/ or
|
||||
* motion nofity events, the user can not scroll the area by pressing those
|
||||
* widgets (unless the widget is activated). #GtkButton is a typical example
|
||||
* of that. Usually that is the desired behaviour.
|
||||
*
|
||||
* Any widget can be registered to provide pointer events for the
|
||||
* #KatzeScrolled by using the
|
||||
* #katze_scrolled_activate_scrolling function.
|
||||
*
|
||||
**/
|
||||
|
||||
G_DEFINE_TYPE (KatzeScrolled, katze_scrolled, GTK_TYPE_SCROLLED_WINDOW);
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
|
||||
PROP_DRAG_SCROLLING,
|
||||
PROP_KINETIC_SCROLLING
|
||||
};
|
||||
|
||||
static void
|
||||
katze_scrolled_set_property (GObject* object,
|
||||
guint prop_id,
|
||||
const GValue* value,
|
||||
GParamSpec* pspec);
|
||||
|
||||
static void
|
||||
katze_scrolled_get_property (GObject* object,
|
||||
guint prop_id,
|
||||
GValue* value,
|
||||
GParamSpec* pspec);
|
||||
|
||||
static void
|
||||
katze_scrolled_dispose (GObject* object);
|
||||
|
||||
static void
|
||||
katze_scrolled_activate_scrolling (KatzeScrolled* scrolled,
|
||||
GtkWidget* widget);
|
||||
|
||||
static void
|
||||
katze_scrolled_set_drag_scrolling (KatzeScrolled* scrolled,
|
||||
gboolean drag_scrolling);
|
||||
|
||||
struct _KatzeScrolledPrivate
|
||||
{
|
||||
/* Settings */
|
||||
guint interval;
|
||||
gdouble deceleration;
|
||||
gboolean drag_scrolling;
|
||||
gboolean kinetic_scrolling;
|
||||
guint32 dragging_stopped_delay;
|
||||
gboolean scrolling_hints;
|
||||
|
||||
/* Temporary variables */
|
||||
gboolean dragged;
|
||||
gboolean press_received;
|
||||
GdkWindow* synthetic_crossing_event_window;
|
||||
|
||||
/* Disabling twice happening scrolling adjustment */
|
||||
GtkAdjustment* hadjustment;
|
||||
GtkWidget* viewport;
|
||||
|
||||
/* Motion scrolling */
|
||||
gint start_x;
|
||||
gint start_y;
|
||||
gint previous_x;
|
||||
gint previous_y;
|
||||
gint farest_x;
|
||||
gint farest_y;
|
||||
guint32 start_time;
|
||||
guint32 previous_time;
|
||||
guint32 farest_time;
|
||||
gboolean going_right;
|
||||
gboolean going_down;
|
||||
|
||||
/* Kinetic scrolling */
|
||||
guint scrolling_timeout_id;
|
||||
gdouble horizontal_speed;
|
||||
gdouble vertical_speed;
|
||||
gdouble horizontal_deceleration;
|
||||
gdouble vertical_deceleration;
|
||||
};
|
||||
|
||||
typedef struct _KatzeScrolledState KatzeScrolledState;
|
||||
typedef gboolean (*KatzeScrolledEventHandler)(GdkEvent* event,
|
||||
KatzeScrolledState* state,
|
||||
gpointer user_data);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
KatzeScrolledEventHandler event_handler;
|
||||
gpointer user_data;
|
||||
} EventHandlerData;
|
||||
|
||||
struct _KatzeScrolledState
|
||||
{
|
||||
GList* current_event_handler;
|
||||
};
|
||||
|
||||
static GList* event_handlers = NULL;
|
||||
|
||||
static void
|
||||
katze_scrolled_event_handler_func (GdkEvent* event,
|
||||
gpointer data);
|
||||
|
||||
static void
|
||||
katze_scrolled_event_handler_append (KatzeScrolledEventHandler event_handler,
|
||||
gpointer user_data)
|
||||
{
|
||||
EventHandlerData* data;
|
||||
|
||||
data = g_new0 (EventHandlerData, 1);
|
||||
data->event_handler = event_handler;
|
||||
data->user_data = user_data;
|
||||
event_handlers = g_list_append (event_handlers, data);
|
||||
|
||||
gdk_event_handler_set ((GdkEventFunc)katze_scrolled_event_handler_func, NULL, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
katze_scrolled_event_handler_next (GdkEvent* event,
|
||||
KatzeScrolledState* state)
|
||||
{
|
||||
EventHandlerData* data;
|
||||
gboolean stop_propagating;
|
||||
|
||||
state->current_event_handler = g_list_next (state->current_event_handler);
|
||||
if (state->current_event_handler)
|
||||
{
|
||||
data = (EventHandlerData*)state->current_event_handler->data;
|
||||
stop_propagating = data->event_handler (event, state, data->user_data);
|
||||
if (!stop_propagating && state->current_event_handler)
|
||||
g_critical ("%s: handler returned FALSE without calling %s first",
|
||||
G_STRFUNC, G_STRFUNC);
|
||||
}
|
||||
else
|
||||
gtk_main_do_event (event);
|
||||
}
|
||||
|
||||
static void
|
||||
katze_scrolled_event_handler_func (GdkEvent* event,
|
||||
gpointer user_data)
|
||||
{
|
||||
KatzeScrolledState* state;
|
||||
EventHandlerData* data;
|
||||
gboolean stop_propagating;
|
||||
|
||||
state = g_slice_new (KatzeScrolledState);
|
||||
state->current_event_handler = g_list_first (event_handlers);
|
||||
if (state->current_event_handler)
|
||||
{
|
||||
data = (EventHandlerData*)state->current_event_handler->data;
|
||||
stop_propagating = data->event_handler (event, state, data->user_data);
|
||||
if (!stop_propagating && state->current_event_handler)
|
||||
g_critical ("%s: handler returned FALSE without calling %s first",
|
||||
G_STRFUNC, "katze_scrolled_event_handler_next");
|
||||
}
|
||||
else
|
||||
gtk_main_do_event (event);
|
||||
|
||||
g_slice_free (KatzeScrolledState, state);
|
||||
}
|
||||
|
||||
static GdkWindow* current_gdk_window;
|
||||
static KatzeScrolled* current_scrolled_window;
|
||||
static GtkWidget* current_widget;
|
||||
static gboolean synthetized_crossing_event;
|
||||
|
||||
static GTree* activated_widgets;
|
||||
|
||||
static gint
|
||||
compare_pointers (gconstpointer a,
|
||||
gconstpointer b)
|
||||
{
|
||||
return a - b;
|
||||
}
|
||||
|
||||
static void
|
||||
disable_hadjustment (KatzeScrolled* scrolled)
|
||||
{
|
||||
KatzeScrolledPrivate* priv = scrolled->priv;
|
||||
GtkAdjustment* hadjustment;
|
||||
GtkWidget* viewport;
|
||||
|
||||
if ((hadjustment = gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (scrolled)))
|
||||
&& priv->hadjustment != hadjustment)
|
||||
{
|
||||
priv->hadjustment = hadjustment;
|
||||
priv->viewport = NULL;
|
||||
viewport = GTK_WIDGET (scrolled);
|
||||
while (GTK_IS_BIN (viewport))
|
||||
{
|
||||
viewport = gtk_bin_get_child (GTK_BIN (viewport));
|
||||
if (GTK_IS_VIEWPORT (viewport))
|
||||
{
|
||||
priv->viewport = viewport;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
g_signal_handlers_block_matched (priv->hadjustment, G_SIGNAL_MATCH_DATA,
|
||||
0, 0, 0, 0, priv->viewport);
|
||||
}
|
||||
|
||||
static void
|
||||
enable_hadjustment (KatzeScrolled* scrolled)
|
||||
{
|
||||
KatzeScrolledPrivate* priv = scrolled->priv;
|
||||
|
||||
g_signal_handlers_unblock_matched (priv->hadjustment, G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, priv->viewport);
|
||||
}
|
||||
|
||||
static gdouble
|
||||
calculate_timeout_scroll_values (gdouble old_value,
|
||||
gdouble upper_limit,
|
||||
gdouble* scrolling_speed_pointer,
|
||||
gdouble deceleration,
|
||||
gdouble* other_deceleration,
|
||||
gdouble normal_deceleration)
|
||||
{
|
||||
gdouble new_value = old_value;
|
||||
|
||||
if (*scrolling_speed_pointer > deceleration ||
|
||||
*scrolling_speed_pointer < -deceleration)
|
||||
{
|
||||
if (old_value + *scrolling_speed_pointer <= 0.0)
|
||||
{
|
||||
new_value = -1.0;
|
||||
*scrolling_speed_pointer = 0.0;
|
||||
*other_deceleration = normal_deceleration;
|
||||
}
|
||||
else if (old_value + *scrolling_speed_pointer >= upper_limit)
|
||||
{
|
||||
new_value = upper_limit;
|
||||
*scrolling_speed_pointer = 0.0;
|
||||
*other_deceleration = normal_deceleration;
|
||||
}
|
||||
else
|
||||
new_value = old_value + *scrolling_speed_pointer;
|
||||
if (*scrolling_speed_pointer > deceleration)
|
||||
*scrolling_speed_pointer -= deceleration;
|
||||
else if (*scrolling_speed_pointer < -deceleration)
|
||||
*scrolling_speed_pointer += deceleration;
|
||||
}
|
||||
|
||||
return new_value;
|
||||
}
|
||||
|
||||
static void
|
||||
do_timeout_scroll (KatzeScrolled* scrolled)
|
||||
{
|
||||
KatzeScrolledPrivate* priv = scrolled->priv;
|
||||
GtkScrolledWindow* gtk_scrolled = GTK_SCROLLED_WINDOW (scrolled);
|
||||
GtkAdjustment* hadjustment;
|
||||
GtkAdjustment* vadjustment;
|
||||
gdouble hpage_size, hupper, hvalue, new_hvalue;
|
||||
gdouble vpage_size, vupper, vvalue, new_vvalue;
|
||||
|
||||
hadjustment = gtk_scrolled_window_get_hadjustment (gtk_scrolled);
|
||||
hpage_size = gtk_adjustment_get_page_size (hadjustment);
|
||||
hupper = gtk_adjustment_get_upper (hadjustment);
|
||||
hvalue = gtk_adjustment_get_value (hadjustment);
|
||||
new_hvalue = calculate_timeout_scroll_values (hvalue,
|
||||
hupper - hpage_size,
|
||||
&priv->horizontal_speed,
|
||||
priv->horizontal_deceleration,
|
||||
&priv->vertical_deceleration,
|
||||
priv->deceleration);
|
||||
|
||||
vadjustment = gtk_scrolled_window_get_vadjustment (gtk_scrolled);
|
||||
vpage_size = gtk_adjustment_get_page_size (vadjustment);
|
||||
vupper = gtk_adjustment_get_upper (vadjustment);
|
||||
vvalue = gtk_adjustment_get_value (vadjustment);
|
||||
new_vvalue = calculate_timeout_scroll_values (vvalue,
|
||||
vupper - vpage_size,
|
||||
&priv->vertical_speed,
|
||||
priv->vertical_deceleration,
|
||||
&priv->horizontal_deceleration,
|
||||
priv->deceleration);
|
||||
|
||||
if (new_vvalue != vvalue)
|
||||
{
|
||||
if (new_hvalue != hvalue)
|
||||
{
|
||||
disable_hadjustment (scrolled);
|
||||
gtk_adjustment_set_value (hadjustment, new_hvalue);
|
||||
enable_hadjustment (scrolled);
|
||||
}
|
||||
gtk_adjustment_set_value (vadjustment, new_vvalue);
|
||||
}
|
||||
else if (new_hvalue != hvalue)
|
||||
gtk_adjustment_set_value (hadjustment, new_hvalue);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
timeout_scroll (gpointer data)
|
||||
{
|
||||
gboolean ret = TRUE;
|
||||
KatzeScrolled* scrolled = KATZE_SCROLLED (data);
|
||||
KatzeScrolledPrivate* priv = scrolled->priv;
|
||||
|
||||
gdk_threads_enter ();
|
||||
do_timeout_scroll (scrolled);
|
||||
|
||||
if (priv->vertical_speed < priv->deceleration &&
|
||||
priv->vertical_speed > -priv->deceleration &&
|
||||
priv->horizontal_speed < priv->deceleration &&
|
||||
priv->horizontal_speed > -priv->deceleration)
|
||||
{
|
||||
priv->scrolling_timeout_id = 0;
|
||||
ret = FALSE;
|
||||
}
|
||||
gdk_threads_leave ();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gdouble
|
||||
calculate_motion_scroll_values (gdouble old_value,
|
||||
gdouble upper_limit,
|
||||
gint current_coordinate,
|
||||
gint previous_coordinate)
|
||||
{
|
||||
gdouble new_value = old_value;
|
||||
gint movement;
|
||||
|
||||
movement = current_coordinate - previous_coordinate;
|
||||
|
||||
if (old_value - movement < upper_limit)
|
||||
new_value = old_value - movement;
|
||||
else
|
||||
new_value = upper_limit;
|
||||
|
||||
return new_value;
|
||||
}
|
||||
|
||||
static void
|
||||
do_motion_scroll (KatzeScrolled* scrolled,
|
||||
GtkWidget* widget,
|
||||
gint x,
|
||||
gint y,
|
||||
guint32 timestamp)
|
||||
{
|
||||
KatzeScrolledPrivate* priv = scrolled->priv;
|
||||
|
||||
if (priv->dragged || gtk_drag_check_threshold (widget, priv->start_x, priv->start_y, x, y))
|
||||
{
|
||||
GtkAdjustment* hadjustment;
|
||||
GtkAdjustment* vadjustment;
|
||||
gdouble hpage_size, hupper, hvalue, new_hvalue;
|
||||
gdouble vpage_size, vupper, vvalue, new_vvalue;
|
||||
|
||||
if (timestamp - priv->previous_time > priv->dragging_stopped_delay || !priv->dragged)
|
||||
{
|
||||
priv->dragged = TRUE;
|
||||
priv->going_right = priv->start_x < x;
|
||||
priv->going_down = priv->start_y < y;
|
||||
priv->start_x = priv->farest_x = x;
|
||||
priv->start_y = priv->farest_y = y;
|
||||
priv->start_time = priv->farest_time = timestamp;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((priv->going_right && x > priv->farest_x)
|
||||
|| (!priv->going_right && x < priv->farest_x))
|
||||
{
|
||||
priv->farest_x = x;
|
||||
priv->farest_time = timestamp;
|
||||
}
|
||||
if ((priv->going_down && y > priv->farest_y)
|
||||
|| (!priv->going_down && y < priv->farest_y))
|
||||
{
|
||||
priv->farest_y = y;
|
||||
priv->farest_time = timestamp;
|
||||
}
|
||||
if (gtk_drag_check_threshold (widget, priv->farest_x, priv->farest_y, x, y))
|
||||
{
|
||||
priv->start_x = priv->farest_x;
|
||||
priv->farest_x = x;
|
||||
priv->start_y = priv->farest_y;
|
||||
priv->farest_y = y;
|
||||
priv->start_time = priv->farest_time;
|
||||
priv->farest_time = timestamp;
|
||||
priv->going_right = priv->start_x < x;
|
||||
priv->going_down = priv->start_y < y;
|
||||
}
|
||||
}
|
||||
|
||||
hadjustment = gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (scrolled));
|
||||
hpage_size = gtk_adjustment_get_page_size (hadjustment);
|
||||
hupper = gtk_adjustment_get_upper (hadjustment);
|
||||
hvalue = gtk_adjustment_get_value (hadjustment);
|
||||
new_hvalue = calculate_motion_scroll_values (hvalue,
|
||||
hupper - hpage_size, x, priv->previous_x);
|
||||
|
||||
vadjustment = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (scrolled));
|
||||
vpage_size = gtk_adjustment_get_page_size (vadjustment);
|
||||
vupper = gtk_adjustment_get_upper (vadjustment);
|
||||
vvalue = gtk_adjustment_get_value (vadjustment);
|
||||
new_vvalue = calculate_motion_scroll_values (vvalue,
|
||||
vupper - vpage_size, y, priv->previous_y);
|
||||
if (new_vvalue != vvalue)
|
||||
{
|
||||
if (new_hvalue != hvalue)
|
||||
{
|
||||
disable_hadjustment (scrolled);
|
||||
gtk_adjustment_set_value (hadjustment, new_hvalue);
|
||||
enable_hadjustment (scrolled);
|
||||
}
|
||||
gtk_adjustment_set_value (vadjustment, new_vvalue);
|
||||
}
|
||||
else if (new_hvalue != hvalue)
|
||||
gtk_adjustment_set_value (hadjustment, new_hvalue);
|
||||
}
|
||||
|
||||
priv->previous_y = y;
|
||||
priv->previous_x = x;
|
||||
priv->previous_time = timestamp;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
button_press_event (GtkWidget* widget,
|
||||
GdkEventButton* event,
|
||||
KatzeScrolled* scrolled)
|
||||
{
|
||||
KatzeScrolledPrivate* priv = scrolled->priv;
|
||||
gint x;
|
||||
gint y;
|
||||
GdkModifierType mask;
|
||||
|
||||
if (!priv->drag_scrolling || event->button != 1)
|
||||
return FALSE;
|
||||
|
||||
priv->press_received = TRUE;
|
||||
gdk_window_get_pointer (gtk_widget_get_window (GTK_WIDGET (scrolled)),
|
||||
&x, &y, &mask);
|
||||
if (event->time - priv->previous_time < priv->dragging_stopped_delay &&
|
||||
gtk_drag_check_threshold (widget, priv->previous_x, priv->previous_y, x, y))
|
||||
{
|
||||
if (priv->scrolling_timeout_id)
|
||||
{
|
||||
g_source_remove (priv->scrolling_timeout_id);
|
||||
priv->scrolling_timeout_id = 0;
|
||||
}
|
||||
/* do_motion_scroll (scrolled, widget, x, y, event->time); */
|
||||
}
|
||||
else
|
||||
{
|
||||
if (priv->scrolling_timeout_id)
|
||||
{
|
||||
g_source_remove (priv->scrolling_timeout_id);
|
||||
priv->scrolling_timeout_id = 0;
|
||||
priv->previous_time = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
priv->dragged = FALSE;
|
||||
priv->previous_time = event->time;
|
||||
}
|
||||
priv->start_x = priv->previous_x = priv->farest_x = x;
|
||||
priv->start_y = priv->previous_y = priv->farest_y = y;
|
||||
priv->start_time = event->time;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
button_release_event (GtkWidget* widget,
|
||||
GdkEventButton* event,
|
||||
KatzeScrolled* scrolled)
|
||||
{
|
||||
KatzeScrolledPrivate* priv = scrolled->priv;
|
||||
gint x;
|
||||
gint y;
|
||||
GdkModifierType mask;
|
||||
|
||||
gdk_window_get_pointer (gtk_widget_get_window (GTK_WIDGET (scrolled)),
|
||||
&x, &y, &mask);
|
||||
if (priv->press_received &&
|
||||
gtk_drag_check_threshold (widget, priv->start_x, priv->start_y, x, y)) {
|
||||
priv->dragged = TRUE;
|
||||
}
|
||||
|
||||
if (priv->press_received && priv->kinetic_scrolling &&
|
||||
event->time - priv->previous_time < priv->dragging_stopped_delay) {
|
||||
priv->vertical_speed = (gdouble)(priv->start_y - y) / (event->time - priv->start_time) * priv->interval;
|
||||
priv->horizontal_speed = (gdouble)(priv->start_x - x) / (event->time - priv->start_time) * priv->interval;
|
||||
if (ABS (priv->vertical_speed) > ABS (priv->horizontal_speed)) {
|
||||
priv->vertical_deceleration = priv->deceleration;
|
||||
priv->horizontal_deceleration = priv->deceleration * ABS (priv->horizontal_speed / priv->vertical_speed);
|
||||
} else {
|
||||
priv->horizontal_deceleration = priv->deceleration;
|
||||
priv->vertical_deceleration = priv->deceleration * ABS (priv->vertical_speed / priv->horizontal_speed);
|
||||
}
|
||||
priv->scrolling_timeout_id = g_timeout_add (priv->interval, timeout_scroll, scrolled);
|
||||
|
||||
do_timeout_scroll (scrolled);
|
||||
}
|
||||
priv->previous_x = x;
|
||||
priv->previous_y = y;
|
||||
priv->previous_time = event->time;
|
||||
|
||||
priv->press_received = FALSE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
motion_notify_event (GtkWidget* widget,
|
||||
GdkEventMotion* event,
|
||||
KatzeScrolled* scrolled)
|
||||
{
|
||||
KatzeScrolledPrivate* priv = scrolled->priv;
|
||||
gint x;
|
||||
gint y;
|
||||
GdkModifierType mask;
|
||||
|
||||
if (priv->press_received)
|
||||
{
|
||||
gdk_window_get_pointer (gtk_widget_get_window (GTK_WIDGET (scrolled)),
|
||||
&x, &y, &mask);
|
||||
do_motion_scroll (scrolled, widget, x, y, event->time);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
katze_scrolled_event_handler (GdkEvent* event,
|
||||
KatzeScrolledState* state,
|
||||
gpointer user_data)
|
||||
{
|
||||
gboolean stop_propagating;
|
||||
GdkEventCrossing crossing;
|
||||
|
||||
stop_propagating = FALSE;
|
||||
|
||||
if (event->type == GDK_BUTTON_PRESS)
|
||||
{
|
||||
gdk_window_get_user_data (event->button.window, (gpointer)¤t_widget);
|
||||
|
||||
if ((current_scrolled_window = g_tree_lookup (activated_widgets, current_widget)))
|
||||
{
|
||||
current_gdk_window = event->button.window;
|
||||
stop_propagating = button_press_event (current_widget, &event->button, current_scrolled_window);
|
||||
}
|
||||
else
|
||||
current_gdk_window = NULL;
|
||||
}
|
||||
else if (event->any.window == current_gdk_window)
|
||||
{
|
||||
if (event->type == GDK_MOTION_NOTIFY)
|
||||
{
|
||||
if (current_scrolled_window->priv->dragged)
|
||||
stop_propagating = motion_notify_event (current_widget, &event->motion, current_scrolled_window);
|
||||
else
|
||||
{
|
||||
stop_propagating = motion_notify_event (current_widget, &event->motion, current_scrolled_window);
|
||||
if (current_scrolled_window->priv->dragged)
|
||||
{
|
||||
crossing.type = GDK_LEAVE_NOTIFY;
|
||||
crossing.window = event->motion.window;
|
||||
crossing.send_event = event->motion.send_event;
|
||||
crossing.subwindow = gtk_widget_get_window (
|
||||
GTK_WIDGET (current_scrolled_window));
|
||||
crossing.time = event->motion.time;
|
||||
crossing.x = event->motion.x;
|
||||
crossing.y = event->motion.y;
|
||||
crossing.x_root = event->motion.x_root;
|
||||
crossing.y_root = event->motion.y_root;
|
||||
crossing.mode = GDK_CROSSING_GRAB;
|
||||
crossing.detail = GDK_NOTIFY_ANCESTOR;
|
||||
crossing.focus = TRUE;
|
||||
crossing.state = event->motion.state;
|
||||
|
||||
gtk_main_do_event ((GdkEvent*)&crossing);
|
||||
synthetized_crossing_event = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((event->type == GDK_ENTER_NOTIFY || event->type == GDK_LEAVE_NOTIFY) &&
|
||||
synthetized_crossing_event)
|
||||
stop_propagating = TRUE;
|
||||
else if (event->type == GDK_BUTTON_RELEASE)
|
||||
stop_propagating = button_release_event (current_widget, &event->button, current_scrolled_window);
|
||||
}
|
||||
|
||||
if (!stop_propagating)
|
||||
katze_scrolled_event_handler_next (event, state);
|
||||
|
||||
if (event->type == GDK_BUTTON_RELEASE && event->button.window == current_gdk_window)
|
||||
{
|
||||
crossing.type = GDK_ENTER_NOTIFY;
|
||||
crossing.window = event->button.window;
|
||||
crossing.send_event = event->button.send_event;
|
||||
crossing.subwindow = gtk_widget_get_window (
|
||||
GTK_WIDGET (current_scrolled_window));
|
||||
crossing.time = event->button.time;
|
||||
crossing.x = event->button.x;
|
||||
crossing.y = event->button.y;
|
||||
crossing.x_root = event->button.x_root;
|
||||
crossing.y_root = event->button.y_root;
|
||||
crossing.mode = GDK_CROSSING_UNGRAB;
|
||||
crossing.detail = GDK_NOTIFY_ANCESTOR;
|
||||
crossing.focus = TRUE;
|
||||
crossing.state = event->button.state;
|
||||
|
||||
gtk_main_do_event ((GdkEvent*)&crossing);
|
||||
synthetized_crossing_event = FALSE;
|
||||
}
|
||||
|
||||
return stop_propagating;
|
||||
}
|
||||
|
||||
static void
|
||||
katze_scrolled_add (GtkContainer* container,
|
||||
GtkWidget* widget)
|
||||
{
|
||||
katze_scrolled_activate_scrolling (KATZE_SCROLLED (container), widget);
|
||||
|
||||
(*GTK_CONTAINER_CLASS (katze_scrolled_parent_class)->add) (container, widget);
|
||||
}
|
||||
|
||||
static void
|
||||
katze_scrolled_realize (GtkWidget* widget)
|
||||
{
|
||||
KatzeScrolled* scrolled = KATZE_SCROLLED (widget);
|
||||
gboolean drag_scrolling;
|
||||
GtkPolicyType policy;
|
||||
GdkWindow* window;
|
||||
GdkWindowAttr attr;
|
||||
|
||||
(*GTK_WIDGET_CLASS (katze_scrolled_parent_class)->realize) (widget);
|
||||
|
||||
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);
|
||||
|
||||
window = g_object_ref (gtk_widget_get_parent_window (widget));
|
||||
gtk_widget_set_window (widget, window);
|
||||
|
||||
attr.height = attr.width = 10;
|
||||
attr.event_mask = GDK_EXPOSURE_MASK;
|
||||
attr.wclass = GDK_INPUT_OUTPUT;
|
||||
attr.window_type = GDK_WINDOW_CHILD;
|
||||
attr.override_redirect = TRUE;
|
||||
|
||||
gtk_widget_set_realized (widget, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
katze_scrolled_dispose (GObject* object)
|
||||
{
|
||||
KatzeScrolled* scrolled = KATZE_SCROLLED (object);
|
||||
KatzeScrolledPrivate* priv = scrolled->priv;
|
||||
|
||||
if (priv->scrolling_timeout_id)
|
||||
{
|
||||
g_source_remove (priv->scrolling_timeout_id);
|
||||
priv->scrolling_timeout_id = 0;
|
||||
}
|
||||
|
||||
(*G_OBJECT_CLASS (katze_scrolled_parent_class)->dispose) (object);
|
||||
}
|
||||
|
||||
static void
|
||||
katze_scrolled_class_init (KatzeScrolledClass* class)
|
||||
{
|
||||
GObjectClass* gobject_class;
|
||||
GtkWidgetClass* widget_class;
|
||||
GtkContainerClass* container_class;
|
||||
GParamFlags flags = G_PARAM_READWRITE | G_PARAM_CONSTRUCT;
|
||||
|
||||
gobject_class = G_OBJECT_CLASS (class);
|
||||
widget_class = GTK_WIDGET_CLASS (class);
|
||||
container_class = GTK_CONTAINER_CLASS (class);
|
||||
|
||||
gobject_class->set_property = katze_scrolled_set_property;
|
||||
gobject_class->get_property = katze_scrolled_get_property;
|
||||
gobject_class->dispose = katze_scrolled_dispose;
|
||||
|
||||
widget_class->realize = katze_scrolled_realize;
|
||||
|
||||
container_class->add = katze_scrolled_add;
|
||||
|
||||
/**
|
||||
* KatzeScrolled:drag-scrolling:
|
||||
*
|
||||
* Whether the widget can be scrolled by dragging its contents.
|
||||
*
|
||||
* If "gtk-touchscreen-mode" is enabled, drag scrolling is
|
||||
* automatically enabled.
|
||||
*
|
||||
* Since: 0.2.0
|
||||
*/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_DRAG_SCROLLING,
|
||||
g_param_spec_boolean (
|
||||
"drag-scrolling",
|
||||
"Drag Scrolling",
|
||||
"Whether the widget can be scrolled by dragging its contents",
|
||||
FALSE,
|
||||
flags));
|
||||
|
||||
/**
|
||||
* KatzeScrolled:kinetic-scrolling:
|
||||
*
|
||||
* Whether drag scrolling is kinetic, that is releasing the
|
||||
* pointer keeps the contents scrolling further relative to
|
||||
* the speed with which they were dragged.
|
||||
*
|
||||
* Since: 0.2.0
|
||||
*/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_KINETIC_SCROLLING,
|
||||
g_param_spec_boolean (
|
||||
"kinetic-scrolling",
|
||||
"Kinetic Scrolling",
|
||||
"Whether drag scrolling is kinetic",
|
||||
TRUE,
|
||||
flags));
|
||||
|
||||
activated_widgets = g_tree_new ((GCompareFunc)compare_pointers);
|
||||
current_gdk_window = NULL;
|
||||
|
||||
/* 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 (katze_widget_has_touchscreen_mode (NULL))
|
||||
katze_scrolled_event_handler_append (katze_scrolled_event_handler, NULL);
|
||||
|
||||
g_type_class_add_private (class, sizeof (KatzeScrolledPrivate));
|
||||
}
|
||||
|
||||
static void
|
||||
katze_scrolled_init (KatzeScrolled* scrolled)
|
||||
{
|
||||
KatzeScrolledPrivate* priv;
|
||||
|
||||
scrolled->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE ((scrolled),
|
||||
KATZE_TYPE_SCROLLED, KatzeScrolledPrivate);
|
||||
|
||||
priv->interval = DEFAULT_INTERVAL;
|
||||
priv->deceleration = DEFAULT_DECELERATION;
|
||||
priv->drag_scrolling = FALSE;
|
||||
priv->kinetic_scrolling = TRUE;
|
||||
priv->dragging_stopped_delay = DEFAULT_DRAGGING_STOPPED_DELAY;
|
||||
}
|
||||
|
||||
static void
|
||||
katze_scrolled_set_property (GObject* object,
|
||||
guint prop_id,
|
||||
const GValue* value,
|
||||
GParamSpec* pspec)
|
||||
{
|
||||
KatzeScrolled* scrolled = KATZE_SCROLLED (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_DRAG_SCROLLING:
|
||||
katze_scrolled_set_drag_scrolling (scrolled, g_value_get_boolean (value));
|
||||
break;
|
||||
case PROP_KINETIC_SCROLLING:
|
||||
scrolled->priv->kinetic_scrolling = g_value_get_boolean (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
katze_scrolled_get_property (GObject* object,
|
||||
guint prop_id,
|
||||
GValue* value,
|
||||
GParamSpec* pspec)
|
||||
{
|
||||
KatzeScrolled* scrolled = KATZE_SCROLLED (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_DRAG_SCROLLING:
|
||||
g_value_set_boolean (value, scrolled->priv->drag_scrolling);
|
||||
break;
|
||||
case PROP_KINETIC_SCROLLING:
|
||||
g_value_set_boolean (value, scrolled->priv->kinetic_scrolling);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* katze_scrolled_new:
|
||||
* @hadjustment: a horizontal #GtkAdjustment, or %NULL
|
||||
* @vadjustment: a vertical #GtkAdjustment, or %NULL
|
||||
*
|
||||
* Creates a new #KatzeScrolled.
|
||||
*
|
||||
* Since: 0.2.0
|
||||
**/
|
||||
|
||||
GtkWidget*
|
||||
katze_scrolled_new (GtkAdjustment* hadjustment,
|
||||
GtkAdjustment* vadjustment)
|
||||
{
|
||||
if (hadjustment)
|
||||
g_return_val_if_fail (GTK_IS_ADJUSTMENT (hadjustment), NULL);
|
||||
if (vadjustment)
|
||||
g_return_val_if_fail (GTK_IS_ADJUSTMENT (vadjustment), NULL);
|
||||
|
||||
return gtk_widget_new (KATZE_TYPE_SCROLLED,
|
||||
"hadjustment", hadjustment,
|
||||
"vadjustment", vadjustment, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* katze_scrolled_activate_scrolling:
|
||||
* @scrolled: a #KatzeScrolled
|
||||
* @widget: a #GtkWidget of which area is made active event source for
|
||||
* drag and kinetic scrolling.
|
||||
*
|
||||
* Activates the widget so that pointer motion events inside the widget are
|
||||
* used to scroll the #KatzeScrolled. The widget can be a child of the
|
||||
* #KatzeScrolled or even a separate widget ("touchpad" style).
|
||||
*
|
||||
* The direct child of the #KatzeScrolled (typically #GtkViewport) is
|
||||
* activated automatically when added. This function has to be used if indirect
|
||||
* descendant widgets are stopping propagation of the button press and release
|
||||
* as well as motion events (for example GtkButton is doing so) but scrolling
|
||||
* should be possible inside their area too.
|
||||
*
|
||||
* This function adds #GDK_BUTTON_PRESS_MASK, #GDK_BUTTON_RELEASE_MASK,
|
||||
* #GDK_POINTER_MOTION_MASK, and #GDK_MOTION_HINT_MAKS into the widgets event mask.
|
||||
*/
|
||||
|
||||
static void
|
||||
katze_scrolled_activate_scrolling (KatzeScrolled* scrolled,
|
||||
GtkWidget* widget)
|
||||
{
|
||||
gtk_widget_add_events (widget,
|
||||
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
|
||||
| GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK);
|
||||
g_tree_insert (activated_widgets, widget, scrolled);
|
||||
}
|
||||
|
||||
static void
|
||||
katze_scrolled_set_drag_scrolling (KatzeScrolled* scrolled,
|
||||
gboolean drag_scrolling)
|
||||
{
|
||||
KatzeScrolledPrivate* priv = scrolled->priv;
|
||||
|
||||
if (priv->drag_scrolling && !drag_scrolling)
|
||||
{
|
||||
if (priv->scrolling_timeout_id)
|
||||
{
|
||||
g_source_remove (priv->scrolling_timeout_id);
|
||||
priv->scrolling_timeout_id = 0;
|
||||
priv->previous_time = 0;
|
||||
}
|
||||
|
||||
priv->press_received = FALSE;
|
||||
}
|
||||
|
||||
priv->drag_scrolling = drag_scrolling;
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2007 Henrik Hedberg <hhedberg@innologies.fi>
|
||||
Copyright (C) 2009 Nadav Wiener <nadavwr@yahoo.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
|
||||
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_SCROLLED_H
|
||||
#define KATZE_SCROLLED_H
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define KATZE_TYPE_SCROLLED (katze_scrolled_get_type())
|
||||
#define KATZE_SCROLLED(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), KATZE_TYPE_SCROLLED, KatzeScrolled))
|
||||
#define KATZE_SCROLLED_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), KATZE_TYPE_SCROLLED, KatzeScrolledClass))
|
||||
#define KATZE_IS_SCROLLED(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), KATZE_TYPE_SCROLLED))
|
||||
#define KATZE_IS_SCROLLED_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), KATZE_TYPE_SCROLLED))
|
||||
#define KATZE_SCROLLED_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), KATZE_TYPE_SCROLLED, KatzeScrolledClass))
|
||||
|
||||
typedef struct _KatzeScrolled KatzeScrolled;
|
||||
typedef struct _KatzeScrolledClass KatzeScrolledClass;
|
||||
typedef struct _KatzeScrolledPrivate KatzeScrolledPrivate;
|
||||
|
||||
struct _KatzeScrolled
|
||||
{
|
||||
GtkScrolledWindow parent;
|
||||
|
||||
KatzeScrolledPrivate* priv;
|
||||
};
|
||||
|
||||
struct _KatzeScrolledClass
|
||||
{
|
||||
GtkScrolledWindowClass parent;
|
||||
|
||||
/* Padding for future expansion */
|
||||
void (*_katze_reserved1) (void);
|
||||
void (*_katze_reserved2) (void);
|
||||
void (*_katze_reserved3) (void);
|
||||
void (*_katze_reserved4) (void);
|
||||
};
|
||||
|
||||
GType
|
||||
katze_scrolled_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GtkWidget*
|
||||
katze_scrolled_new (GtkAdjustment* hadjustment,
|
||||
GtkAdjustment* vadjustment);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __KATZE_SCROLLED_H__ */
|
|
@ -1,134 +0,0 @@
|
|||
/*
|
||||
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 "katze-separatoraction.h"
|
||||
|
||||
struct _KatzeSeparatorAction
|
||||
{
|
||||
GtkAction parent_instance;
|
||||
};
|
||||
|
||||
struct _KatzeSeparatorActionClass
|
||||
{
|
||||
GtkActionClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (KatzeSeparatorAction, katze_separator_action, GTK_TYPE_ACTION);
|
||||
|
||||
static void
|
||||
katze_separator_action_finalize (GObject* object);
|
||||
|
||||
static void
|
||||
katze_separator_action_activate (GtkAction* object);
|
||||
|
||||
static GtkWidget*
|
||||
katze_separator_action_create_tool_item (GtkAction* action);
|
||||
|
||||
static GtkWidget*
|
||||
katze_separator_action_create_menu_item (GtkAction* action);
|
||||
|
||||
static void
|
||||
katze_separator_action_connect_proxy (GtkAction* action,
|
||||
GtkWidget* proxy);
|
||||
|
||||
static void
|
||||
katze_separator_action_disconnect_proxy (GtkAction* action,
|
||||
GtkWidget* proxy);
|
||||
|
||||
static void
|
||||
katze_separator_action_class_init (KatzeSeparatorActionClass* class)
|
||||
{
|
||||
GObjectClass* gobject_class;
|
||||
GtkActionClass* action_class;
|
||||
|
||||
gobject_class = G_OBJECT_CLASS (class);
|
||||
gobject_class->finalize = katze_separator_action_finalize;
|
||||
|
||||
action_class = GTK_ACTION_CLASS (class);
|
||||
action_class->activate = katze_separator_action_activate;
|
||||
action_class->create_menu_item = katze_separator_action_create_menu_item;
|
||||
action_class->create_tool_item = katze_separator_action_create_tool_item;
|
||||
action_class->connect_proxy = katze_separator_action_connect_proxy;
|
||||
action_class->disconnect_proxy = katze_separator_action_disconnect_proxy;
|
||||
}
|
||||
|
||||
static void
|
||||
katze_separator_action_init (KatzeSeparatorAction* separator_action)
|
||||
{
|
||||
/* Nothing to do. */
|
||||
}
|
||||
|
||||
static void
|
||||
katze_separator_action_finalize (GObject* object)
|
||||
{
|
||||
G_OBJECT_CLASS (katze_separator_action_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
katze_separator_action_activate (GtkAction* action)
|
||||
{
|
||||
GSList* proxies;
|
||||
|
||||
proxies = gtk_action_get_proxies (action);
|
||||
if (!proxies)
|
||||
return;
|
||||
|
||||
do
|
||||
if (GTK_IS_TOOL_ITEM (proxies->data))
|
||||
{
|
||||
|
||||
}
|
||||
while ((proxies = g_slist_next (proxies)));
|
||||
|
||||
if (GTK_ACTION_CLASS (katze_separator_action_parent_class)->activate)
|
||||
GTK_ACTION_CLASS (katze_separator_action_parent_class)->activate (action);
|
||||
}
|
||||
|
||||
static GtkWidget*
|
||||
katze_separator_action_create_menu_item (GtkAction* action)
|
||||
{
|
||||
GtkWidget* menuitem;
|
||||
|
||||
menuitem = gtk_separator_menu_item_new ();
|
||||
return menuitem;
|
||||
}
|
||||
|
||||
static GtkWidget*
|
||||
katze_separator_action_create_tool_item (GtkAction* action)
|
||||
{
|
||||
GtkWidget* toolitem;
|
||||
|
||||
toolitem = GTK_WIDGET (gtk_separator_tool_item_new ());
|
||||
return toolitem;
|
||||
}
|
||||
|
||||
static void
|
||||
katze_separator_action_connect_proxy (GtkAction* action,
|
||||
GtkWidget* proxy)
|
||||
{
|
||||
GTK_ACTION_CLASS (katze_separator_action_parent_class)->connect_proxy (
|
||||
action, proxy);
|
||||
|
||||
if (GTK_IS_TOOL_ITEM (proxy))
|
||||
{
|
||||
}
|
||||
else if (GTK_IS_MENU_ITEM (proxy))
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
katze_separator_action_disconnect_proxy (GtkAction* action,
|
||||
GtkWidget* proxy)
|
||||
{
|
||||
GTK_ACTION_CLASS (katze_separator_action_parent_class)->disconnect_proxy
|
||||
(action, proxy);
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2009 Christian Dywan <christian@twotoasts.de>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
See the file COPYING for the full license text.
|
||||
*/
|
||||
|
||||
#ifndef __KATZE_SEPARATOR_ACTION_H__
|
||||
#define __KATZE_SEPARATOR_ACTION_H__
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define KATZE_TYPE_SEPARATOR_ACTION \
|
||||
(katze_separator_action_get_type ())
|
||||
#define KATZE_SEPARATOR_ACTION(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST ((obj), KATZE_TYPE_SEPARATOR_ACTION, \
|
||||
KatzeSeparatorAction))
|
||||
#define KATZE_SEPARATOR_ACTION_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST ((klass), KATZE_TYPE_SEPARATOR_ACTION, \
|
||||
KatzeSeparatorActionClass))
|
||||
#define KATZE_IS_SEPARATOR_ACTION(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), KATZE_TYPE_SEPARATOR_ACTION))
|
||||
#define KATZE_IS_SEPARATOR_ACTION_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE ((klass), KATZE_TYPE_SEPARATOR_ACTION))
|
||||
#define KATZE_SEPARATOR_ACTION_GET_CLASS(obj) \
|
||||
(G_TYPE_INSTANCE_GET_CLASS ((obj), KATZE_TYPE_SEPARATOR_ACTION, \
|
||||
KatzeSeparatorActionClass))
|
||||
|
||||
typedef struct _KatzeSeparatorAction KatzeSeparatorAction;
|
||||
typedef struct _KatzeSeparatorActionClass KatzeSeparatorActionClass;
|
||||
|
||||
GType
|
||||
katze_separator_action_get_type (void) G_GNUC_CONST;
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __KATZE_SEPARATOR_ACTION_H__ */
|
28
katze/katze-separatoraction.vala
Normal file
28
katze/katze-separatoraction.vala
Normal file
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
Copyright (C) 2009-2013 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.
|
||||
*/
|
||||
|
||||
namespace Katze {
|
||||
public class SeparatorAction : Gtk.Action {
|
||||
Gtk.MenuItem? menuitem = null;
|
||||
Gtk.ToolItem? toolitem = null;
|
||||
|
||||
public override unowned Gtk.Widget create_menu_item () {
|
||||
menuitem = new Gtk.SeparatorMenuItem ();
|
||||
return menuitem;
|
||||
}
|
||||
|
||||
public override unowned Gtk.Widget create_tool_item () {
|
||||
toolitem = new Gtk.SeparatorToolItem ();
|
||||
return toolitem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -97,12 +97,12 @@ katze_throbber_realize (GtkWidget* widget);
|
|||
#if GTK_CHECK_VERSION (3, 0, 0)
|
||||
static void
|
||||
katze_throbber_get_preferred_height (GtkWidget *widget,
|
||||
gint *minimal_width,
|
||||
gint *natural_width);
|
||||
gint *minimal_height,
|
||||
gint *natural_height);
|
||||
static void
|
||||
katze_throbber_get_preferred_width (GtkWidget *widget,
|
||||
gint *minimal_width,
|
||||
gint *natural_width);
|
||||
gint *minimal_width,
|
||||
gint *natural_width);
|
||||
#endif
|
||||
static void
|
||||
katze_throbber_unrealize (GtkWidget* widget);
|
||||
|
@ -229,7 +229,7 @@ katze_throbber_class_init (KatzeThrobberClass* class)
|
|||
flags));
|
||||
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_PIXBUF,
|
||||
PROP_STATIC_PIXBUF,
|
||||
g_param_spec_object (
|
||||
"static-pixbuf",
|
||||
"Static Pixbuf",
|
||||
|
@ -490,13 +490,11 @@ katze_throbber_set_animated (KatzeThrobber* throbber,
|
|||
g_object_set (throbber, "active", animated, NULL);
|
||||
#else
|
||||
if (animated && (throbber->timer_id < 0))
|
||||
throbber->timer_id = g_timeout_add_full (
|
||||
G_PRIORITY_LOW, 50,
|
||||
(GSourceFunc)katze_throbber_timeout,
|
||||
throbber,
|
||||
(GDestroyNotify)katze_throbber_timeout_destroy);
|
||||
gtk_widget_queue_draw (GTK_WIDGET (throbber));
|
||||
throbber->timer_id = midori_timeout_add (50,
|
||||
(GSourceFunc)katze_throbber_timeout, throbber,
|
||||
(GDestroyNotify)katze_throbber_timeout_destroy);
|
||||
#endif
|
||||
gtk_widget_queue_draw (GTK_WIDGET (throbber));
|
||||
|
||||
g_object_notify (G_OBJECT (throbber), "animated");
|
||||
}
|
||||
|
@ -857,14 +855,14 @@ katze_throbber_size_request (GtkWidget* widget,
|
|||
#if GTK_CHECK_VERSION (3, 0, 0)
|
||||
static void
|
||||
katze_throbber_get_preferred_height (GtkWidget *widget,
|
||||
gint *minimal_width,
|
||||
gint *natural_width)
|
||||
gint *minimal_height,
|
||||
gint *natural_height)
|
||||
{
|
||||
GtkRequisition requisition;
|
||||
|
||||
katze_throbber_size_request (widget, &requisition);
|
||||
|
||||
*minimal_width = *natural_width = requisition.height;
|
||||
*minimal_height = *natural_height = requisition.height;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -902,6 +900,7 @@ katze_throbber_aligned_coords (GtkWidget* widget,
|
|||
#endif
|
||||
|
||||
#if GTK_CHECK_VERSION (3, 0, 0)
|
||||
allocation.x = allocation.y = 0;
|
||||
allocation.width = gtk_widget_get_allocated_width (widget);
|
||||
allocation.height = gtk_widget_get_allocated_height (widget);
|
||||
gtk_widget_get_preferred_size (widget, &requisition, NULL);
|
||||
|
|
|
@ -29,10 +29,6 @@
|
|||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_HILDON_2_2
|
||||
#include <hildon/hildon.h>
|
||||
#endif
|
||||
|
||||
#define I_ g_intern_static_string
|
||||
|
||||
static void
|
||||
|
@ -42,12 +38,7 @@ proxy_toggle_button_toggled_cb (GtkToggleButton* button,
|
|||
gboolean toggled;
|
||||
const gchar* property;
|
||||
|
||||
#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
|
||||
property = g_object_get_data (G_OBJECT (button), "property");
|
||||
g_object_set (object, property, toggled, NULL);
|
||||
}
|
||||
|
@ -79,6 +70,24 @@ proxy_uri_file_set_cb (GtkFileChooser* button,
|
|||
g_object_set (object, property, file, NULL);
|
||||
}
|
||||
|
||||
#if GTK_CHECK_VERSION (3, 2, 0)
|
||||
static void
|
||||
proxy_font_chooser_font_activated_cb (GtkFontChooser* chooser,
|
||||
const gchar* font_name,
|
||||
GObject* object)
|
||||
{
|
||||
gtk_font_chooser_set_font (chooser, font_name);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
proxy_font_chooser_filter_monospace_cb (PangoFontFamily* family,
|
||||
PangoFontFace* face,
|
||||
gpointer data)
|
||||
{
|
||||
gboolean monospace = GPOINTER_TO_INT (data);
|
||||
return monospace == pango_font_family_is_monospace (family);
|
||||
}
|
||||
#else
|
||||
static void
|
||||
proxy_combo_box_text_changed_cb (GtkComboBoxText* button,
|
||||
GObject* object)
|
||||
|
@ -88,6 +97,7 @@ proxy_combo_box_text_changed_cb (GtkComboBoxText* button,
|
|||
g_object_set (object, property, text, NULL);
|
||||
g_free (text);
|
||||
}
|
||||
#endif
|
||||
|
||||
static const gchar*
|
||||
katze_app_info_get_commandline (GAppInfo* info)
|
||||
|
@ -219,17 +229,6 @@ 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)
|
||||
|
@ -277,7 +276,6 @@ proxy_combo_box_changed_cb (GtkComboBox* button,
|
|||
|
||||
if (custom_value)
|
||||
{
|
||||
#if GTK_CHECK_VERSION (2, 12, 0)
|
||||
if (value == custom_value)
|
||||
gtk_widget_set_tooltip_text (GTK_WIDGET (button), NULL);
|
||||
else
|
||||
|
@ -286,10 +284,8 @@ proxy_combo_box_changed_cb (GtkComboBox* button,
|
|||
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,
|
||||
|
@ -331,12 +327,19 @@ proxy_widget_string_destroy_cb (GtkWidget* proxy,
|
|||
static GList*
|
||||
katze_app_info_get_all_for_category (const gchar* category)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
/* FIXME: Real filtering by category would be better */
|
||||
const gchar* content_type = g_content_type_from_mime_type (category);
|
||||
GList* all_apps = g_app_info_get_all_for_type (content_type);
|
||||
#else
|
||||
GList* all_apps = g_app_info_get_all ();
|
||||
#endif
|
||||
GList* apps = NULL;
|
||||
guint i = 0;
|
||||
GAppInfo* info;
|
||||
while ((info = g_list_nth_data (all_apps, i++)))
|
||||
GList* app;
|
||||
for (app = apps; app; app = g_list_next (app))
|
||||
{
|
||||
GAppInfo* info = app->data;
|
||||
#ifdef GDK_WINDOWING_X11
|
||||
gchar* filename = g_strconcat ("applications/", g_app_info_get_id (info), NULL);
|
||||
GKeyFile* file = g_key_file_new ();
|
||||
|
@ -360,6 +363,92 @@ katze_app_info_get_all_for_category (const gchar* category)
|
|||
return apps;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
proxy_populate_apps (GtkWidget* widget)
|
||||
{
|
||||
const gchar* property = g_object_get_data (G_OBJECT (widget), "property");
|
||||
GObject* object = g_object_get_data (G_OBJECT (widget), "object");
|
||||
gchar* string = katze_object_get_string (object, property);
|
||||
if (!g_strcmp0 (string, ""))
|
||||
katze_assign (string, NULL);
|
||||
GtkSettings* settings = gtk_widget_get_settings (widget);
|
||||
gint icon_width = 16;
|
||||
if (settings == NULL)
|
||||
settings = gtk_settings_get_for_screen (gdk_screen_get_default ());
|
||||
gtk_icon_size_lookup_for_settings (settings, GTK_ICON_SIZE_MENU,
|
||||
&icon_width, NULL);
|
||||
|
||||
GtkComboBox* combo = GTK_COMBO_BOX (widget);
|
||||
GtkListStore* model = GTK_LIST_STORE (gtk_combo_box_get_model (combo));
|
||||
GtkTreeIter iter_none;
|
||||
gtk_list_store_insert_with_values (model, &iter_none, 0,
|
||||
0, NULL, 1, NULL, 2, _("None"), 3, icon_width, -1);
|
||||
|
||||
const gchar* app_type = g_object_get_data (G_OBJECT (widget), "app-type");
|
||||
GList* apps = g_app_info_get_all_for_type (app_type);
|
||||
GAppInfo* info;
|
||||
if (!apps)
|
||||
apps = katze_app_info_get_all_for_category (app_type);
|
||||
if (apps != NULL)
|
||||
{
|
||||
GList* app;
|
||||
for (app = apps; app; app = g_list_next (app))
|
||||
{
|
||||
GAppInfo* info = app->data;
|
||||
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);
|
||||
}
|
||||
g_list_free (apps);
|
||||
}
|
||||
|
||||
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);
|
||||
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_signal_connect (widget, "changed",
|
||||
G_CALLBACK (proxy_combo_box_apps_changed_cb), object);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
/**
|
||||
* katze_property_proxy:
|
||||
* @object: a #GObject
|
||||
|
@ -452,23 +541,14 @@ katze_property_proxy (gpointer object,
|
|||
gchar* notify_property;
|
||||
gboolean toggled = katze_object_get_boolean (object, property);
|
||||
|
||||
#ifdef HAVE_HILDON_2_2
|
||||
if (_hint != I_("toggle"))
|
||||
{
|
||||
widget = hildon_check_button_new (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
|
||||
gtk_button_set_label (GTK_BUTTON (widget), gettext (nick));
|
||||
hildon_check_button_set_active (HILDON_CHECK_BUTTON (widget), toggled);
|
||||
}
|
||||
|
||||
widget = gtk_check_button_new ();
|
||||
if (_hint == I_("toggle"))
|
||||
gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (widget), FALSE);
|
||||
else
|
||||
#endif
|
||||
{
|
||||
widget = gtk_check_button_new ();
|
||||
if (_hint == I_("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);
|
||||
}
|
||||
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);
|
||||
|
@ -517,42 +597,46 @@ katze_property_proxy (gpointer object,
|
|||
string = g_strdup (G_PARAM_SPEC_STRING (pspec)->default_value);
|
||||
gtk_file_chooser_set_uri (GTK_FILE_CHOOSER (widget),
|
||||
string ? string : "");
|
||||
#if GTK_CHECK_VERSION (2, 12, 0)
|
||||
g_signal_connect (widget, "file-set",
|
||||
G_CALLBACK (proxy_uri_file_set_cb), object);
|
||||
#else
|
||||
if (pspec->flags & G_PARAM_WRITABLE)
|
||||
g_signal_connect (widget, "selection-changed",
|
||||
G_CALLBACK (proxy_uri_file_set_cb), object);
|
||||
#endif
|
||||
}
|
||||
else if (type == G_TYPE_PARAM_STRING && (_hint == I_("font")
|
||||
|| _hint == I_("font-monospace")))
|
||||
{
|
||||
GtkComboBox* combo;
|
||||
gint n_families, i;
|
||||
PangoContext* context;
|
||||
PangoFontFamily** families;
|
||||
gboolean monospace = _hint == I_("font-monospace");
|
||||
string = katze_object_get_string (object, property);
|
||||
|
||||
widget = gtk_combo_box_text_new ();
|
||||
combo = GTK_COMBO_BOX (widget);
|
||||
context = gtk_widget_get_pango_context (widget);
|
||||
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"));
|
||||
gboolean monospace = _hint == I_("font-monospace");
|
||||
|
||||
#if GTK_CHECK_VERSION (3, 2, 0)
|
||||
widget = gtk_font_button_new ();
|
||||
gtk_font_button_set_show_size (GTK_FONT_BUTTON (widget), FALSE);
|
||||
gtk_font_chooser_set_font (GTK_FONT_CHOOSER (widget), string);
|
||||
g_signal_connect (widget, "font-activated",
|
||||
G_CALLBACK (proxy_font_chooser_font_activated_cb), object);
|
||||
gtk_font_chooser_set_filter_func (GTK_FONT_CHOOSER (widget),
|
||||
(GtkFontFilterFunc)proxy_font_chooser_filter_monospace_cb, GINT_TO_POINTER (monospace), NULL);
|
||||
#else
|
||||
GtkComboBox* combo;
|
||||
gint n_families, i;
|
||||
PangoContext* context;
|
||||
PangoFontFamily** families;
|
||||
|
||||
widget = gtk_combo_box_text_new ();
|
||||
combo = GTK_COMBO_BOX (widget);
|
||||
context = gtk_widget_get_pango_context (widget);
|
||||
pango_context_list_families (context, &families, &n_families);
|
||||
if (string)
|
||||
{
|
||||
gint j = 0;
|
||||
for (i = 0; i < n_families; i++)
|
||||
{
|
||||
const gchar* font = pango_font_family_get_name (families[i]);
|
||||
if (monospace != pango_font_family_is_monospace (families[i]))
|
||||
continue;
|
||||
const gchar* font = pango_font_family_get_name (families[i]);
|
||||
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), font);
|
||||
if (!g_ascii_strcasecmp (font, string))
|
||||
gtk_combo_box_set_active (combo, j);
|
||||
|
@ -564,22 +648,13 @@ katze_property_proxy (gpointer object,
|
|||
g_signal_connect (widget, "changed",
|
||||
G_CALLBACK (proxy_combo_box_text_changed_cb), object);
|
||||
g_free (families);
|
||||
#endif
|
||||
}
|
||||
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];
|
||||
GtkSettings* settings;
|
||||
gint icon_width = 16;
|
||||
GtkTreeIter iter_none;
|
||||
GAppInfo* info;
|
||||
|
||||
settings = gtk_settings_get_for_screen (gdk_screen_get_default ());
|
||||
gtk_icon_size_lookup_for_settings (settings, 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);
|
||||
|
@ -591,77 +666,10 @@ katze_property_proxy (gpointer object,
|
|||
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);
|
||||
|
||||
gtk_list_store_insert_with_values (model, &iter_none, 0,
|
||||
0, NULL, 1, NULL, 2, _("None"), 3, icon_width, -1);
|
||||
|
||||
if (apps != NULL)
|
||||
{
|
||||
gint i = 0;
|
||||
|
||||
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);
|
||||
}
|
||||
g_list_free (apps);
|
||||
}
|
||||
|
||||
{
|
||||
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);
|
||||
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_signal_connect (widget, "changed",
|
||||
G_CALLBACK (proxy_combo_box_apps_changed_cb), object);
|
||||
g_object_set_data_full (G_OBJECT (widget), "app-type", g_strdup (app_type), g_free);
|
||||
g_object_set_data_full (G_OBJECT (widget), "object", g_object_ref (object), g_object_unref);
|
||||
g_idle_add_full (G_PRIORITY_LOW, (GSourceFunc)proxy_populate_apps, widget, NULL);
|
||||
}
|
||||
else if (type == G_TYPE_PARAM_STRING)
|
||||
{
|
||||
|
@ -699,7 +707,8 @@ katze_property_proxy (gpointer object,
|
|||
}
|
||||
else if (type == G_TYPE_PARAM_FLOAT)
|
||||
{
|
||||
gfloat value = katze_object_get_float (object, property);
|
||||
gfloat value;
|
||||
g_object_get (object, property, &value, NULL);
|
||||
|
||||
widget = gtk_spin_button_new_with_range (
|
||||
G_PARAM_SPEC_FLOAT (pspec)->minimum,
|
||||
|
@ -742,10 +751,7 @@ 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);
|
||||
|
@ -763,39 +769,17 @@ katze_property_proxy (gpointer object,
|
|||
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_text_new ();
|
||||
#endif
|
||||
for (i = 0; i < enum_class->n_values; i++)
|
||||
{
|
||||
const gchar* raw_label = gettext (enum_class->values[i].value_nick);
|
||||
gchar* label = katze_strip_mnemonics (raw_label);
|
||||
#ifdef HAVE_HILDON_2_2
|
||||
hildon_touch_selector_append_text (HILDON_TOUCH_SELECTOR (selector), label);
|
||||
#else
|
||||
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (widget), label);
|
||||
#endif
|
||||
g_free (label);
|
||||
}
|
||||
#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);
|
||||
|
@ -812,11 +796,10 @@ katze_property_proxy (gpointer object,
|
|||
G_CALLBACK (proxy_entry_focus_out_event_cb), object);
|
||||
g_object_set_data_full (G_OBJECT (entry), "property",
|
||||
g_strdup (custom), g_free);
|
||||
gtk_widget_set_tooltip_text (widget, NULL);
|
||||
}
|
||||
#if GTK_CHECK_VERSION (2, 12, 0)
|
||||
else
|
||||
gtk_widget_set_tooltip_text (widget, custom_text);
|
||||
#endif
|
||||
|
||||
g_free (custom_text);
|
||||
|
||||
|
@ -831,10 +814,6 @@ katze_property_proxy (gpointer object,
|
|||
widget = gtk_label_new (gettext (nick));
|
||||
g_free (string);
|
||||
|
||||
#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",
|
||||
|
@ -843,53 +822,6 @@ katze_property_proxy (gpointer object,
|
|||
return widget;
|
||||
}
|
||||
|
||||
/**
|
||||
* katze_property_label:
|
||||
* @object: a #GObject
|
||||
* @property: the name of a property
|
||||
*
|
||||
* 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,
|
||||
const gchar* property)
|
||||
{
|
||||
GObjectClass* class;
|
||||
GParamSpec* pspec;
|
||||
const gchar* nick;
|
||||
GtkWidget* widget;
|
||||
|
||||
g_return_val_if_fail (G_IS_OBJECT (object), NULL);
|
||||
|
||||
class = G_OBJECT_GET_CLASS (object);
|
||||
pspec = g_object_class_find_property (class, property);
|
||||
if (!pspec)
|
||||
{
|
||||
g_warning (_("Property '%s' is invalid for %s"),
|
||||
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;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GtkWidget* widget;
|
||||
|
@ -910,21 +842,29 @@ katze_widget_popup_position_menu (GtkMenu* menu,
|
|||
GtkRequisition widget_req;
|
||||
KatzePopupInfo* info = user_data;
|
||||
GtkWidget* widget = info->widget;
|
||||
GdkWindow* window = gtk_widget_get_window (widget);
|
||||
gint widget_height;
|
||||
|
||||
gtk_widget_get_allocation (widget, &allocation);
|
||||
if (!window)
|
||||
return;
|
||||
|
||||
#if !GTK_CHECK_VERSION (3, 0, 0)
|
||||
if (GTK_IS_ENTRY (widget))
|
||||
window = gdk_window_get_parent (window);
|
||||
#endif
|
||||
|
||||
/* Retrieve size and position of both widget and menu */
|
||||
if (!gtk_widget_get_has_window (widget))
|
||||
{
|
||||
gdk_window_get_position (gtk_widget_get_window (widget), &wx, &wy);
|
||||
wx += allocation.x;
|
||||
wy += allocation.y;
|
||||
}
|
||||
else
|
||||
gdk_window_get_origin (gtk_widget_get_window (widget), &wx, &wy);
|
||||
gtk_widget_get_allocation (widget, &allocation);
|
||||
gdk_window_get_origin (window, &wx, &wy);
|
||||
wx += allocation.x;
|
||||
wy += allocation.y;
|
||||
#if GTK_CHECK_VERSION (3, 0, 0)
|
||||
gtk_widget_get_preferred_size (GTK_WIDGET (menu), &menu_req, NULL);
|
||||
gtk_widget_get_preferred_size (widget, &widget_req, NULL);
|
||||
#else
|
||||
gtk_widget_size_request (GTK_WIDGET (menu), &menu_req);
|
||||
gtk_widget_size_request (widget, &widget_req);
|
||||
#endif
|
||||
menu_width = menu_req.width;
|
||||
widget_height = widget_req.height; /* Better than allocation.height */
|
||||
|
||||
|
@ -1016,59 +956,6 @@ katze_image_menu_item_new_ellipsized (const gchar* label)
|
|||
return menuitem;
|
||||
}
|
||||
|
||||
/**
|
||||
* katze_pixbuf_new_from_buffer:
|
||||
* @buffer: Buffer with image data
|
||||
* @length: Length of the buffer
|
||||
* @mime_type: a MIME type, or %NULL
|
||||
* @error: return location for a #GError, or %NULL
|
||||
*
|
||||
* Creates a new #GdkPixbuf out of the specified buffer.
|
||||
*
|
||||
* You can specify a MIME type if looking at the buffer
|
||||
* is not enough to determine the right type.
|
||||
*
|
||||
* Return value: A newly-allocated #GdkPixbuf
|
||||
**/
|
||||
GdkPixbuf*
|
||||
katze_pixbuf_new_from_buffer (const guchar* buffer,
|
||||
gsize length,
|
||||
const gchar* mime_type,
|
||||
GError** error)
|
||||
{
|
||||
/* Proposed for inclusion in GdkPixbuf
|
||||
See http://bugzilla.gnome.org/show_bug.cgi?id=74291 */
|
||||
GdkPixbufLoader* loader;
|
||||
GdkPixbuf* pixbuf;
|
||||
|
||||
g_return_val_if_fail (buffer != NULL, NULL);
|
||||
g_return_val_if_fail (length > 0, NULL);
|
||||
|
||||
if (mime_type)
|
||||
{
|
||||
loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, error);
|
||||
if (!loader)
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
loader = gdk_pixbuf_loader_new ();
|
||||
if (!gdk_pixbuf_loader_write (loader, buffer, length, error))
|
||||
{
|
||||
g_object_unref (loader);
|
||||
return NULL;
|
||||
}
|
||||
if (!gdk_pixbuf_loader_close (loader, error))
|
||||
{
|
||||
g_object_unref (loader);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
|
||||
g_object_ref (pixbuf);
|
||||
g_object_unref (loader);
|
||||
return pixbuf;
|
||||
}
|
||||
|
||||
/**
|
||||
* katze_tree_view_get_selected_iter:
|
||||
* @treeview: a #GtkTreeView
|
||||
|
@ -1190,27 +1077,14 @@ katze_strip_mnemonics (const gchar* original)
|
|||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* katze_object_has_property:
|
||||
* @object: a #GObject
|
||||
* @property: the name of the property
|
||||
*
|
||||
* Determine if @object has a property with the specified name.
|
||||
*
|
||||
* Return value: a boolean
|
||||
*
|
||||
* Since: 0.1.2
|
||||
**/
|
||||
gboolean
|
||||
katze_object_has_property (gpointer object,
|
||||
const gchar* property)
|
||||
const gchar*
|
||||
katze_skip_whitespace (const gchar* str)
|
||||
{
|
||||
GObjectClass* class;
|
||||
|
||||
g_return_val_if_fail (G_IS_OBJECT (object), FALSE);
|
||||
|
||||
class = G_OBJECT_GET_CLASS (object);
|
||||
return g_object_class_find_property (class, property) != NULL;
|
||||
if (str == NULL)
|
||||
return NULL;
|
||||
while (*str == ' ' || *str == '\t' || *str == '\n')
|
||||
str++;
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1257,28 +1131,6 @@ katze_object_get_int (gpointer object,
|
|||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* katze_object_get_float:
|
||||
* @object: a #GObject
|
||||
* @property: the name of the property to get
|
||||
*
|
||||
* Retrieve the float value of the specified property.
|
||||
*
|
||||
* Return value: a float
|
||||
**/
|
||||
gfloat
|
||||
katze_object_get_float (gpointer object,
|
||||
const gchar* property)
|
||||
{
|
||||
gfloat value = -1.0f;
|
||||
|
||||
g_return_val_if_fail (G_IS_OBJECT (object), -1.0f);
|
||||
/* FIXME: Check value type */
|
||||
|
||||
g_object_get (object, property, &value, NULL);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* katze_object_get_enum:
|
||||
* @object: a #GObject
|
||||
|
@ -1353,165 +1205,17 @@ katze_object_get_object (gpointer object,
|
|||
* 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;
|
||||
|
||||
/* Use g_access instead of g_file_test for better performance */
|
||||
if (g_access (pathname, F_OK) == 0)
|
||||
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_access (fn, F_OK) != 0)
|
||||
{
|
||||
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;
|
||||
|
||||
g_return_val_if_fail (uri != NULL, NULL);
|
||||
|
||||
if (midori_uri_is_http (uri))
|
||||
{
|
||||
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] == '/')
|
||||
{
|
||||
gchar* ticon_uri = g_strdup (uri);
|
||||
ticon_uri[i] = '\0';
|
||||
icon_uri = g_strdup_printf ("%s/favicon.ico", ticon_uri);
|
||||
g_free (ticon_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, ".");
|
||||
filename = g_strdup_printf ("%s%s", checksum, ext ? ext : "");
|
||||
g_free (icon_uri);
|
||||
g_free (checksum);
|
||||
path = g_build_filename (g_get_user_cache_dir (), PACKAGE_NAME,
|
||||
"icons", filename, NULL);
|
||||
g_free (filename);
|
||||
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);
|
||||
midori_paths_mkdir_with_parents (pathname, mode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1520,7 +1224,16 @@ katze_uri_entry_changed_cb (GtkWidget* entry,
|
|||
{
|
||||
const gchar* uri = gtk_entry_get_text (GTK_ENTRY (entry));
|
||||
gboolean valid = midori_uri_is_location (uri);
|
||||
if (*uri && !valid)
|
||||
if (!valid && g_object_get_data (G_OBJECT (entry), "allow_%s"))
|
||||
valid = uri && g_str_has_prefix (uri, "%s");
|
||||
if (!valid)
|
||||
valid = midori_uri_is_ip_address (uri);
|
||||
|
||||
#if GTK_CHECK_VERSION (3, 2, 0)
|
||||
g_object_set_data (G_OBJECT (entry), "invalid", GINT_TO_POINTER (uri && *uri && !valid));
|
||||
gtk_widget_queue_draw (entry);
|
||||
#else
|
||||
if (uri && *uri && !valid)
|
||||
{
|
||||
GdkColor bg_color = { 0 };
|
||||
GdkColor fg_color = { 0 };
|
||||
|
@ -1534,11 +1247,34 @@ katze_uri_entry_changed_cb (GtkWidget* entry,
|
|||
gtk_widget_modify_base (entry, GTK_STATE_NORMAL, NULL);
|
||||
gtk_widget_modify_text (entry, GTK_STATE_NORMAL, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (other_widget != NULL)
|
||||
gtk_widget_set_sensitive (other_widget, valid);
|
||||
}
|
||||
|
||||
#if GTK_CHECK_VERSION (3, 2, 0)
|
||||
static gboolean
|
||||
katze_uri_entry_draw_cb (GtkWidget* entry,
|
||||
cairo_t* cr,
|
||||
GtkWidget* other_widget)
|
||||
{
|
||||
const GdkRGBA color = { 0.9, 0., 0., 1. };
|
||||
double width = gtk_widget_get_allocated_width (entry);
|
||||
double height = gtk_widget_get_allocated_height (entry);
|
||||
|
||||
if (!g_object_get_data (G_OBJECT (entry), "invalid"))
|
||||
return FALSE;
|
||||
|
||||
/* FIXME: error-underline-color requires GtkTextView */
|
||||
gdk_cairo_set_source_rgba (cr, &color);
|
||||
|
||||
pango_cairo_show_error_underline (cr, width * 0.15, height / 1.9,
|
||||
width * 0.75, height / 1.9 / 2);
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* katze_uri_entry_new:
|
||||
* @other_widget: a #GtkWidget, or %NULL
|
||||
|
@ -1556,11 +1292,31 @@ GtkWidget*
|
|||
katze_uri_entry_new (GtkWidget* other_widget)
|
||||
{
|
||||
GtkWidget* entry = gtk_entry_new ();
|
||||
#if GTK_CHECK_VERSION (3, 6, 0)
|
||||
gtk_entry_set_input_purpose (GTK_ENTRY (entry), GTK_INPUT_PURPOSE_URL);
|
||||
#endif
|
||||
|
||||
gtk_entry_set_icon_from_gicon (GTK_ENTRY (entry), GTK_ENTRY_ICON_PRIMARY,
|
||||
g_themed_icon_new_with_default_fallbacks ("text-html-symbolic"));
|
||||
g_signal_connect (entry, "changed",
|
||||
G_CALLBACK (katze_uri_entry_changed_cb), other_widget);
|
||||
#if GTK_CHECK_VERSION (3, 2, 0)
|
||||
g_signal_connect_after (entry, "draw",
|
||||
G_CALLBACK (katze_uri_entry_draw_cb), other_widget);
|
||||
#endif
|
||||
return entry;
|
||||
}
|
||||
|
||||
void
|
||||
katze_widget_add_class (GtkWidget* widget,
|
||||
const gchar* class_name)
|
||||
{
|
||||
#if GTK_CHECK_VERSION (3,0,0)
|
||||
GtkStyleContext* context = gtk_widget_get_style_context (widget);
|
||||
gtk_style_context_add_class (context, class_name);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* katze_assert_str_equal:
|
||||
* @input: a string
|
||||
|
@ -1585,3 +1341,21 @@ katze_assert_str_equal (const gchar* input,
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
katze_window_set_sensible_default_size (GtkWindow* window)
|
||||
{
|
||||
GdkScreen* screen;
|
||||
GdkRectangle monitor;
|
||||
gint width, height;
|
||||
|
||||
g_return_if_fail (GTK_IS_WINDOW (window));
|
||||
|
||||
screen = gtk_window_get_screen (window);
|
||||
gdk_screen_get_monitor_geometry (screen, 0, &monitor);
|
||||
width = monitor.width / 1.7;
|
||||
height = monitor.height / 1.7;
|
||||
gtk_window_set_default_size (window, width, height);
|
||||
/* 700x100 is the approximate useful minimum dimensions */
|
||||
gtk_widget_set_size_request (GTK_WIDGET (window), 700, 100);
|
||||
}
|
||||
|
||||
|
|
|
@ -19,15 +19,6 @@
|
|||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/**
|
||||
* KATZE_OBJECT_NAME:
|
||||
* @object: an object
|
||||
*
|
||||
* Return the name of an object's class structure's type.
|
||||
**/
|
||||
#define KATZE_OBJECT_NAME(object) \
|
||||
G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (object))
|
||||
|
||||
/**
|
||||
* katze_assign:
|
||||
* @lvalue: a pointer
|
||||
|
@ -45,7 +36,7 @@ G_BEGIN_DECLS
|
|||
* Unrefs @lvalue if needed and assigns it the value of @rvalue.
|
||||
**/
|
||||
#define katze_object_assign(lvalue, rvalue) \
|
||||
lvalue = ((lvalue ? g_object_unref (lvalue) : lvalue), rvalue)
|
||||
lvalue = ((lvalue ? g_object_unref (lvalue) : (void)0), rvalue)
|
||||
|
||||
/**
|
||||
* katze_strv_assign:
|
||||
|
@ -58,15 +49,25 @@ G_BEGIN_DECLS
|
|||
**/
|
||||
#define katze_strv_assign(lvalue, rvalue) lvalue = (g_strfreev (lvalue), rvalue)
|
||||
|
||||
/**
|
||||
* katze_str_non_null:
|
||||
* @str: a string, or %NULL
|
||||
*
|
||||
* Returns "" if @str is %NULL.
|
||||
*
|
||||
* Since: 0.4.4
|
||||
**/
|
||||
static inline const gchar*
|
||||
katze_str_non_null (const gchar* str)
|
||||
{
|
||||
return str ? str : "";
|
||||
}
|
||||
|
||||
GtkWidget*
|
||||
katze_property_proxy (gpointer object,
|
||||
const gchar* property,
|
||||
const gchar* hint);
|
||||
|
||||
GtkWidget*
|
||||
katze_property_label (gpointer object,
|
||||
const gchar* property);
|
||||
|
||||
typedef enum {
|
||||
KATZE_MENU_POSITION_CURSOR = 0,
|
||||
KATZE_MENU_POSITION_LEFT,
|
||||
|
@ -82,12 +83,6 @@ katze_widget_popup (GtkWidget* widget,
|
|||
GtkWidget*
|
||||
katze_image_menu_item_new_ellipsized (const gchar* label);
|
||||
|
||||
GdkPixbuf*
|
||||
katze_pixbuf_new_from_buffer (const guchar* buffer,
|
||||
gsize length,
|
||||
const gchar* mime_type,
|
||||
GError** error);
|
||||
|
||||
gboolean
|
||||
katze_tree_view_get_selected_iter (GtkTreeView* treeview,
|
||||
GtkTreeModel** model,
|
||||
|
@ -101,9 +96,8 @@ katze_bookmark_populate_tree_view (KatzeArray* array,
|
|||
gchar*
|
||||
katze_strip_mnemonics (const gchar* original);
|
||||
|
||||
gboolean
|
||||
katze_object_has_property (gpointer object,
|
||||
const gchar* property);
|
||||
const gchar*
|
||||
katze_skip_whitespace (const gchar* str);
|
||||
|
||||
gint
|
||||
katze_object_get_boolean (gpointer object,
|
||||
|
@ -113,10 +107,6 @@ gint
|
|||
katze_object_get_int (gpointer object,
|
||||
const gchar* property);
|
||||
|
||||
gfloat
|
||||
katze_object_get_float (gpointer object,
|
||||
const gchar* property);
|
||||
|
||||
gint
|
||||
katze_object_get_enum (gpointer object,
|
||||
const gchar* property);
|
||||
|
@ -133,21 +123,21 @@ 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);
|
||||
|
||||
GtkWidget*
|
||||
katze_uri_entry_new (GtkWidget* other_widget);
|
||||
|
||||
void
|
||||
katze_widget_add_class (GtkWidget* widget,
|
||||
const gchar* class_name);
|
||||
|
||||
void
|
||||
katze_assert_str_equal (const gchar* input,
|
||||
const gchar* result,
|
||||
const gchar* expected);
|
||||
|
||||
void
|
||||
katze_window_set_sensible_default_size (GtkWindow* window);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __KATZE_UTILS_H__ */
|
||||
|
|
|
@ -20,9 +20,7 @@
|
|||
#include "katze-item.h"
|
||||
#include "katze-array.h"
|
||||
#include "katze-arrayaction.h"
|
||||
#include "katze-separatoraction.h"
|
||||
#include "katze-net.h"
|
||||
#include "katze-scrolled.h"
|
||||
#include "katze-preferences.h"
|
||||
|
||||
#endif /* __KATZE_H__ */
|
||||
|
|
38
katze/katze.vapi
Normal file
38
katze/katze.vapi
Normal file
|
@ -0,0 +1,38 @@
|
|||
/* Copyright (C) 2012 André Stösel <andre@stoesel.de>
|
||||
This file is licensed under the terms of the expat license, see the file EXPAT. */
|
||||
|
||||
[CCode (cprefix = "Katze", lower_case_cprefix = "katze_")]
|
||||
namespace Katze {
|
||||
static void assert_str_equal (string input, string result, string? expected);
|
||||
static unowned Gtk.Widget property_proxy (void* object, string property, string? hint);
|
||||
[CCode (cheader_filename = "katze/katze.h", cprefix = "KATZE_MENU_POSITION_")]
|
||||
enum MenuPos {
|
||||
CURSOR,
|
||||
LEFT,
|
||||
RIGHT
|
||||
}
|
||||
static void widget_popup (Gtk.Widget? widget, Gtk.Menu menu, Gdk.EventButton? event, MenuPos pos);
|
||||
|
||||
[CCode (cheader_filename = "katze/katze.h")]
|
||||
public class Array : Katze.Item {
|
||||
public Array (GLib.Type type);
|
||||
public signal void add_item (GLib.Object item);
|
||||
public signal void remove_item (GLib.Object item);
|
||||
public uint get_length ();
|
||||
public GLib.List<unowned Item> get_items ();
|
||||
public bool is_empty ();
|
||||
}
|
||||
|
||||
[CCode (cheader_filename = "katze/katze.h")]
|
||||
public class Item : GLib.Object {
|
||||
public Item ();
|
||||
public string? uri { get; set; }
|
||||
public string? name { get; set; }
|
||||
public string? text { get; set; }
|
||||
|
||||
public bool get_meta_boolean (string key);
|
||||
public int64 get_meta_integer (string key);
|
||||
public void set_meta_integer (string key, int64 value);
|
||||
}
|
||||
}
|
||||
|
145
katze/midori-hsts.vala
Normal file
145
katze/midori-hsts.vala
Normal file
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
Copyright (C) 2012 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.
|
||||
*/
|
||||
|
||||
namespace Midori {
|
||||
public class HSTS : GLib.Object, Soup.SessionFeature {
|
||||
public class Directive {
|
||||
public Soup.Date? expires = null;
|
||||
public bool sub_domains = false;
|
||||
|
||||
public Directive (bool include_sub_domains) {
|
||||
expires = new Soup.Date.from_now (int.MAX);
|
||||
sub_domains = include_sub_domains;
|
||||
}
|
||||
|
||||
public Directive.from_header (string header) {
|
||||
var param_list = Soup.header_parse_param_list (header);
|
||||
if (param_list == null)
|
||||
return;
|
||||
|
||||
string? max_age = param_list.lookup ("max-age");
|
||||
if (max_age != null)
|
||||
expires = new Soup.Date.from_now (max_age.to_int ());
|
||||
// if (param_list.lookup_extended ("includeSubDomains", null, null))
|
||||
if ("includeSubDomains" in header)
|
||||
sub_domains = true;
|
||||
Soup.header_free_param_list (param_list);
|
||||
}
|
||||
|
||||
public bool is_valid () {
|
||||
return expires != null && !expires.is_past ();
|
||||
}
|
||||
}
|
||||
|
||||
HashTable<string, Directive> whitelist;
|
||||
bool debug = false;
|
||||
|
||||
public HSTS () {
|
||||
whitelist = new HashTable<string, Directive> (str_hash, str_equal);
|
||||
read_cache.begin (File.new_for_path (Paths.get_preset_filename (null, "hsts")));
|
||||
read_cache.begin (File.new_for_path (Paths.get_config_filename_for_reading ("hsts")));
|
||||
if (strcmp (Environment.get_variable ("MIDORI_DEBUG"), "hsts") == 0)
|
||||
debug = true;
|
||||
}
|
||||
|
||||
async void read_cache (File file) {
|
||||
try {
|
||||
var stream = new DataInputStream (yield file.read_async ());
|
||||
do {
|
||||
string? line = yield stream.read_line_async ();
|
||||
if (line == null)
|
||||
break;
|
||||
string[] parts = line.split (" ", 2);
|
||||
if (parts[0] == null || parts[1] == null)
|
||||
break;
|
||||
var directive = new Directive.from_header (parts[1]);
|
||||
if (directive.is_valid ())
|
||||
append_to_whitelist (parts[0], directive);
|
||||
} while (true);
|
||||
}
|
||||
catch (Error error) { }
|
||||
}
|
||||
|
||||
#if HAVE_LIBSOUP_2_34_0
|
||||
/* No sub-features */
|
||||
public bool add_feature (Type type) { return false; }
|
||||
public bool remove_feature (Type type) { return false; }
|
||||
public bool has_feature (Type type) { return false; }
|
||||
#endif
|
||||
|
||||
public void attach (Soup.Session session) { session.request_queued.connect (queued); }
|
||||
public void detach (Soup.Session session) { /* FIXME disconnect */ }
|
||||
|
||||
/* Never called but required by the interface */
|
||||
public void request_started (Soup.Session session, Soup.Message msg, Soup.Socket socket) { }
|
||||
public void request_queued (Soup.Session session, Soup.Message message) { }
|
||||
public void request_unqueued (Soup.Session session, Soup.Message msg) { }
|
||||
|
||||
bool should_secure_host (string host) {
|
||||
Directive? directive = whitelist.lookup (host);
|
||||
if (directive == null)
|
||||
directive = whitelist.lookup ("*." + host);
|
||||
return directive != null && directive.is_valid ();
|
||||
}
|
||||
|
||||
void queued (Soup.Session session, Soup.Message message) {
|
||||
if (should_secure_host (message.uri.host)) {
|
||||
message.uri.set_scheme ("https");
|
||||
session.requeue_message (message);
|
||||
if (debug)
|
||||
stdout.printf ("HSTS: Enforce %s\n", message.uri.host);
|
||||
}
|
||||
else if (message.uri.scheme == "http")
|
||||
message.finished.connect (strict_transport_security_handled);
|
||||
}
|
||||
|
||||
void append_to_whitelist (string host, Directive directive) {
|
||||
whitelist.insert (host, directive);
|
||||
if (directive.sub_domains)
|
||||
whitelist.insert ("*." + host, directive);
|
||||
}
|
||||
|
||||
async void append_to_cache (string host, string header) {
|
||||
if (Midori.Paths.is_readonly ())
|
||||
return;
|
||||
|
||||
string filename = Paths.get_config_filename_for_writing ("hsts");
|
||||
try {
|
||||
var file = File.new_for_path (filename);
|
||||
var stream = file.append_to/* FIXME _async*/ (FileCreateFlags.NONE);
|
||||
yield stream.write_async ((host + " " + header + "\n").data);
|
||||
yield stream.flush_async ();
|
||||
}
|
||||
catch (Error error) {
|
||||
critical ("Failed to update %s: %s", filename, error.message);
|
||||
}
|
||||
}
|
||||
|
||||
void strict_transport_security_handled (Soup.Message message) {
|
||||
if (message == null || message.uri == null)
|
||||
return;
|
||||
|
||||
unowned string? hsts = message.response_headers.get_one ("Strict-Transport-Security");
|
||||
if (hsts == null)
|
||||
return;
|
||||
|
||||
var directive = new Directive.from_header (hsts);
|
||||
if (directive.is_valid ()) {
|
||||
append_to_whitelist (message.uri.host, directive);
|
||||
append_to_cache.begin (message.uri.host, hsts);
|
||||
}
|
||||
if (debug)
|
||||
stdout.printf ("HSTS: '%s' sets '%s' valid? %s\n",
|
||||
message.uri.host, hsts, directive.is_valid ().to_string ());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
468
katze/midori-paths.vala
Normal file
468
katze/midori-paths.vala
Normal file
|
@ -0,0 +1,468 @@
|
|||
/*
|
||||
Copyright (C) 2012 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.
|
||||
*/
|
||||
|
||||
namespace GLib {
|
||||
#if HAVE_WIN32
|
||||
extern static string win32_get_package_installation_directory_of_module (void* hmodule = null);
|
||||
#endif
|
||||
}
|
||||
|
||||
extern const string LIBDIR;
|
||||
extern const string MDATADIR;
|
||||
extern const string PACKAGE_NAME;
|
||||
extern const string SYSCONFDIR;
|
||||
extern const string MIDORI_VERSION_SUFFIX;
|
||||
const string MODULE_PREFIX = "lib";
|
||||
const string MODULE_SUFFIX = "." + GLib.Module.SUFFIX;
|
||||
|
||||
namespace Midori {
|
||||
public enum RuntimeMode {
|
||||
UNDEFINED,
|
||||
NORMAL,
|
||||
APP,
|
||||
PRIVATE,
|
||||
PORTABLE
|
||||
}
|
||||
|
||||
namespace Paths {
|
||||
static string? exec_path = null;
|
||||
static string[] command_line = null;
|
||||
static string? runtime_dir = null;
|
||||
static RuntimeMode mode = RuntimeMode.UNDEFINED;
|
||||
|
||||
static string? config_dir = null;
|
||||
static string? readonly_dir = null;
|
||||
static string? cache_dir = null;
|
||||
static string? cache_dir_for_reading = null;
|
||||
static string? user_data_dir = null;
|
||||
static string? user_data_dir_for_reading = null;
|
||||
static string? tmp_dir = null;
|
||||
|
||||
namespace Test {
|
||||
public void reset_runtime_mode () {
|
||||
mode = RuntimeMode.UNDEFINED;
|
||||
}
|
||||
}
|
||||
|
||||
public static string get_config_dir_for_reading () {
|
||||
assert (mode != RuntimeMode.UNDEFINED);
|
||||
return readonly_dir ?? config_dir;
|
||||
}
|
||||
|
||||
/* returns the path to a user configuration file whose contents should not be modified.
|
||||
to get the path to save settings, use get_config_filename() */
|
||||
public static string get_config_filename_for_reading (string filename) {
|
||||
assert (mode != RuntimeMode.UNDEFINED);
|
||||
return Path.build_path (Path.DIR_SEPARATOR_S,
|
||||
readonly_dir ?? config_dir, filename);
|
||||
}
|
||||
|
||||
public bool is_readonly () {
|
||||
assert (mode != RuntimeMode.UNDEFINED);
|
||||
return readonly_dir != null;
|
||||
}
|
||||
|
||||
public RuntimeMode get_runtime_mode () {
|
||||
assert (mode != RuntimeMode.UNDEFINED);
|
||||
return mode;
|
||||
}
|
||||
|
||||
public static unowned string get_runtime_dir () {
|
||||
if (runtime_dir != null)
|
||||
return runtime_dir;
|
||||
|
||||
#if HAVE_WIN32
|
||||
runtime_dir = Environment.get_variable ("XDG_RUNTIME_DIR");
|
||||
if (runtime_dir == null || runtime_dir == "")
|
||||
runtime_dir = Environment.get_user_data_dir ();
|
||||
#else
|
||||
runtime_dir = Environment.get_variable ("XDG_RUNTIME_DIR");
|
||||
if (runtime_dir == null || runtime_dir == "") {
|
||||
runtime_dir = Path.build_path (Path.DIR_SEPARATOR_S,
|
||||
Environment.get_tmp_dir (), PACKAGE_NAME + "-" + Environment.get_user_name ());
|
||||
mkdir_with_parents (runtime_dir);
|
||||
return runtime_dir;
|
||||
}
|
||||
#endif
|
||||
runtime_dir = Path.build_path (Path.DIR_SEPARATOR_S, runtime_dir, PACKAGE_NAME);
|
||||
mkdir_with_parents (runtime_dir);
|
||||
return runtime_dir;
|
||||
}
|
||||
|
||||
public static void init (RuntimeMode new_mode, string? config) {
|
||||
assert (mode == RuntimeMode.UNDEFINED);
|
||||
assert (new_mode != RuntimeMode.UNDEFINED);
|
||||
mode = new_mode;
|
||||
if (mode == RuntimeMode.PORTABLE || mode == RuntimeMode.PRIVATE)
|
||||
Gtk.Settings.get_default ().gtk_recent_files_max_age = 0;
|
||||
if (mode == RuntimeMode.PORTABLE) {
|
||||
config_dir = Path.build_path (Path.DIR_SEPARATOR_S,
|
||||
exec_path, "profile", "config");
|
||||
cache_dir = Path.build_path (Path.DIR_SEPARATOR_S,
|
||||
exec_path, "profile", "cache");
|
||||
user_data_dir = Path.build_path (Path.DIR_SEPARATOR_S,
|
||||
exec_path, "profile", "misc");
|
||||
tmp_dir = Path.build_path (Path.DIR_SEPARATOR_S,
|
||||
exec_path, "profile", "tmp");
|
||||
}
|
||||
else if (mode == RuntimeMode.PRIVATE || mode == RuntimeMode.APP) {
|
||||
string? real_config = config != null && !Path.is_absolute (config)
|
||||
? Path.build_filename (Environment.get_current_dir (), config) : config;
|
||||
readonly_dir = real_config ?? Path.build_path (Path.DIR_SEPARATOR_S,
|
||||
Environment.get_user_config_dir (), PACKAGE_NAME);
|
||||
cache_dir_for_reading = Path.build_path (Path.DIR_SEPARATOR_S,
|
||||
Environment.get_user_cache_dir (), PACKAGE_NAME);
|
||||
user_data_dir_for_reading = Environment.get_user_data_dir ();
|
||||
tmp_dir = get_runtime_dir ();
|
||||
}
|
||||
else {
|
||||
string? real_config = config != null && !Path.is_absolute (config)
|
||||
? Path.build_filename (Environment.get_current_dir (), config) : config;
|
||||
config_dir = real_config ?? Path.build_path (Path.DIR_SEPARATOR_S,
|
||||
Environment.get_user_config_dir (), PACKAGE_NAME);
|
||||
cache_dir = Path.build_path (Path.DIR_SEPARATOR_S,
|
||||
Environment.get_user_cache_dir (), PACKAGE_NAME);
|
||||
user_data_dir = Environment.get_user_data_dir ();
|
||||
#if HAVE_WEBKIT2_A
|
||||
WebKit.WebContext.get_default ().set_disk_cache_directory (
|
||||
Path.build_path (Path.DIR_SEPARATOR_S, cache_dir, "web"));
|
||||
#endif
|
||||
#if HAVE_WEBKIT2
|
||||
var cookie_manager = WebKit.WebContext.get_default ().get_cookie_manager ();
|
||||
cookie_manager.set_persistent_storage (Path.build_filename (config, "cookies.db"),
|
||||
WebKit.CookiePersistentStorage.SQLITE);
|
||||
#endif
|
||||
tmp_dir = get_runtime_dir ();
|
||||
}
|
||||
#if HAVE_WEBKIT_1_3_13
|
||||
if (user_data_dir != null) {
|
||||
string folder = Path.build_filename (user_data_dir, "webkit", "icondatabase");
|
||||
#if HAVE_WEBKIT2
|
||||
WebKit.WebContext.get_default ().set_favicon_database_directory (folder);
|
||||
#elif HAVE_WEBKIT_1_8_0
|
||||
WebKit.get_favicon_database ().set_path (folder);
|
||||
#elif HAVE_WEBKIT_1_3_13
|
||||
WebKit.get_icon_database ().set_path (folder);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
if (strcmp (Environment.get_variable ("MIDORI_DEBUG"), "paths") == 0) {
|
||||
stdout.printf ("config: %s\ncache: %s\nuser_data: %s\ntmp: %s\n",
|
||||
config_dir, cache_dir, user_data_dir, tmp_dir);
|
||||
}
|
||||
}
|
||||
|
||||
public static void mkdir_with_parents (string path, int mode = 0700) {
|
||||
/* Use g_access instead of g_file_test for better performance */
|
||||
if (Posix.access (path, Posix.F_OK) == 0)
|
||||
return;
|
||||
int i = path.index_of_char (Path.DIR_SEPARATOR, 0);
|
||||
do {
|
||||
string fn = path.substring (i, -1);
|
||||
if (Posix.access (fn, Posix.F_OK) != 0) {
|
||||
if (DirUtils.create (fn, mode) == -1) {
|
||||
/* Slow fallback; if this fails we fail */
|
||||
DirUtils.create_with_parents (path, mode);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (!FileUtils.test (fn, FileTest.IS_SYMLINK))
|
||||
return; /* Failed */
|
||||
|
||||
i = path.index_of_char (Path.DIR_SEPARATOR, i);
|
||||
}
|
||||
while (i != -1);
|
||||
}
|
||||
|
||||
public static void remove_path (string path) {
|
||||
try {
|
||||
var dir = Dir.open (path, 0);
|
||||
string? name;
|
||||
while (true) {
|
||||
name = dir.read_name ();
|
||||
if (name == null)
|
||||
break;
|
||||
remove_path (Path.build_filename (path, name));
|
||||
}
|
||||
}
|
||||
catch (Error error) {
|
||||
FileUtils.remove (path);
|
||||
}
|
||||
}
|
||||
|
||||
public static unowned string get_config_dir_for_writing () {
|
||||
assert (config_dir != null);
|
||||
mkdir_with_parents (config_dir);
|
||||
return config_dir;
|
||||
}
|
||||
|
||||
public static string get_extension_config_dir (string extension) {
|
||||
assert (config_dir != null);
|
||||
string folder;
|
||||
if ("." in extension)
|
||||
folder = Path.build_filename (config_dir, "extensions", extension);
|
||||
else
|
||||
folder = Path.build_filename (config_dir, "extensions",
|
||||
MODULE_PREFIX + extension + "." + GLib.Module.SUFFIX);
|
||||
mkdir_with_parents (folder);
|
||||
return folder;
|
||||
}
|
||||
|
||||
public static string get_extension_preset_filename (string extension, string filename) {
|
||||
assert (exec_path != null);
|
||||
string preset_filename = extension;
|
||||
if (extension.has_prefix (MODULE_PREFIX))
|
||||
preset_filename = extension.split (MODULE_PREFIX)[1];
|
||||
if (extension.has_suffix (MODULE_SUFFIX))
|
||||
preset_filename = preset_filename.split (MODULE_SUFFIX)[0];
|
||||
return get_preset_filename (Path.build_filename ("extensions", preset_filename), filename);
|
||||
}
|
||||
|
||||
/* returns the path to a user configuration file to which it is permitted to write.
|
||||
this is also necessary for files whose state is synchronized to disk by a manager,
|
||||
e.g. cookies. */
|
||||
public static string get_config_filename_for_writing (string filename) {
|
||||
assert (mode != RuntimeMode.UNDEFINED);
|
||||
assert (config_dir != null);
|
||||
mkdir_with_parents (config_dir);
|
||||
return Path.build_path (Path.DIR_SEPARATOR_S, config_dir, filename);
|
||||
}
|
||||
|
||||
public static unowned string get_cache_dir () {
|
||||
assert (cache_dir != null);
|
||||
return cache_dir;
|
||||
}
|
||||
|
||||
public static unowned string get_user_data_dir () {
|
||||
assert (user_data_dir != null);
|
||||
return user_data_dir;
|
||||
}
|
||||
|
||||
public static unowned string get_user_data_dir_for_reading () {
|
||||
assert (user_data_dir_for_reading != null || user_data_dir != null);
|
||||
if (user_data_dir != null)
|
||||
return user_data_dir;
|
||||
return user_data_dir_for_reading;
|
||||
}
|
||||
|
||||
public static unowned string get_cache_dir_for_reading () {
|
||||
assert (cache_dir_for_reading != null || cache_dir != null);
|
||||
if (cache_dir != null)
|
||||
return cache_dir;
|
||||
return cache_dir_for_reading;
|
||||
}
|
||||
|
||||
public static unowned string get_tmp_dir () {
|
||||
assert (tmp_dir != null);
|
||||
return tmp_dir;
|
||||
}
|
||||
|
||||
public static string make_tmp_dir (string tmpl) {
|
||||
assert (tmp_dir != null);
|
||||
#if HAVE_GLIB_2_30
|
||||
try {
|
||||
return DirUtils.make_tmp (tmpl);
|
||||
}
|
||||
catch (Error error) {
|
||||
GLib.error (error.message);
|
||||
}
|
||||
#else
|
||||
string folder = Path.build_path (Path.DIR_SEPARATOR_S, Environment.get_tmp_dir (), tmpl);
|
||||
DirUtils.mkdtemp (folder);
|
||||
return folder;
|
||||
#endif
|
||||
}
|
||||
|
||||
public static void init_exec_path (string[] new_command_line) {
|
||||
assert (command_line == null);
|
||||
command_line = new_command_line;
|
||||
#if HAVE_WIN32
|
||||
exec_path = Environment.get_variable ("MIDORI_EXEC_PATH") ??
|
||||
win32_get_package_installation_directory_of_module ();
|
||||
#else
|
||||
string? executable;
|
||||
try {
|
||||
if (!Path.is_absolute (command_line[0])) {
|
||||
string program = Environment.find_program_in_path (command_line[0]);
|
||||
if (FileUtils.test (program, FileTest.IS_SYMLINK))
|
||||
executable = FileUtils.read_link (program);
|
||||
else
|
||||
executable = program;
|
||||
}
|
||||
else
|
||||
executable = FileUtils.read_link (command_line[0]);
|
||||
}
|
||||
catch (Error error) {
|
||||
executable = command_line[0];
|
||||
}
|
||||
|
||||
exec_path = File.new_for_path (executable).get_parent ().get_parent ().get_path ();
|
||||
#endif
|
||||
if (strcmp (Environment.get_variable ("MIDORI_DEBUG"), "paths") == 0) {
|
||||
stdout.printf ("command_line: %s\nexec_path: %s\nres: %s\nlib: %s\n",
|
||||
get_command_line_str (true), exec_path,
|
||||
get_res_filename (""), get_lib_path (PACKAGE_NAME));
|
||||
}
|
||||
}
|
||||
|
||||
public static unowned string[] get_command_line () {
|
||||
assert (command_line != null);
|
||||
return command_line;
|
||||
}
|
||||
|
||||
public static string get_command_line_str (bool for_display) {
|
||||
assert (command_line != null);
|
||||
if (for_display)
|
||||
return string.joinv (" ", command_line).replace (Environment.get_home_dir (), "~");
|
||||
return string.joinv (" ", command_line).replace ("--debug", "").replace ("-g", "")
|
||||
.replace ("--diagnostic-dialog", "").replace ("-d", "");
|
||||
}
|
||||
|
||||
public static string get_lib_path (string package) {
|
||||
assert (command_line != null);
|
||||
#if HAVE_WIN32
|
||||
return Path.build_filename (exec_path, "lib", package);
|
||||
#else
|
||||
string path = Path.build_filename (exec_path, "lib", package);
|
||||
if (Posix.access (path, Posix.F_OK) == 0)
|
||||
return path;
|
||||
|
||||
if (package == PACKAGE_NAME) {
|
||||
/* Fallback to build folder */
|
||||
path = Path.build_filename ((File.new_for_path (exec_path).get_path ()), "extensions");
|
||||
if (Posix.access (path, Posix.F_OK) == 0)
|
||||
return path;
|
||||
}
|
||||
|
||||
return Path.build_filename (LIBDIR, PACKAGE_NAME);
|
||||
#endif
|
||||
}
|
||||
|
||||
public static string get_res_filename (string filename) {
|
||||
assert (command_line != null);
|
||||
#if HAVE_WIN32
|
||||
return Path.build_filename (exec_path, "share", PACKAGE_NAME, "res", filename);
|
||||
#else
|
||||
string path = Path.build_filename (exec_path, "share", PACKAGE_NAME, "res", filename);
|
||||
if (Posix.access (path, Posix.F_OK) == 0)
|
||||
return path;
|
||||
|
||||
/* Fallback to build folder */
|
||||
path = Path.build_filename ((File.new_for_path (exec_path)
|
||||
.get_parent ().get_parent ().get_path ()), "data", filename);
|
||||
if (Posix.access (path, Posix.F_OK) == 0)
|
||||
return path;
|
||||
|
||||
return Path.build_filename (MDATADIR, PACKAGE_NAME, "res", filename);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* returns the path to a file containing read-only data installed with the application
|
||||
if @res is true, looks in the midori resource folder specifically */
|
||||
public static string get_data_filename (string filename, bool res) {
|
||||
assert (command_line != null);
|
||||
string res1 = res ? PACKAGE_NAME : "";
|
||||
string res2 = res ? "res" : "";
|
||||
|
||||
#if HAVE_WIN32
|
||||
return Path.build_filename (exec_path, "share", res1, res2, filename);
|
||||
#else
|
||||
string path = Path.build_filename (get_user_data_dir_for_reading (), res1, res2, filename);
|
||||
if (Posix.access (path, Posix.F_OK) == 0)
|
||||
return path;
|
||||
|
||||
foreach (string data_dir in Environment.get_system_data_dirs ()) {
|
||||
path = Path.build_filename (data_dir, res1, res2, filename);
|
||||
if (Posix.access (path, Posix.F_OK) == 0)
|
||||
return path;
|
||||
}
|
||||
|
||||
return Path.build_filename (MDATADIR, res1, res2, filename);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* returns the path to a file containing system default configuration */
|
||||
public static string get_preset_filename (string? folder, string filename) {
|
||||
assert (exec_path != null);
|
||||
|
||||
#if HAVE_WIN32
|
||||
return Path.build_filename (exec_path, "etc", "xdg", PACKAGE_NAME, folder ?? "", filename);
|
||||
#else
|
||||
foreach (string config_dir in Environment.get_system_config_dirs ()) {
|
||||
string path = Path.build_filename (config_dir, PACKAGE_NAME, folder ?? "", filename);
|
||||
if (Posix.access (path, Posix.F_OK) == 0)
|
||||
return path;
|
||||
}
|
||||
|
||||
return Path.build_filename (SYSCONFDIR, "xdg", PACKAGE_NAME, folder ?? "", filename);
|
||||
#endif
|
||||
}
|
||||
|
||||
public static void clear_icons () {
|
||||
assert (cache_dir != null);
|
||||
assert (user_data_dir != null);
|
||||
#if HAVE_WEBKIT2
|
||||
WebKit.WebContext.get_default ().get_favicon_database ().clear ();
|
||||
#elif HAVE_WEBKIT_1_8_0
|
||||
WebKit.get_favicon_database ().clear ();
|
||||
#elif HAVE_WEBKIT_1_3_13
|
||||
WebKit.get_icon_database ().clear ();
|
||||
#endif
|
||||
/* FIXME: Exclude search engine icons */
|
||||
remove_path (Path.build_filename (cache_dir, "icons"));
|
||||
remove_path (Path.build_filename (user_data_dir, "webkit", "icondatabase"));
|
||||
}
|
||||
|
||||
public static Gdk.Pixbuf? get_icon (string? uri, Gtk.Widget? widget) {
|
||||
if (!Midori.URI.is_resource (uri))
|
||||
return null;
|
||||
int icon_width = 16, icon_height = 16;
|
||||
if (widget != null)
|
||||
Gtk.icon_size_lookup_for_settings (widget.get_settings (),
|
||||
Gtk.IconSize.MENU, out icon_width, out icon_height);
|
||||
#if HAVE_WEBKIT2
|
||||
/* TODO async
|
||||
var database = WebKit.WebContext.get_default ().get_favicon_database ();
|
||||
database.get_favicon.begin (uri, null); */
|
||||
#elif HAVE_WEBKIT_1_8_0
|
||||
Gdk.Pixbuf? pixbuf = WebKit.get_favicon_database ()
|
||||
.try_get_favicon_pixbuf (uri, icon_width, icon_height);
|
||||
if (pixbuf != null)
|
||||
return pixbuf;
|
||||
#elif HAVE_WEBKIT_1_3_13
|
||||
Gdk.Pixbuf? pixbuf = WebKit.get_icon_database ().get_icon_pixbuf (uri);
|
||||
if (pixbuf != null)
|
||||
return pixbuf.scale_simple (icon_width, icon_height, Gdk.InterpType.BILINEAR);
|
||||
#else
|
||||
if (Midori.URI.is_http (uri)) {
|
||||
try {
|
||||
uint i = 8;
|
||||
while (uri[i] != '\0' && uri[i] != '/')
|
||||
i++;
|
||||
string icon_uri = (uri[i] == '/')
|
||||
? uri.substring (0, i) + "/favicon.ico"
|
||||
: uri + "/favicon.ico";
|
||||
string checksum = Checksum.compute_for_string (ChecksumType.MD5, icon_uri, -1);
|
||||
string filename = checksum + Midori.Download.get_extension_for_uri (icon_uri) ?? "";
|
||||
string path = Path.build_filename (get_cache_dir_for_reading (), "icons", filename);
|
||||
Gdk.Pixbuf? pixbuf = new Gdk.Pixbuf.from_file_at_size (path, icon_width, icon_height);
|
||||
if (pixbuf != null)
|
||||
return pixbuf;
|
||||
}
|
||||
catch (GLib.Error error) { }
|
||||
}
|
||||
#endif
|
||||
if (widget != null)
|
||||
return widget.render_icon (Gtk.STOCK_FILE, Gtk.IconSize.MENU, null);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,6 +18,8 @@ namespace Midori {
|
|||
public class URI : Object {
|
||||
public static string? parse_hostname (string? uri, out string path) {
|
||||
/* path may be null. */
|
||||
if (&path != null)
|
||||
path = null;
|
||||
if (uri == null)
|
||||
return uri;
|
||||
unowned string? hostname = uri.chr (-1, '/');
|
||||
|
@ -57,10 +59,22 @@ namespace Midori {
|
|||
string? unescaped = GLib.Uri.unescape_string (uri, "+");
|
||||
if (unescaped == null)
|
||||
return uri;
|
||||
return unescaped.replace (" ", "%20");
|
||||
return unescaped.replace (" ", "%20").replace ("\n", "%0A");
|
||||
}
|
||||
return uri;
|
||||
}
|
||||
|
||||
/* Strip http(s), file and www. for tab titles or completion */
|
||||
public static string strip_prefix_for_display (string uri) {
|
||||
if (is_http (uri) || uri.has_prefix ("file://")) {
|
||||
string stripped_uri = uri.split ("://")[1];
|
||||
if (is_http (uri) && stripped_uri.has_prefix ("www."))
|
||||
return stripped_uri.substring (4, -1);
|
||||
return stripped_uri;
|
||||
}
|
||||
return uri;
|
||||
}
|
||||
|
||||
public static string format_for_display (string? uri) {
|
||||
/* Percent-decode and decode puniycode for user display */
|
||||
if (uri != null && uri.has_prefix ("http://")) {
|
||||
|
@ -85,6 +99,9 @@ namespace Midori {
|
|||
if (uri == null)
|
||||
return keywords;
|
||||
string escaped = GLib.Uri.escape_string (keywords, ":/", true);
|
||||
/* Allow DuckDuckGo to distinguish Midori and in turn share revenue */
|
||||
if (uri == "https://duckduckgo.com/?q=%s")
|
||||
return "https://duckduckgo.com/?q=%s&t=midori".printf (escaped);
|
||||
if (uri.str ("%s") != null)
|
||||
return uri.printf (escaped);
|
||||
return uri + escaped;
|
||||
|
@ -111,44 +128,70 @@ namespace Midori {
|
|||
|| (uri.has_prefix ("geo:") && uri.chr (-1, ',') != null)
|
||||
|| uri.has_prefix ("javascript:"));
|
||||
}
|
||||
public static bool is_email (string? uri) {
|
||||
return uri != null
|
||||
&& (uri.chr (-1, '@') != null || uri.has_prefix ("mailto:"))
|
||||
/* :// and @ together would mean login credentials */
|
||||
&& uri.str ("://") == null;
|
||||
}
|
||||
|
||||
public static bool is_ip_address (string? uri) {
|
||||
/* Quick check for IPv4 or IPv6, no validation.
|
||||
FIXME: Schemes are not handled
|
||||
hostname_is_ip_address () is not used because
|
||||
we'd have to separate the path from the URI first. */
|
||||
return uri != null && uri[0].isdigit ()
|
||||
&& (uri.chr (4, '.') != null || uri.chr (4, ':') != null);
|
||||
if (uri == null)
|
||||
return false;
|
||||
/* Skip leading user/ password */
|
||||
if (uri.chr (-1, '@') != null)
|
||||
return is_ip_address (uri.split ("@")[1]);
|
||||
/* IPv4 */
|
||||
if (uri[0] != '0' && uri[0].isdigit () && (uri.chr (4, '.') != null))
|
||||
return true;
|
||||
/* IPv6 */
|
||||
if (uri[0].isalnum () && uri[1].isalnum ()
|
||||
&& uri[2].isalnum () && uri[3].isalnum () && uri[4] == ':'
|
||||
&& (uri[5] == ':' || uri[5].isalnum ()))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
public static bool is_valid (string? uri) {
|
||||
return uri != null
|
||||
&& uri.chr (-1, ' ') == null
|
||||
&& (URI.is_location (uri) || uri.chr (-1, '.') != null);
|
||||
}
|
||||
|
||||
public static string? get_folder (string uri) {
|
||||
/* Base the start folder on the current view's uri if it is local */
|
||||
try {
|
||||
string? filename = Filename.from_uri (uri);
|
||||
if (filename != null) {
|
||||
string? dirname = Path.get_dirname (filename);
|
||||
if (dirname != null && FileUtils.test (dirname, FileTest.IS_DIR))
|
||||
return dirname;
|
||||
}
|
||||
}
|
||||
catch (Error error) { }
|
||||
return null;
|
||||
}
|
||||
|
||||
public static GLib.ChecksumType get_fingerprint (string uri,
|
||||
out string checksum, out string label) {
|
||||
|
||||
/* http://foo.bar/baz/spam.eggs#!algo!123456 */
|
||||
unowned string display = null;
|
||||
GLib.ChecksumType type = (GLib.ChecksumType)int.MAX;
|
||||
|
||||
unowned string delimiter = "#!md5!";
|
||||
unowned string display = _("MD5-Checksum:");
|
||||
GLib.ChecksumType type = GLib.ChecksumType.MD5;
|
||||
unowned string? fragment = uri.str (delimiter);
|
||||
if (fragment == null) {
|
||||
delimiter = "#!sha1!";
|
||||
if (fragment != null) {
|
||||
display = _("MD5-Checksum:");
|
||||
type = GLib.ChecksumType.MD5;
|
||||
}
|
||||
|
||||
delimiter = "#!sha1!";
|
||||
fragment = uri.str (delimiter);
|
||||
if (fragment != null) {
|
||||
display = _("SHA1-Checksum:");
|
||||
type = GLib.ChecksumType.SHA1;
|
||||
fragment = uri.str (delimiter);
|
||||
}
|
||||
if (fragment == null) {
|
||||
type = (GLib.ChecksumType)int.MAX;
|
||||
display = null;
|
||||
}
|
||||
|
||||
/* No SHA256: no known usage and no need for strong encryption */
|
||||
|
||||
if (&checksum != null)
|
||||
checksum = fragment != null
|
||||
? fragment.offset (delimiter.length) : null;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -26,115 +26,15 @@
|
|||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#if GTK_CHECK_VERSION (2, 16, 0)
|
||||
#define GtkIconEntry GtkEntry
|
||||
#define GtkIconEntryPosition GtkEntryIconPosition
|
||||
#define GTK_ICON_ENTRY_PRIMARY GTK_ENTRY_ICON_PRIMARY
|
||||
#define GTK_ICON_ENTRY_SECONDARY GTK_ENTRY_ICON_SECONDARY
|
||||
#define GTK_ICON_ENTRY GTK_ENTRY
|
||||
#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,
|
||||
GtkEntryIconPosition position,
|
||||
GdkPixbuf* pixbuf);
|
||||
#define gtk_icon_entry_set_tooltip gtk_entry_set_icon_tooltip_text
|
||||
#define gtk_icon_entry_set_icon_highlight gtk_entry_set_icon_activatable
|
||||
#define gtk_icon_entry_set_progress_fraction gtk_entry_set_progress_fraction
|
||||
#else
|
||||
|
||||
#define GTK_TYPE_ICON_ENTRY (gtk_icon_entry_get_type())
|
||||
#define GTK_ICON_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GTK_TYPE_ICON_ENTRY, GtkIconEntry))
|
||||
#define GTK_ICON_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GTK_TYPE_ICON_ENTRY, GtkIconEntryClass))
|
||||
#define GTK_IS_ICON_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GTK_TYPE_ICON_ENTRY))
|
||||
#define GTK_IS_ICON_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GTK_TYPE_ICON_ENTRY))
|
||||
#define GTK_ICON_ENTRY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_ICON_ENTRY, GtkIconEntryClass))
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GTK_ICON_ENTRY_PRIMARY,
|
||||
GTK_ICON_ENTRY_SECONDARY
|
||||
} GtkIconEntryPosition;
|
||||
|
||||
typedef struct _GtkIconEntry GtkIconEntry;
|
||||
typedef struct _GtkIconEntryClass GtkIconEntryClass;
|
||||
typedef struct _GtkIconEntryPrivate GtkIconEntryPrivate;
|
||||
|
||||
struct _GtkIconEntry
|
||||
{
|
||||
GtkEntry parent_object;
|
||||
|
||||
GtkIconEntryPrivate* priv;
|
||||
};
|
||||
|
||||
struct _GtkIconEntryClass
|
||||
{
|
||||
GtkEntryClass parent_class;
|
||||
|
||||
/* Signals */
|
||||
void (*icon_pressed) (GtkIconEntry *entry,
|
||||
GtkIconEntryPosition icon_pos,
|
||||
int button);
|
||||
void (*icon_released) (GtkIconEntry *entry,
|
||||
GtkIconEntryPosition icon_pos,
|
||||
int button);
|
||||
|
||||
void (*gtk_reserved1) (void);
|
||||
void (*gtk_reserved2) (void);
|
||||
void (*gtk_reserved3) (void);
|
||||
void (*gtk_reserved4) (void);
|
||||
};
|
||||
|
||||
GType gtk_icon_entry_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GtkWidget* gtk_icon_entry_new (void);
|
||||
|
||||
void gtk_icon_entry_set_icon_from_pixbuf (GtkIconEntry *entry,
|
||||
GtkIconEntryPosition icon_pos,
|
||||
GdkPixbuf *pixbuf);
|
||||
void gtk_icon_entry_set_icon_from_stock (GtkIconEntry *entry,
|
||||
GtkIconEntryPosition icon_pos,
|
||||
const gchar *stock_id);
|
||||
void gtk_icon_entry_set_icon_from_icon_name (GtkIconEntry *entry,
|
||||
GtkIconEntryPosition icon_pos,
|
||||
const gchar *icon_name);
|
||||
|
||||
void gtk_icon_entry_set_icon_from_gicon (const GtkIconEntry *entry,
|
||||
GtkIconEntryPosition icon_pos,
|
||||
GIcon *icon);
|
||||
|
||||
GdkPixbuf* gtk_icon_entry_get_pixbuf (const GtkIconEntry *entry,
|
||||
GtkIconEntryPosition icon_pos);
|
||||
|
||||
GIcon* gtk_icon_entry_get_gicon (const GtkIconEntry *entry,
|
||||
GtkIconEntryPosition icon_pos);
|
||||
|
||||
void gtk_icon_entry_set_icon_highlight (const GtkIconEntry *entry,
|
||||
GtkIconEntryPosition icon_pos,
|
||||
gboolean highlight);
|
||||
|
||||
gboolean gtk_icon_entry_get_icon_highlight (const GtkIconEntry *entry,
|
||||
GtkIconEntryPosition icon_pos);
|
||||
|
||||
void gtk_icon_entry_set_cursor (const GtkIconEntry *icon_entry,
|
||||
GtkIconEntryPosition icon_pos,
|
||||
GdkCursorType cursor_type);
|
||||
|
||||
void gtk_icon_entry_set_tooltip (const GtkIconEntry *icon_entry,
|
||||
GtkIconEntryPosition icon_pos,
|
||||
const gchar *text);
|
||||
|
||||
void gtk_icon_entry_set_icon_sensitive (const GtkIconEntry *icon_entry,
|
||||
GtkIconEntryPosition icon_pos,
|
||||
gboolean sensitive);
|
||||
|
||||
void gtk_icon_entry_set_progress_fraction (GtkIconEntry *icon_entry,
|
||||
gdouble fraction);
|
||||
|
||||
#endif
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
|
2579
midori/main.c
2579
midori/main.c
File diff suppressed because it is too large
Load diff
|
@ -6,6 +6,7 @@ OBJECT:OBJECT
|
|||
VOID:BOOLEAN,STRING
|
||||
VOID:OBJECT,ENUM,BOOLEAN
|
||||
VOID:OBJECT,INT,INT
|
||||
VOID:OBJECT,OBJECT
|
||||
VOID:POINTER,INT
|
||||
VOID:STRING,BOOLEAN
|
||||
VOID:STRING,INT,STRING
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright (C) 2008-2010 Christian Dywan <christian@twotoasts.de>
|
||||
Copyright (C) 2008-2012 Christian Dywan <christian@twotoasts.de>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
|
@ -21,9 +21,11 @@
|
|||
|
||||
#include "midori-app.h"
|
||||
#include "midori-platform.h"
|
||||
#include "midori-core.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <glib/gstdio.h>
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#if ENABLE_NLS
|
||||
|
@ -31,16 +33,7 @@
|
|||
#include <locale.h>
|
||||
#endif
|
||||
|
||||
#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
|
||||
#if HAVE_UNIQUE
|
||||
typedef gpointer MidoriAppInstance;
|
||||
#define MidoriAppInstanceNull NULL
|
||||
#if defined(G_DISABLE_DEPRECATED) && !defined(G_CONST_RETURN)
|
||||
|
@ -64,14 +57,14 @@
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SIGNAL_H
|
||||
#include <signal.h>
|
||||
#endif
|
||||
|
||||
struct _MidoriApp
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
MidoriBrowser* browser;
|
||||
GtkAccelGroup* accel_group;
|
||||
|
||||
gchar* name;
|
||||
MidoriWebSettings* settings;
|
||||
KatzeArray* bookmarks;
|
||||
KatzeArray* trash;
|
||||
|
@ -81,13 +74,16 @@ struct _MidoriApp
|
|||
KatzeArray* extensions;
|
||||
KatzeArray* browsers;
|
||||
|
||||
MidoriBrowser* browser;
|
||||
MidoriAppInstance instance;
|
||||
|
||||
#if !HAVE_HILDON || !HAVE_LIBNOTIFY
|
||||
#if !HAVE_LIBNOTIFY
|
||||
gchar* program_notify_send;
|
||||
#endif
|
||||
};
|
||||
|
||||
static gchar* app_name = NULL;
|
||||
|
||||
struct _MidoriAppClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
|
@ -216,7 +212,6 @@ _midori_app_add_browser (MidoriApp* app,
|
|||
g_return_if_fail (MIDORI_IS_APP (app));
|
||||
g_return_if_fail (MIDORI_IS_BROWSER (browser));
|
||||
|
||||
gtk_window_add_accel_group (GTK_WINDOW (browser), app->accel_group);
|
||||
g_object_connect (browser,
|
||||
"signal::focus-in-event", midori_browser_focus_in_event_cb, app,
|
||||
"signal::new-window", midori_browser_new_window_cb, app,
|
||||
|
@ -226,9 +221,34 @@ _midori_app_add_browser (MidoriApp* app,
|
|||
NULL);
|
||||
g_signal_connect_swapped (browser, "send-notification",
|
||||
G_CALLBACK (midori_app_send_notification), app);
|
||||
|
||||
katze_array_add_item (app->browsers, browser);
|
||||
|
||||
#if GTK_CHECK_VERSION (3, 0, 0)
|
||||
if (app->browser == NULL)
|
||||
{
|
||||
gchar* filename;
|
||||
if ((filename = midori_paths_get_res_filename ("gtk3.css")))
|
||||
{
|
||||
GtkCssProvider* css_provider = gtk_css_provider_new ();
|
||||
GError* error = NULL;
|
||||
gtk_css_provider_load_from_path (css_provider, filename, &error);
|
||||
if (error == NULL)
|
||||
{
|
||||
gtk_style_context_add_provider_for_screen (
|
||||
gtk_widget_get_screen (GTK_WIDGET (browser)),
|
||||
GTK_STYLE_PROVIDER (css_provider),
|
||||
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_warning ("Failed to load \"%s\": %s", filename, error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
g_free (filename);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
app->browser = browser;
|
||||
#if HAVE_UNIQUE
|
||||
/* We *do not* let unique watch windows because that includes
|
||||
|
@ -238,10 +258,28 @@ _midori_app_add_browser (MidoriApp* app,
|
|||
#endif
|
||||
}
|
||||
|
||||
#ifdef HAVE_SIGNAL_H
|
||||
static MidoriApp* app_singleton;
|
||||
static void
|
||||
midori_app_signal_handler (int signal_id)
|
||||
{
|
||||
signal (signal_id, 0);
|
||||
if (!midori_paths_is_readonly ())
|
||||
midori_app_quit (app_singleton);
|
||||
if (kill (getpid (), signal_id))
|
||||
exit (1);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
_midori_app_quit (MidoriApp* app)
|
||||
{
|
||||
gtk_main_quit ();
|
||||
if (!midori_paths_is_readonly ())
|
||||
{
|
||||
gchar* config_file = midori_paths_get_config_filename_for_writing ("running");
|
||||
g_unlink (config_file);
|
||||
g_free (config_file);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -470,8 +508,7 @@ midori_app_command_received (MidoriApp* app,
|
|||
{
|
||||
MidoriBrowser* browser = midori_app_create_browser (app);
|
||||
midori_app_add_browser (app, browser);
|
||||
/* FIXME: Should open the homepage according to settings */
|
||||
midori_browser_add_uri (browser, "");
|
||||
midori_browser_add_uri (browser, "about:home");
|
||||
midori_browser_activate_action (browser, "Location");
|
||||
gtk_widget_show (GTK_WIDGET (browser));
|
||||
midori_app_raise_window (GTK_WINDOW (browser), screen);
|
||||
|
@ -517,21 +554,12 @@ midori_app_command_received (MidoriApp* app,
|
|||
else
|
||||
{
|
||||
/* Switch to already open tab if possible */
|
||||
guint i = 0;
|
||||
GtkWidget* tab;
|
||||
gboolean found = FALSE;
|
||||
while ((tab = midori_browser_get_nth_tab (browser, i++)))
|
||||
if (g_str_equal (
|
||||
midori_view_get_display_uri (MIDORI_VIEW (tab)),
|
||||
fixed_uri))
|
||||
{
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
if (found)
|
||||
midori_browser_set_current_tab (browser, tab);
|
||||
KatzeArray* items = midori_browser_get_proxy_array (browser);
|
||||
KatzeItem* found = katze_array_find_uri (items, fixed_uri);
|
||||
if (found != NULL)
|
||||
midori_browser_set_current_item (browser, found);
|
||||
else
|
||||
midori_browser_set_current_page (browser,
|
||||
midori_browser_set_current_tab (browser,
|
||||
midori_browser_add_uri (browser, fixed_uri));
|
||||
}
|
||||
}
|
||||
|
@ -543,51 +571,18 @@ midori_app_command_received (MidoriApp* app,
|
|||
}
|
||||
else if (g_str_equal (command, "command"))
|
||||
{
|
||||
guint i = 0;
|
||||
|
||||
if (!uris || !app->browser)
|
||||
return FALSE;
|
||||
while (uris[i] != NULL)
|
||||
{
|
||||
gint i;
|
||||
for (i = 0; uris && uris[i]; i++)
|
||||
midori_browser_activate_action (app->browser, uris[i]);
|
||||
i++;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#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
|
||||
#if HAVE_UNIQUE
|
||||
static UniqueResponse
|
||||
midori_browser_message_received_cb (UniqueApp* instance,
|
||||
gint command,
|
||||
|
@ -687,58 +682,42 @@ static MidoriAppInstance
|
|||
midori_app_create_instance (MidoriApp* app)
|
||||
{
|
||||
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;
|
||||
guint i, n;
|
||||
#if !HAVE_UNIQUE
|
||||
gboolean exists;
|
||||
GIOChannel* channel;
|
||||
#endif
|
||||
|
||||
if (!app->name)
|
||||
{
|
||||
const gchar* config = sokoke_set_config_dir (NULL);
|
||||
gchar* name_hash;
|
||||
name_hash = g_compute_checksum_for_string (G_CHECKSUM_MD5, config, -1);
|
||||
app->name = g_strconcat ("midori", "_", name_hash, NULL);
|
||||
g_free (name_hash);
|
||||
g_object_notify (G_OBJECT (app), "name");
|
||||
}
|
||||
|
||||
if (!(display = gdk_display_get_default ()))
|
||||
return MidoriAppInstanceNull;
|
||||
|
||||
{
|
||||
#if HAVE_UNIQUE
|
||||
const gchar* config = midori_paths_get_config_dir_for_reading ();
|
||||
gchar* config_hash = g_compute_checksum_for_string (G_CHECKSUM_MD5, config, -1);
|
||||
gchar* name_hash = g_compute_checksum_for_string (G_CHECKSUM_MD5, app_name, -1);
|
||||
katze_assign (app_name, g_strconcat (PACKAGE_NAME,
|
||||
"_", config_hash, "_", name_hash, NULL));
|
||||
g_free (config_hash);
|
||||
g_free (name_hash);
|
||||
#else
|
||||
katze_assign (app_name, g_strdup (PACKAGE_NAME));
|
||||
#endif
|
||||
g_object_notify (G_OBJECT (app), "name");
|
||||
}
|
||||
|
||||
#ifdef GDK_WINDOWING_X11
|
||||
/* On X11: :0 or :0.0 which is equivalent */
|
||||
display_name = g_strndup (gdk_display_get_name (display), 2);
|
||||
#else
|
||||
display_name = g_strdup (gdk_display_get_name (display));
|
||||
n = strlen (display_name);
|
||||
for (i = 0; i < n; i++)
|
||||
if (strchr (":.\\/", display_name[i]))
|
||||
display_name[i] = '_';
|
||||
instance_name = g_strdup_printf ("de.twotoasts.%s_%s", app->name, display_name);
|
||||
#endif
|
||||
g_strdelimit (display_name, ":.\\/", '_');
|
||||
instance_name = g_strdup_printf ("de.twotoasts.%s_%s", app_name, display_name);
|
||||
g_free (display_name);
|
||||
katze_assign (app_name, instance_name);
|
||||
|
||||
#if HAVE_UNIQUE
|
||||
instance = unique_app_new (instance_name, NULL);
|
||||
|
@ -746,7 +725,7 @@ midori_app_create_instance (MidoriApp* app)
|
|||
g_signal_connect (instance, "message-received",
|
||||
G_CALLBACK (midori_browser_message_received_cb), app);
|
||||
#else
|
||||
instance = socket_init (instance_name, sokoke_set_config_dir (NULL), &exists);
|
||||
instance = socket_init (instance_name, midori_paths_get_config_dir_for_writing (), &exists);
|
||||
g_object_set_data (G_OBJECT (app), "sock-exists",
|
||||
exists ? (gpointer)0xdeadbeef : NULL);
|
||||
if (instance != MidoriAppInstanceNull)
|
||||
|
@ -755,19 +734,53 @@ midori_app_create_instance (MidoriApp* app)
|
|||
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;
|
||||
}
|
||||
|
||||
const gchar*
|
||||
midori_app_get_name (MidoriApp* app)
|
||||
{
|
||||
return app_name;
|
||||
}
|
||||
|
||||
gboolean
|
||||
midori_app_get_crashed (MidoriApp* app)
|
||||
{
|
||||
if (!midori_paths_is_readonly ())
|
||||
{
|
||||
/* We test for the presence of a dummy file which is created once
|
||||
and deleted during normal runtime, but persists in case of a crash. */
|
||||
gchar* config_file = midori_paths_get_config_filename_for_writing ("running");
|
||||
gboolean crashed = (g_access (config_file, F_OK) == 0);
|
||||
if (!crashed)
|
||||
g_file_set_contents (config_file, "RUNNING", -1, NULL);
|
||||
g_free (config_file);
|
||||
if (crashed)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
midori_app_init (MidoriApp* app)
|
||||
{
|
||||
app->accel_group = gtk_accel_group_new ();
|
||||
#ifdef HAVE_SIGNAL_H
|
||||
app_singleton = app;
|
||||
#ifdef SIGHUP
|
||||
signal (SIGHUP, &midori_app_signal_handler);
|
||||
#endif
|
||||
#ifdef SIGINT
|
||||
signal (SIGINT, &midori_app_signal_handler);
|
||||
#endif
|
||||
#ifdef SIGTERM
|
||||
signal (SIGTERM, &midori_app_signal_handler);
|
||||
#endif
|
||||
#ifdef SIGQUIT
|
||||
signal (SIGQUIT, &midori_app_signal_handler);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
app->settings = NULL;
|
||||
app->bookmarks = NULL;
|
||||
|
@ -775,17 +788,16 @@ midori_app_init (MidoriApp* app)
|
|||
app->search_engines = NULL;
|
||||
app->history = NULL;
|
||||
app->speeddial = NULL;
|
||||
app->extensions = NULL;
|
||||
app->extensions = katze_array_new (KATZE_TYPE_ARRAY);
|
||||
app->browsers = katze_array_new (MIDORI_TYPE_BROWSER);
|
||||
|
||||
app->instance = MidoriAppInstanceNull;
|
||||
|
||||
#if HAVE_LIBNOTIFY
|
||||
notify_init ("midori");
|
||||
notify_init (PACKAGE_NAME);
|
||||
#else
|
||||
app->program_notify_send = g_find_program_in_path ("notify-send");
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -793,9 +805,7 @@ midori_app_finalize (GObject* object)
|
|||
{
|
||||
MidoriApp* app = MIDORI_APP (object);
|
||||
|
||||
g_object_unref (app->accel_group);
|
||||
|
||||
katze_assign (app->name, NULL);
|
||||
katze_assign (app_name, NULL);
|
||||
katze_object_assign (app->settings, NULL);
|
||||
katze_object_assign (app->bookmarks, NULL);
|
||||
katze_object_assign (app->trash, NULL);
|
||||
|
@ -805,10 +815,7 @@ midori_app_finalize (GObject* object)
|
|||
katze_object_assign (app->extensions, NULL);
|
||||
katze_object_assign (app->browsers, NULL);
|
||||
|
||||
#if HAVE_HILDON
|
||||
osso_deinitialize (app->instance);
|
||||
app->instance = NULL;
|
||||
#elif HAVE_UNIQUE
|
||||
#if HAVE_UNIQUE
|
||||
katze_object_assign (app->instance, NULL);
|
||||
#else
|
||||
sock_cleanup ();
|
||||
|
@ -835,7 +842,7 @@ midori_app_set_property (GObject* object,
|
|||
switch (prop_id)
|
||||
{
|
||||
case PROP_NAME:
|
||||
katze_assign (app->name, g_value_dup_string (value));
|
||||
katze_assign (app_name, g_value_dup_string (value));
|
||||
break;
|
||||
case PROP_SETTINGS:
|
||||
katze_object_assign (app->settings, g_value_dup_object (value));
|
||||
|
@ -875,7 +882,7 @@ midori_app_get_property (GObject* object,
|
|||
switch (prop_id)
|
||||
{
|
||||
case PROP_NAME:
|
||||
g_value_set_string (value, app->name);
|
||||
g_value_set_string (value, app_name);
|
||||
break;
|
||||
case PROP_SETTINGS:
|
||||
g_value_set_object (value, app->settings);
|
||||
|
@ -918,12 +925,38 @@ midori_app_get_property (GObject* object,
|
|||
* Return value: a new #MidoriApp
|
||||
**/
|
||||
MidoriApp*
|
||||
midori_app_new (void)
|
||||
midori_app_new (const gchar* name)
|
||||
{
|
||||
MidoriApp* app = g_object_new (MIDORI_TYPE_APP,
|
||||
NULL);
|
||||
return g_object_new (MIDORI_TYPE_APP, "name", name, NULL);
|
||||
}
|
||||
|
||||
return app;
|
||||
/**
|
||||
* midori_app_new_proxy:
|
||||
* @app: a #MidoriApp, or %NULL
|
||||
*
|
||||
* Instantiates a proxy #MidoriApp that can be passed to untrusted code
|
||||
* or for sensitive use cases. Properties can be freely changed.
|
||||
*
|
||||
* Return value: a new #MidoriApp
|
||||
*
|
||||
* Since: 0.5.0
|
||||
**/
|
||||
MidoriApp*
|
||||
midori_app_new_proxy (MidoriApp* app)
|
||||
{
|
||||
g_return_val_if_fail (MIDORI_IS_APP (app) || !app, NULL);
|
||||
|
||||
return midori_app_new (NULL);
|
||||
}
|
||||
|
||||
static gboolean instance_is_not_running = FALSE;
|
||||
static gboolean instance_is_running = FALSE;
|
||||
|
||||
void
|
||||
midori_app_set_instance_is_running (gboolean is_running)
|
||||
{
|
||||
instance_is_not_running = !is_running;
|
||||
instance_is_running = is_running;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -943,20 +976,19 @@ midori_app_instance_is_running (MidoriApp* app)
|
|||
{
|
||||
g_return_val_if_fail (MIDORI_IS_APP (app), FALSE);
|
||||
|
||||
if (instance_is_not_running)
|
||||
return FALSE;
|
||||
else if (instance_is_running)
|
||||
return TRUE;
|
||||
|
||||
if (app->instance == MidoriAppInstanceNull)
|
||||
app->instance = midori_app_create_instance (app);
|
||||
|
||||
#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);
|
||||
#if HAVE_UNIQUE
|
||||
return app->instance && unique_app_is_running (app->instance);
|
||||
#else
|
||||
return g_object_get_data (G_OBJECT (app), "sock-exists") != NULL;
|
||||
return g_object_get_data (G_OBJECT (app), "sock-exists") != NULL;
|
||||
#endif
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -973,19 +1005,13 @@ midori_app_instance_is_running (MidoriApp* app)
|
|||
gboolean
|
||||
midori_app_instance_send_activate (MidoriApp* app)
|
||||
{
|
||||
#if HAVE_UNIQUE
|
||||
UniqueResponse response;
|
||||
#endif
|
||||
|
||||
/* g_return_val_if_fail (MIDORI_IS_APP (app), FALSE); */
|
||||
g_return_val_if_fail (MIDORI_IS_APP (app), FALSE);
|
||||
g_return_val_if_fail (midori_app_instance_is_running (app), FALSE);
|
||||
|
||||
#if HAVE_HILDON
|
||||
osso_application_top (app->instance, PACKAGE_NAME, NULL);
|
||||
#elif HAVE_UNIQUE
|
||||
#if HAVE_UNIQUE
|
||||
if (app->instance)
|
||||
{
|
||||
response = unique_app_send_message (app->instance, UNIQUE_ACTIVATE, NULL);
|
||||
UniqueResponse response = unique_app_send_message (app->instance, UNIQUE_ACTIVATE, NULL);
|
||||
if (response == UNIQUE_RESPONSE_OK)
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -1011,19 +1037,13 @@ midori_app_instance_send_activate (MidoriApp* app)
|
|||
gboolean
|
||||
midori_app_instance_send_new_browser (MidoriApp* app)
|
||||
{
|
||||
#if HAVE_UNIQUE
|
||||
UniqueResponse response;
|
||||
#endif
|
||||
|
||||
/* g_return_val_if_fail (MIDORI_IS_APP (app), FALSE); */
|
||||
g_return_val_if_fail (MIDORI_IS_APP (app), FALSE);
|
||||
g_return_val_if_fail (midori_app_instance_is_running (app), FALSE);
|
||||
|
||||
#if HAVE_HILDON
|
||||
osso_application_top (app->instance, PACKAGE_NAME, "new");
|
||||
#elif HAVE_UNIQUE
|
||||
#if HAVE_UNIQUE
|
||||
if (app->instance)
|
||||
{
|
||||
response = unique_app_send_message (app->instance, UNIQUE_NEW, NULL);
|
||||
UniqueResponse response = unique_app_send_message (app->instance, UNIQUE_NEW, NULL);
|
||||
if (response == UNIQUE_RESPONSE_OK)
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -1053,20 +1073,26 @@ gboolean
|
|||
midori_app_instance_send_uris (MidoriApp* app,
|
||||
gchar** uris)
|
||||
{
|
||||
#if HAVE_UNIQUE
|
||||
UniqueMessageData* message;
|
||||
UniqueResponse response;
|
||||
#endif
|
||||
|
||||
/* g_return_val_if_fail (MIDORI_IS_APP (app), FALSE); */
|
||||
g_return_val_if_fail (MIDORI_IS_APP (app), FALSE);
|
||||
g_return_val_if_fail (midori_app_instance_is_running (app), FALSE);
|
||||
g_return_val_if_fail (uris != NULL, FALSE);
|
||||
|
||||
#if HAVE_HILDON
|
||||
/* FIXME: Implement */
|
||||
#elif HAVE_UNIQUE
|
||||
#if HAVE_UNIQUE
|
||||
if (app->instance)
|
||||
{
|
||||
UniqueMessageData* message;
|
||||
UniqueResponse response;
|
||||
/* Encode any IDN addresses because libUnique doesn't like them */
|
||||
int i = 0;
|
||||
while (uris[i] != NULL)
|
||||
{
|
||||
gchar* new_uri = sokoke_magic_uri (uris[i], TRUE, TRUE);
|
||||
gchar* escaped_uri = g_uri_escape_string (new_uri, NULL, FALSE);
|
||||
g_free (new_uri);
|
||||
katze_assign (uris[i], escaped_uri);
|
||||
i++;
|
||||
}
|
||||
|
||||
message = unique_message_data_new ();
|
||||
unique_message_data_set_uris (message, uris);
|
||||
response = unique_app_send_message (app->instance, UNIQUE_OPEN, message);
|
||||
|
@ -1103,23 +1129,24 @@ gboolean
|
|||
midori_app_send_command (MidoriApp* app,
|
||||
gchar** command)
|
||||
{
|
||||
#if HAVE_UNIQUE
|
||||
UniqueMessageData* message;
|
||||
UniqueResponse response;
|
||||
#endif
|
||||
|
||||
/* g_return_val_if_fail (MIDORI_IS_APP (app), FALSE); */
|
||||
g_return_val_if_fail (MIDORI_IS_APP (app), FALSE);
|
||||
g_return_val_if_fail (command != NULL, FALSE);
|
||||
|
||||
if (!midori_app_instance_is_running (app))
|
||||
{
|
||||
MidoriBrowser* browser = midori_browser_new ();
|
||||
int i;
|
||||
for (i=0; command && command[i]; i++)
|
||||
midori_browser_assert_action (browser, command[i]);
|
||||
gtk_widget_destroy (GTK_WIDGET (browser));
|
||||
return midori_app_command_received (app, "command", command, NULL);
|
||||
}
|
||||
|
||||
#if HAVE_HILDON
|
||||
/* FIXME: Implement */
|
||||
#elif HAVE_UNIQUE
|
||||
#if HAVE_UNIQUE
|
||||
if (app->instance)
|
||||
{
|
||||
message = unique_message_data_new ();
|
||||
UniqueResponse response;
|
||||
UniqueMessageData* message = unique_message_data_new ();
|
||||
unique_message_data_set_uris (message, command);
|
||||
response = unique_app_send_message (app->instance,
|
||||
MIDORI_UNIQUE_COMMAND, message);
|
||||
|
@ -1160,6 +1187,17 @@ midori_app_add_browser (MidoriApp* app,
|
|||
g_signal_emit (app, signals[ADD_BROWSER], 0, browser);
|
||||
}
|
||||
|
||||
void
|
||||
midori_app_set_browsers (MidoriApp* app,
|
||||
KatzeArray* browsers,
|
||||
MidoriBrowser* browser)
|
||||
{
|
||||
g_return_if_fail (MIDORI_IS_APP (app));
|
||||
g_return_if_fail (KATZE_IS_ARRAY (browsers));
|
||||
katze_object_assign (app->browsers, g_object_ref (browsers));
|
||||
app->browser = browser;
|
||||
}
|
||||
|
||||
/**
|
||||
* midori_app_create_browser:
|
||||
* @app: a #MidoriApp
|
||||
|
@ -1263,17 +1301,13 @@ midori_app_send_notification (MidoriApp* app,
|
|||
g_return_if_fail (MIDORI_IS_APP (app));
|
||||
g_return_if_fail (title);
|
||||
|
||||
#if HAVE_HILDON
|
||||
hildon_banner_show_information_with_markup (GTK_WIDGET (app->browser),
|
||||
"midori", message);
|
||||
#elif HAVE_LIBNOTIFY
|
||||
#if HAVE_LIBNOTIFY
|
||||
if (notify_is_initted ())
|
||||
{
|
||||
NotifyNotification* note;
|
||||
#if NOTIFY_CHECK_VERSION (0, 7, 0)
|
||||
note = notify_notification_new (title, message, "midori");
|
||||
NotifyNotification* note = notify_notification_new (title, message, "midori");
|
||||
#else
|
||||
note = notify_notification_new (title, message, "midori", NULL);
|
||||
NotifyNotification* note = notify_notification_new (title, message, "midori", NULL);
|
||||
#endif
|
||||
notify_notification_show (note, NULL);
|
||||
g_object_unref (note);
|
||||
|
@ -1305,143 +1339,38 @@ midori_app_send_notification (MidoriApp* app,
|
|||
* Since: 0.4.2
|
||||
**/
|
||||
void
|
||||
midori_app_setup (gchar** argument_vector)
|
||||
midori_app_setup (gint *argc,
|
||||
gchar** *argument_vector,
|
||||
const GOptionEntry *entries)
|
||||
{
|
||||
GtkIconSource* icon_source;
|
||||
GtkIconSet* icon_set;
|
||||
GtkIconFactory* factory;
|
||||
gsize i;
|
||||
GError* error = NULL;
|
||||
gboolean success;
|
||||
|
||||
typedef struct
|
||||
static GtkStockItem items[] =
|
||||
{
|
||||
const gchar* stock_id;
|
||||
const gchar* label;
|
||||
GdkModifierType modifier;
|
||||
guint keyval;
|
||||
const gchar* fallback;
|
||||
} FatStockItem;
|
||||
static FatStockItem items[] =
|
||||
{
|
||||
{ STOCK_EXTENSION, NULL, 0, 0, GTK_STOCK_CONVERT },
|
||||
{ STOCK_IMAGE, NULL, 0, 0, GTK_STOCK_ORIENTATION_PORTRAIT },
|
||||
{ STOCK_WEB_BROWSER, NULL, 0, 0, "gnome-web-browser" },
|
||||
{ STOCK_NEWS_FEED, NULL, 0, 0, GTK_STOCK_INDEX },
|
||||
{ STOCK_SCRIPT, NULL, 0, 0, GTK_STOCK_EXECUTE },
|
||||
{ STOCK_STYLE, NULL, 0, 0, GTK_STOCK_SELECT_COLOR },
|
||||
{ STOCK_TRANSFER, NULL, 0, 0, GTK_STOCK_SAVE },
|
||||
{ STOCK_IMAGE },
|
||||
{ MIDORI_STOCK_WEB_BROWSER },
|
||||
{ STOCK_NEWS_FEED },
|
||||
{ STOCK_STYLE },
|
||||
|
||||
{ STOCK_BOOKMARK, N_("_Bookmark"), 0, 0, GTK_STOCK_FILE },
|
||||
{ STOCK_BOOKMARKS, N_("_Bookmarks"), GDK_CONTROL_MASK | GDK_SHIFT_MASK, GDK_KEY_B, GTK_STOCK_DIRECTORY },
|
||||
{ STOCK_BOOKMARK_ADD, N_("Add Boo_kmark"), 0, 0, "stock_add-bookmark" },
|
||||
{ STOCK_CONSOLE, N_("_Console"), 0, 0, GTK_STOCK_DIALOG_WARNING },
|
||||
{ STOCK_EXTENSIONS, N_("_Extensions"), 0, 0, GTK_STOCK_CONVERT },
|
||||
{ STOCK_HISTORY, N_("_History"), GDK_CONTROL_MASK | GDK_SHIFT_MASK, GDK_KEY_H, GTK_STOCK_SORT_ASCENDING },
|
||||
{ STOCK_HOMEPAGE, N_("_Homepage"), 0, 0, GTK_STOCK_HOME },
|
||||
{ STOCK_SCRIPTS, N_("_Userscripts"), 0, 0, GTK_STOCK_EXECUTE },
|
||||
{ STOCK_TAB_NEW, N_("New _Tab"), 0, 0, GTK_STOCK_ADD },
|
||||
{ STOCK_TRANSFERS, N_("_Transfers"), GDK_CONTROL_MASK | GDK_SHIFT_MASK, GDK_KEY_J, GTK_STOCK_SAVE },
|
||||
{ STOCK_PLUGINS, N_("Netscape p_lugins"), 0, 0, GTK_STOCK_CONVERT },
|
||||
{ STOCK_USER_TRASH, N_("_Closed Tabs"), 0, 0, "gtk-undo-ltr" },
|
||||
{ STOCK_WINDOW_NEW, N_("New _Window"), 0, 0, GTK_STOCK_ADD },
|
||||
{ GTK_STOCK_DIRECTORY, N_("New _Folder"), 0, 0, NULL },
|
||||
{ STOCK_BOOKMARKS, N_("_Bookmarks"), GDK_CONTROL_MASK | GDK_SHIFT_MASK, GDK_KEY_B },
|
||||
{ STOCK_BOOKMARK_ADD, N_("Add Boo_kmark") },
|
||||
{ STOCK_EXTENSION, N_("_Extensions") },
|
||||
{ STOCK_HISTORY, N_("_History"), GDK_CONTROL_MASK | GDK_SHIFT_MASK, GDK_KEY_H },
|
||||
{ STOCK_SCRIPT, N_("_Userscripts") },
|
||||
{ STOCK_STYLE, N_("User_styles") },
|
||||
{ STOCK_TAB_NEW, N_("New _Tab") },
|
||||
{ MIDORI_STOCK_TRANSFER, N_("_Transfers"), GDK_CONTROL_MASK | GDK_SHIFT_MASK, GDK_KEY_J },
|
||||
{ MIDORI_STOCK_PLUGINS, N_("Netscape p_lugins") },
|
||||
{ STOCK_USER_TRASH, N_("_Closed Tabs") },
|
||||
{ STOCK_WINDOW_NEW, N_("New _Window") },
|
||||
{ STOCK_FOLDER_NEW, N_("New _Folder") },
|
||||
};
|
||||
|
||||
/* Preserve argument vector */
|
||||
sokoke_get_argv (argument_vector);
|
||||
|
||||
/* libSoup uses threads, therefore if WebKit is built with libSoup
|
||||
* or Midori is using it, we need to initialize threads. */
|
||||
if (!g_thread_supported ()) g_thread_init (NULL);
|
||||
|
||||
#if ENABLE_NLS
|
||||
setlocale (LC_ALL, "");
|
||||
if (g_getenv ("MIDORI_NLSPATH"))
|
||||
bindtextdomain (GETTEXT_PACKAGE, g_getenv ("MIDORI_NLSPATH"));
|
||||
else
|
||||
#ifdef G_OS_WIN32
|
||||
{
|
||||
gchar* path = sokoke_find_data_filename ("locale", FALSE);
|
||||
bindtextdomain (GETTEXT_PACKAGE, path);
|
||||
g_free (path);
|
||||
}
|
||||
#else
|
||||
bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
|
||||
#endif
|
||||
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
|
||||
textdomain (GETTEXT_PACKAGE);
|
||||
#endif
|
||||
|
||||
g_type_init ();
|
||||
factory = gtk_icon_factory_new ();
|
||||
for (i = 0; i < G_N_ELEMENTS (items); i++)
|
||||
{
|
||||
icon_set = gtk_icon_set_new ();
|
||||
icon_source = gtk_icon_source_new ();
|
||||
if (items[i].fallback)
|
||||
{
|
||||
gtk_icon_source_set_icon_name (icon_source, items[i].fallback);
|
||||
items[i].fallback = NULL;
|
||||
gtk_icon_set_add_source (icon_set, icon_source);
|
||||
}
|
||||
gtk_icon_source_set_icon_name (icon_source, items[i].stock_id);
|
||||
gtk_icon_set_add_source (icon_set, icon_source);
|
||||
gtk_icon_source_free (icon_source);
|
||||
gtk_icon_factory_add (factory, items[i].stock_id, icon_set);
|
||||
gtk_icon_set_unref (icon_set);
|
||||
}
|
||||
gtk_stock_add_static ((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
|
||||
|
||||
/* Print messages to stdout on Win32 console, cf. AbiWord
|
||||
* http://svn.abisource.com/abiword/trunk/src/wp/main/win/Win32Main.cpp */
|
||||
#ifdef _WIN32
|
||||
|
@ -1464,5 +1393,117 @@ midori_app_setup (gchar** argument_vector)
|
|||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* libSoup uses threads, therefore if WebKit is built with libSoup
|
||||
* or Midori is using it, we need to initialize threads. */
|
||||
#if !GLIB_CHECK_VERSION (2, 32, 0)
|
||||
if (!g_thread_supported ()) g_thread_init (NULL);
|
||||
#endif
|
||||
|
||||
/* Midori.Paths uses GFile */
|
||||
g_type_init ();
|
||||
/* Preserve argument vector */
|
||||
midori_paths_init_exec_path (*argument_vector, *argc);
|
||||
|
||||
#if ENABLE_NLS
|
||||
if (g_getenv ("MIDORI_NLSPATH"))
|
||||
bindtextdomain (GETTEXT_PACKAGE, g_getenv ("MIDORI_NLSPATH"));
|
||||
else
|
||||
#ifdef G_OS_WIN32
|
||||
{
|
||||
gchar* path = midori_paths_get_data_filename ("locale", FALSE);
|
||||
bindtextdomain (GETTEXT_PACKAGE, path);
|
||||
g_free (path);
|
||||
}
|
||||
#else
|
||||
bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
|
||||
#endif
|
||||
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
|
||||
textdomain (GETTEXT_PACKAGE);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_GRANITE_CLUTTER
|
||||
success = gtk_clutter_init_with_args (argc, argument_vector, _("[Addresses]"),
|
||||
(GOptionEntry*)entries, GETTEXT_PACKAGE, &error);
|
||||
#elif GTK_CHECK_VERSION (3, 0, 0)
|
||||
success = gtk_init_with_args (argc, argument_vector, _("[Addresses]"),
|
||||
entries, GETTEXT_PACKAGE, &error);
|
||||
#else
|
||||
success = gtk_init_with_args (argc, argument_vector, _("[Addresses]"),
|
||||
(GOptionEntry*)entries, GETTEXT_PACKAGE, &error);
|
||||
#endif
|
||||
|
||||
factory = gtk_icon_factory_new ();
|
||||
for (i = 0; i < G_N_ELEMENTS (items); i++)
|
||||
{
|
||||
icon_set = gtk_icon_set_new ();
|
||||
icon_source = gtk_icon_source_new ();
|
||||
gtk_icon_source_set_icon_name (icon_source, items[i].stock_id);
|
||||
gtk_icon_set_add_source (icon_set, icon_source);
|
||||
gtk_icon_source_free (icon_source);
|
||||
gtk_icon_factory_add (factory, items[i].stock_id, icon_set);
|
||||
gtk_icon_set_unref (icon_set);
|
||||
}
|
||||
gtk_stock_add_static ((GtkStockItem*)items, G_N_ELEMENTS (items));
|
||||
gtk_icon_factory_add_default (factory);
|
||||
g_object_unref (factory);
|
||||
|
||||
if (!success)
|
||||
midori_error (error->message);
|
||||
}
|
||||
|
||||
void
|
||||
midori_error (const gchar* format,
|
||||
...)
|
||||
{
|
||||
g_printerr ("%s - ", g_get_application_name ());
|
||||
va_list args;
|
||||
va_start (args, format);
|
||||
g_vfprintf (stderr, format, args);
|
||||
va_end (args);
|
||||
g_printerr ("\n");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
gboolean
|
||||
midori_debug (const gchar* token)
|
||||
{
|
||||
static const gchar* debug_token = NULL;
|
||||
const gchar* debug_tokens = "headers body referer cookies paths hsts unarmed bookmarks ";
|
||||
const gchar* full_debug_tokens = "adblock:match adblock:time startup ";
|
||||
if (debug_token == NULL)
|
||||
{
|
||||
gchar* found_token;
|
||||
const gchar* debug = g_getenv ("MIDORI_DEBUG");
|
||||
const gchar* legacy_touchscreen = g_getenv ("MIDORI_TOUCHSCREEN");
|
||||
if (legacy_touchscreen && *legacy_touchscreen)
|
||||
g_warning ("MIDORI_TOUCHSCREEN is obsolete: "
|
||||
"GTK+ 3.4 enables touchscreens automatically, "
|
||||
"older GTK+ versions aren't supported as of Midori 0.4.9");
|
||||
if (debug && (found_token = strstr (full_debug_tokens, debug)) && *(found_token + strlen (debug)) == ' ')
|
||||
{
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
debug_token = g_intern_static_string (debug);
|
||||
#else
|
||||
g_warning ("Value '%s' for MIDORI_DEBUG requires a full debugging build.", debug);
|
||||
#endif
|
||||
}
|
||||
else if (debug && (found_token = strstr (debug_tokens, debug)) && *(found_token + strlen (debug)) == ' ')
|
||||
debug_token = g_intern_static_string (debug);
|
||||
else if (debug)
|
||||
g_warning ("Unrecognized value '%s' for MIDORI_DEBUG.", debug);
|
||||
else
|
||||
debug_token = "NONE";
|
||||
if (!debug_token)
|
||||
{
|
||||
debug_token = "INVALID";
|
||||
g_print ("Supported values: %s\nWith full debugging: %s\n",
|
||||
debug_tokens, full_debug_tokens);
|
||||
}
|
||||
}
|
||||
if (debug_token != g_intern_static_string ("NONE")
|
||||
&& !strstr (debug_tokens, token) && !strstr (full_debug_tokens, token))
|
||||
g_warning ("Token '%s' passed to midori_debug is not a known token.", token);
|
||||
return debug_token == g_intern_static_string (token);
|
||||
}
|
||||
|
||||
|
|
|
@ -39,7 +39,19 @@ GType
|
|||
midori_app_get_type (void) G_GNUC_CONST;
|
||||
|
||||
MidoriApp*
|
||||
midori_app_new (void);
|
||||
midori_app_new (const gchar* name);
|
||||
|
||||
MidoriApp*
|
||||
midori_app_new_proxy (MidoriApp* app);
|
||||
|
||||
const gchar*
|
||||
midori_app_get_name (MidoriApp* app);
|
||||
|
||||
gboolean
|
||||
midori_app_get_crashed (MidoriApp* app);
|
||||
|
||||
void
|
||||
midori_app_set_instance_is_running(gboolean is_running);
|
||||
|
||||
gboolean
|
||||
midori_app_instance_is_running (MidoriApp* app);
|
||||
|
@ -80,7 +92,16 @@ midori_app_send_notification (MidoriApp* app,
|
|||
const gchar* message);
|
||||
|
||||
void
|
||||
midori_app_setup (gchar** argument_vector);
|
||||
midori_app_setup (gint *argc,
|
||||
gchar** *argument_vector,
|
||||
const GOptionEntry *entries);
|
||||
|
||||
gboolean
|
||||
midori_debug (const gchar* token);
|
||||
|
||||
void
|
||||
midori_error (const gchar* format,
|
||||
...);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
|
|
@ -35,7 +35,8 @@ katze_xbel_parse_info (KatzeItem* item,
|
|||
xmlNodePtr cur);
|
||||
|
||||
static gchar*
|
||||
katze_item_metadata_to_xbel (KatzeItem* item);
|
||||
katze_item_metadata_to_xbel (KatzeItem* item,
|
||||
gboolean tiny_xbel);
|
||||
|
||||
#if HAVE_LIBXML
|
||||
static KatzeItem*
|
||||
|
@ -50,9 +51,17 @@ katze_item_from_xmlNodePtr (xmlNodePtr cur)
|
|||
while (cur)
|
||||
{
|
||||
if (katze_str_equal ((gchar*)cur->name, "title"))
|
||||
item->name = g_strstrip ((gchar*)xmlNodeGetContent (cur));
|
||||
{
|
||||
gchar* value = g_strstrip ((gchar*)xmlNodeGetContent (cur));
|
||||
katze_item_set_name (item, value);
|
||||
xmlFree (value);
|
||||
}
|
||||
else if (katze_str_equal ((gchar*)cur->name, "desc"))
|
||||
item->text = g_strstrip ((gchar*)xmlNodeGetContent (cur));
|
||||
{
|
||||
gchar* value = g_strstrip ((gchar*)xmlNodeGetContent (cur));
|
||||
katze_item_set_text (item, value);
|
||||
xmlFree (value);
|
||||
}
|
||||
else if (katze_str_equal ((gchar*)cur->name, "info"))
|
||||
katze_xbel_parse_info (item, cur);
|
||||
cur = cur->next;
|
||||
|
@ -86,9 +95,17 @@ katze_array_from_xmlNodePtr (xmlNodePtr cur)
|
|||
while (cur)
|
||||
{
|
||||
if (katze_str_equal ((gchar*)cur->name, "title"))
|
||||
((KatzeItem*)array)->name = g_strstrip ((gchar*)xmlNodeGetContent (cur));
|
||||
{
|
||||
gchar* value = g_strstrip ((gchar*)xmlNodeGetContent (cur));
|
||||
katze_item_set_text (KATZE_ITEM (array), value);
|
||||
xmlFree (value);
|
||||
}
|
||||
else if (katze_str_equal ((gchar*)cur->name, "desc"))
|
||||
((KatzeItem*)array)->text = g_strstrip ((gchar*)xmlNodeGetContent (cur));
|
||||
{
|
||||
gchar* value = g_strstrip ((gchar*)xmlNodeGetContent (cur));
|
||||
katze_item_set_name (KATZE_ITEM (array), value);
|
||||
xmlFree (value);
|
||||
}
|
||||
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"))
|
||||
|
@ -187,13 +204,12 @@ katze_xbel_parse_info (KatzeItem* item,
|
|||
/* Loads the contents from an xmlNodePtr into an array. */
|
||||
static gboolean
|
||||
katze_array_from_xmlDocPtr (KatzeArray* array,
|
||||
gboolean tiny_xbel,
|
||||
xmlDocPtr doc)
|
||||
{
|
||||
xmlNodePtr cur;
|
||||
KatzeItem* item;
|
||||
|
||||
cur = xmlDocGetRootElement (doc);
|
||||
|
||||
if ((cur = xmlDocGetRootElement (doc)) == NULL)
|
||||
{
|
||||
/* Empty document */
|
||||
|
@ -205,17 +221,17 @@ katze_array_from_xmlDocPtr (KatzeArray* array,
|
|||
gchar* value;
|
||||
|
||||
value = (gchar*)xmlGetProp (cur, (xmlChar*)"version");
|
||||
if (!value || !katze_str_equal (value, "1.0"))
|
||||
if (!tiny_xbel && (!value || !katze_str_equal (value, "1.0")))
|
||||
g_warning ("XBEL version is not 1.0.");
|
||||
g_free (value);
|
||||
xmlFree (value);
|
||||
|
||||
value = (gchar*)xmlGetProp (cur, (xmlChar*)"title");
|
||||
katze_item_set_name (KATZE_ITEM (array), value);
|
||||
g_free (value);
|
||||
xmlFree (value);
|
||||
|
||||
value = (gchar*)xmlGetProp (cur, (xmlChar*)"desc");
|
||||
katze_item_set_text (KATZE_ITEM (array), value);
|
||||
g_free (value);
|
||||
xmlFree (value);
|
||||
}
|
||||
else if (katze_str_equal ((gchar*)cur->name, "RDF"))
|
||||
{
|
||||
|
@ -227,21 +243,28 @@ katze_array_from_xmlDocPtr (KatzeArray* array,
|
|||
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));
|
||||
{
|
||||
gchar* value = g_strstrip ((gchar*)xmlNodeGetContent (cur_item));
|
||||
katze_item_set_name (item, value);
|
||||
xmlFree (value);
|
||||
}
|
||||
else if (katze_str_equal ((gchar*)cur_item->name, "link"))
|
||||
item->uri = g_strstrip ((gchar*)xmlNodeGetContent (cur_item));
|
||||
{
|
||||
gchar* value = g_strstrip ((gchar*)xmlNodeGetContent (cur_item));
|
||||
katze_item_set_uri (item, value);
|
||||
xmlFree (value);
|
||||
}
|
||||
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);
|
||||
xmlFree (value);
|
||||
}
|
||||
cur_item = cur_item->next;
|
||||
}
|
||||
|
@ -378,7 +401,11 @@ katze_array_from_netscape_file (KatzeArray* array,
|
|||
if (item && katze_str_equal (element[1], "DD"))
|
||||
{
|
||||
if (element[2])
|
||||
item->text = katze_unescape_html (element[2]);
|
||||
{
|
||||
gchar* text = katze_unescape_html (element[2]);
|
||||
katze_item_set_text (item, text);
|
||||
g_free (text);
|
||||
}
|
||||
item = NULL;
|
||||
}
|
||||
/* end of current folder, level-up */
|
||||
|
@ -459,16 +486,16 @@ katze_array_from_opera_file (KatzeArray* array,
|
|||
if (parts && parts[0] && parts[1])
|
||||
{
|
||||
if (katze_str_equal (parts[0], "NAME"))
|
||||
item->name = g_strdup (parts[1]);
|
||||
katze_item_set_name (item, parts[1]);
|
||||
else if (katze_str_equal (parts[0], "URL"))
|
||||
item->uri = g_strdup (parts[1]);
|
||||
katze_item_set_uri (item, parts[1]);
|
||||
else if (katze_str_equal (parts[0], "DESCRIPTION"))
|
||||
item->text = g_strdup (parts[1]);
|
||||
katze_item_set_text (item, parts[1]);
|
||||
else if (katze_str_equal (parts[0], "CREATED"))
|
||||
item->added = g_ascii_strtoull (parts[1], NULL, 10);
|
||||
katze_item_set_added (item, 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); */
|
||||
katze_item_set_visited (item, 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);
|
||||
|
@ -597,6 +624,7 @@ midori_array_from_file (KatzeArray* array,
|
|||
|
||||
/* XBEL */
|
||||
if (katze_str_equal (format, "xbel")
|
||||
|| katze_str_equal (format, "xbel-tiny")
|
||||
|| !*format)
|
||||
{
|
||||
xmlDocPtr doc;
|
||||
|
@ -610,7 +638,7 @@ midori_array_from_file (KatzeArray* array,
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
if (!katze_array_from_xmlDocPtr (array, doc))
|
||||
if (!katze_array_from_xmlDocPtr (array, katze_str_equal (format, "xbel-tiny"), doc))
|
||||
{
|
||||
/* Parsing failed */
|
||||
xmlFreeDoc (doc);
|
||||
|
@ -701,13 +729,14 @@ string_append_xml_element (GString* string,
|
|||
|
||||
static void
|
||||
string_append_item (GString* string,
|
||||
KatzeItem* item)
|
||||
KatzeItem* item,
|
||||
gboolean tiny_xbel)
|
||||
{
|
||||
gchar* metadata;
|
||||
|
||||
g_return_if_fail (KATZE_IS_ITEM (item));
|
||||
|
||||
metadata = katze_item_metadata_to_xbel (item);
|
||||
metadata = katze_item_metadata_to_xbel (item, tiny_xbel);
|
||||
if (KATZE_IS_ARRAY (item))
|
||||
{
|
||||
KatzeItem* _item;
|
||||
|
@ -719,7 +748,7 @@ string_append_item (GString* string,
|
|||
string_append_xml_element (string, "title", katze_item_get_name (item));
|
||||
string_append_xml_element (string, "desc", katze_item_get_text (item));
|
||||
KATZE_ARRAY_FOREACH_ITEM_L (_item, array, list)
|
||||
string_append_item (string, _item);
|
||||
string_append_item (string, _item, tiny_xbel);
|
||||
g_string_append (string, metadata);
|
||||
g_string_append (string, "</folder>\n");
|
||||
g_list_free (list);
|
||||
|
@ -729,7 +758,12 @@ string_append_item (GString* string,
|
|||
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));
|
||||
/* Strip LRE leading character */
|
||||
if (item->name != NULL && g_str_has_prefix (item->name, ""))
|
||||
string_append_xml_element (string, "title",
|
||||
g_utf8_next_char (strstr (item->name, "")));
|
||||
else
|
||||
string_append_xml_element (string, "title", item->name);
|
||||
string_append_xml_element (string, "desc", katze_item_get_text (item));
|
||||
g_string_append (string, metadata);
|
||||
g_string_append (string, "</bookmark>\n");
|
||||
|
@ -772,7 +806,7 @@ string_append_netscape_item (GString* string,
|
|||
string_append_escaped (string, katze_item_get_name (item));
|
||||
g_string_append (string, "</A>\n");
|
||||
|
||||
if (item->text && g_strcmp0 (item->text, ""))
|
||||
if (g_strcmp0 (katze_str_non_null (katze_item_get_text (item)), ""))
|
||||
{
|
||||
g_string_append (string, "\t<DD>");
|
||||
string_append_escaped (string, katze_item_get_text (item));
|
||||
|
@ -782,7 +816,8 @@ string_append_netscape_item (GString* string,
|
|||
}
|
||||
|
||||
static gchar*
|
||||
katze_item_metadata_to_xbel (KatzeItem* item)
|
||||
katze_item_metadata_to_xbel (KatzeItem* item,
|
||||
gboolean tiny_xbel)
|
||||
{
|
||||
GList* keys = katze_item_get_meta_keys (item);
|
||||
GString* markup;
|
||||
|
@ -812,7 +847,7 @@ katze_item_metadata_to_xbel (KatzeItem* item)
|
|||
string_append_escaped (markdown, value);
|
||||
g_string_append_printf (markdown, "</%s>\n", key);
|
||||
}
|
||||
else if (namespace)
|
||||
else if (namespace || tiny_xbel)
|
||||
{
|
||||
g_string_append_printf (markup, " %s=\"", key);
|
||||
string_append_escaped (markup, value);
|
||||
|
@ -825,7 +860,7 @@ katze_item_metadata_to_xbel (KatzeItem* item)
|
|||
g_string_append_c (markup, '\"');
|
||||
}
|
||||
}
|
||||
if (!namespace)
|
||||
if (!namespace && !tiny_xbel)
|
||||
{
|
||||
namespace_uri = "http://www.twotoasts.de";
|
||||
g_string_append_printf (markup, " owner=\"%s\"", namespace_uri);
|
||||
|
@ -840,25 +875,27 @@ katze_item_metadata_to_xbel (KatzeItem* item)
|
|||
|
||||
static gchar*
|
||||
katze_array_to_xbel (KatzeArray* array,
|
||||
gboolean tiny_xbel,
|
||||
GError** error)
|
||||
{
|
||||
gchar* metadata = katze_item_metadata_to_xbel (KATZE_ITEM (array));
|
||||
gchar* metadata = katze_item_metadata_to_xbel (KATZE_ITEM (array), tiny_xbel);
|
||||
KatzeItem* item;
|
||||
GList* list;
|
||||
|
||||
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");
|
||||
GString* markup = g_string_new ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
|
||||
if (tiny_xbel)
|
||||
g_string_append (markup, "<xbel>\n");
|
||||
else
|
||||
g_string_append (markup,
|
||||
"<!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 ? metadata : "");
|
||||
KATZE_ARRAY_FOREACH_ITEM_L (item, array, list)
|
||||
string_append_item (markup, item);
|
||||
string_append_item (markup, item, tiny_xbel);
|
||||
g_string_append (markup, "</xbel>\n");
|
||||
|
||||
g_free (metadata);
|
||||
|
@ -901,24 +938,20 @@ midori_array_to_file_format (KatzeArray* array,
|
|||
GError** error)
|
||||
{
|
||||
gchar* data;
|
||||
FILE* fp;
|
||||
gboolean success;
|
||||
|
||||
if (!g_strcmp0 (format, "xbel"))
|
||||
data = katze_array_to_xbel (array, error);
|
||||
data = katze_array_to_xbel (array, FALSE, error);
|
||||
else if (!g_strcmp0 (format, "xbel-tiny"))
|
||||
data = katze_array_to_xbel (array, TRUE, error);
|
||||
else if (!g_strcmp0 (format, "netscape"))
|
||||
data = katze_array_to_netscape_html (array, error);
|
||||
else
|
||||
return FALSE;
|
||||
if (!(fp = fopen (filename, "w")))
|
||||
{
|
||||
*error = g_error_new_literal (G_FILE_ERROR, G_FILE_ERROR_ACCES,
|
||||
_("Writing failed."));
|
||||
return FALSE;
|
||||
}
|
||||
fputs (data, fp);
|
||||
fclose (fp);
|
||||
|
||||
success = g_file_set_contents (filename, data, -1, error);
|
||||
g_free (data);
|
||||
return TRUE;
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -945,6 +978,7 @@ midori_array_to_file (KatzeArray* array,
|
|||
g_return_val_if_fail (!error || !*error, FALSE);
|
||||
|
||||
if (!g_strcmp0 (format, "xbel")
|
||||
|| !g_strcmp0 (format, "xbel-tiny")
|
||||
|| !g_strcmp0 (format, "netscape"))
|
||||
return midori_array_to_file_format (array, filename, format, error);
|
||||
|
||||
|
@ -967,41 +1001,44 @@ katze_item_set_value_from_column (sqlite3_stmt* stmt,
|
|||
const unsigned char* uri;
|
||||
uri = sqlite3_column_text (stmt, column);
|
||||
if (uri && uri[0] && uri[0] != '(')
|
||||
item->uri = g_strdup ((gchar*)uri);
|
||||
katze_item_set_uri (item, (gchar*)uri);
|
||||
}
|
||||
else if (g_str_equal (name, "title") || g_str_equal (name, "name"))
|
||||
{
|
||||
const unsigned char* title;
|
||||
title = sqlite3_column_text (stmt, column);
|
||||
item->name = g_strdup ((gchar*)title);
|
||||
katze_item_set_name (item, (gchar*)title);
|
||||
}
|
||||
else if (g_str_equal (name, "date"))
|
||||
else if (g_str_equal (name, "date") || g_str_equal (name, "created"))
|
||||
{
|
||||
gint date;
|
||||
date = sqlite3_column_int64 (stmt, column);
|
||||
item->added = date;
|
||||
katze_item_set_added (item, date);
|
||||
}
|
||||
else if (g_str_equal (name, "day") || g_str_equal (name, "app")
|
||||
|| g_str_equal (name, "toolbar"))
|
||||
|| g_str_equal (name, "toolbar") || g_str_equal (name, "id")
|
||||
|| g_str_equal (name, "parentid") || g_str_equal (name, "seq")
|
||||
|| g_str_equal (name, "last_visit") || g_str_equal (name, "visit_count")
|
||||
|| g_str_equal (name, "pos_panel") || g_str_equal (name, "pos_bar"))
|
||||
{
|
||||
gint value;
|
||||
value = sqlite3_column_int64 (stmt, column);
|
||||
katze_item_set_meta_integer (item, name, value);
|
||||
}
|
||||
else if (g_str_equal (name, "folder"))
|
||||
{
|
||||
const unsigned char* folder;
|
||||
folder = sqlite3_column_text (stmt, column);
|
||||
katze_item_set_meta_string (item, name, (gchar*)folder);
|
||||
}
|
||||
else if (g_str_equal (name, "desc"))
|
||||
{
|
||||
const unsigned char* text;
|
||||
text = sqlite3_column_text (stmt, column);
|
||||
item->text = g_strdup ((gchar*)text);
|
||||
katze_item_set_text (item, (gchar*)text);
|
||||
}
|
||||
else if (g_str_equal (name, "nick"))
|
||||
{
|
||||
const unsigned char* sql;
|
||||
sql = sqlite3_column_text (stmt, column);
|
||||
katze_item_set_meta_string (item, name, (gchar*)sql);
|
||||
}
|
||||
else
|
||||
g_warn_if_reached ();
|
||||
g_critical ("%s: Unexpected column '%s'", G_STRFUNC, name);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1066,6 +1103,73 @@ katze_array_from_sqlite (sqlite3* db,
|
|||
return katze_array_from_statement (stmt);
|
||||
}
|
||||
|
||||
/**
|
||||
* midori_array_query_recursive:
|
||||
* @array: the main bookmark array
|
||||
* @fields: comma separated list of fields
|
||||
* @condition: condition, like "folder = '%q'"
|
||||
* @value: a value to be inserted if @condition contains %q
|
||||
* @recursive: if %TRUE include children
|
||||
*
|
||||
* Stores the result in a #KatzeArray.
|
||||
*
|
||||
* Return value: a #KatzeArray on success, %NULL otherwise
|
||||
*
|
||||
* Since: 0.4.4
|
||||
**/
|
||||
KatzeArray*
|
||||
midori_array_query_recursive (KatzeArray* bookmarks,
|
||||
const gchar* fields,
|
||||
const gchar* condition,
|
||||
const gchar* value,
|
||||
gboolean recursive)
|
||||
{
|
||||
sqlite3* db;
|
||||
gchar* sqlcmd;
|
||||
char* sqlcmd_value;
|
||||
KatzeArray* array;
|
||||
KatzeItem* item;
|
||||
GList* list;
|
||||
|
||||
g_return_val_if_fail (KATZE_IS_ARRAY (bookmarks), NULL);
|
||||
g_return_val_if_fail (fields, NULL);
|
||||
g_return_val_if_fail (condition, NULL);
|
||||
db = g_object_get_data (G_OBJECT (bookmarks), "db");
|
||||
g_return_val_if_fail (db != NULL, NULL);
|
||||
|
||||
sqlcmd = g_strdup_printf ("SELECT %s FROM bookmarks WHERE %s "
|
||||
"ORDER BY (uri='') ASC, title DESC", fields, condition);
|
||||
if (strstr (condition, "%q"))
|
||||
{
|
||||
sqlcmd_value = sqlite3_mprintf (sqlcmd, value ? value : "");
|
||||
array = katze_array_from_sqlite (db, sqlcmd_value);
|
||||
sqlite3_free (sqlcmd_value);
|
||||
}
|
||||
else
|
||||
array = katze_array_from_sqlite (db, sqlcmd);
|
||||
g_free (sqlcmd);
|
||||
|
||||
if (!recursive)
|
||||
return array;
|
||||
|
||||
KATZE_ARRAY_FOREACH_ITEM_L (item, array, list)
|
||||
{
|
||||
if (KATZE_ITEM_IS_FOLDER (item))
|
||||
{
|
||||
gchar* parentid = g_strdup_printf ("%" G_GINT64_FORMAT,
|
||||
katze_item_get_meta_integer (item, "id"));
|
||||
KatzeArray* subarray = midori_array_query_recursive (bookmarks,
|
||||
fields, "parentid=%q", parentid, TRUE);
|
||||
katze_item_set_name (KATZE_ITEM (subarray), katze_item_get_name (item));
|
||||
katze_array_add_item (array, subarray);
|
||||
|
||||
g_free (parentid);
|
||||
}
|
||||
}
|
||||
g_list_free (list);
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* midori_array_query:
|
||||
* @array: the main bookmark array
|
||||
|
@ -1078,6 +1182,8 @@ katze_array_from_sqlite (sqlite3* db,
|
|||
* Return value: a #KatzeArray on success, %NULL otherwise
|
||||
*
|
||||
* Since: 0.4.3
|
||||
*
|
||||
* Deprecated: 0.4.4: Use midori_array_query_recursive() instead.
|
||||
**/
|
||||
KatzeArray*
|
||||
midori_array_query (KatzeArray* bookmarks,
|
||||
|
@ -1085,29 +1191,6 @@ midori_array_query (KatzeArray* bookmarks,
|
|||
const gchar* condition,
|
||||
const gchar* value)
|
||||
{
|
||||
sqlite3* db;
|
||||
gchar* sqlcmd;
|
||||
char* sqlcmd_value;
|
||||
KatzeArray* array;
|
||||
|
||||
g_return_val_if_fail (KATZE_IS_ARRAY (bookmarks), NULL);
|
||||
g_return_val_if_fail (fields, NULL);
|
||||
g_return_val_if_fail (condition, NULL);
|
||||
db = g_object_get_data (G_OBJECT (bookmarks), "db");
|
||||
if (db == NULL)
|
||||
return NULL;
|
||||
|
||||
sqlcmd = g_strdup_printf ("SELECT %s FROM bookmarks WHERE %s "
|
||||
"ORDER BY title DESC", fields, condition);
|
||||
if (strstr (condition, "%q"))
|
||||
{
|
||||
sqlcmd_value = sqlite3_mprintf (sqlcmd, value ? value : "");
|
||||
array = katze_array_from_sqlite (db, sqlcmd_value);
|
||||
sqlite3_free (sqlcmd_value);
|
||||
}
|
||||
else
|
||||
array = katze_array_from_sqlite (db, sqlcmd);
|
||||
g_free (sqlcmd);
|
||||
return array;
|
||||
return midori_array_query_recursive (bookmarks, fields, condition, value, FALSE);
|
||||
}
|
||||
|
||||
|
|
|
@ -36,6 +36,13 @@ midori_array_query (KatzeArray* array,
|
|||
const gchar* condition,
|
||||
const gchar* value);
|
||||
|
||||
KatzeArray*
|
||||
midori_array_query_recursive (KatzeArray* array,
|
||||
const gchar* fields,
|
||||
const gchar* condition,
|
||||
const gchar* value,
|
||||
gboolean recursive);
|
||||
|
||||
KatzeArray*
|
||||
katze_array_from_sqlite (sqlite3* db,
|
||||
const gchar* sqlcmd);
|
||||
|
|
327
midori/midori-bookmarks.c
Normal file
327
midori/midori-bookmarks.c
Normal file
|
@ -0,0 +1,327 @@
|
|||
/*
|
||||
Copyright (C) 2010 Christian Dywan <christian@twotoasts.de>
|
||||
Copyright (C) 2010 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-bookmarks.h"
|
||||
#include "panels/midori-bookmarks.h"
|
||||
#include "midori-app.h"
|
||||
#include "midori-array.h"
|
||||
#include "sokoke.h"
|
||||
#include "midori-core.h"
|
||||
|
||||
#include <glib/gstdio.h>
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include <config.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
void
|
||||
midori_bookmarks_dbtracer (void* dummy,
|
||||
const char* query)
|
||||
{
|
||||
g_printerr ("%s\n", query);
|
||||
}
|
||||
|
||||
void
|
||||
midori_bookmarks_add_item_cb (KatzeArray* array,
|
||||
KatzeItem* item,
|
||||
sqlite3* db)
|
||||
{
|
||||
midori_bookmarks_insert_item_db (db, item,
|
||||
katze_item_get_meta_integer (item, "parentid"));
|
||||
}
|
||||
|
||||
void
|
||||
midori_bookmarks_remove_item_cb (KatzeArray* array,
|
||||
KatzeItem* item,
|
||||
sqlite3* db)
|
||||
{
|
||||
gchar* sqlcmd;
|
||||
char* errmsg = NULL;
|
||||
|
||||
|
||||
sqlcmd = sqlite3_mprintf (
|
||||
"DELETE FROM bookmarks WHERE id = %" G_GINT64_FORMAT ";",
|
||||
katze_item_get_meta_integer (item, "id"));
|
||||
|
||||
if (sqlite3_exec (db, sqlcmd, NULL, NULL, &errmsg) != SQLITE_OK)
|
||||
{
|
||||
g_printerr (_("Failed to remove history item: %s\n"), errmsg);
|
||||
sqlite3_free (errmsg);
|
||||
}
|
||||
|
||||
sqlite3_free (sqlcmd);
|
||||
}
|
||||
|
||||
#define _APPEND_TO_SQL_ERRORMSG(custom_errmsg) \
|
||||
do { \
|
||||
if (sql_errmsg) \
|
||||
{ \
|
||||
g_string_append_printf (errmsg_str, "%s : %s\n", custom_errmsg, sql_errmsg); \
|
||||
sqlite3_free (sql_errmsg); \
|
||||
} \
|
||||
else \
|
||||
g_string_append (errmsg_str, custom_errmsg); \
|
||||
} while (0)
|
||||
|
||||
gboolean
|
||||
midori_bookmarks_import_from_old_db (sqlite3* db,
|
||||
const gchar* oldfile,
|
||||
gchar** errmsg)
|
||||
{
|
||||
gint sql_errcode;
|
||||
gboolean failure = FALSE;
|
||||
gchar* sql_errmsg = NULL;
|
||||
GString* errmsg_str = g_string_new (NULL);
|
||||
gchar* attach_stmt = sqlite3_mprintf ("ATTACH DATABASE %Q AS old_db;", oldfile);
|
||||
const gchar* convert_stmts =
|
||||
"BEGIN TRANSACTION;"
|
||||
"INSERT INTO main.bookmarks (parentid, title, uri, desc, app, toolbar) "
|
||||
"SELECT NULL AS parentid, title, uri, desc, app, toolbar "
|
||||
"FROM old_db.bookmarks;"
|
||||
"UPDATE main.bookmarks SET parentid = ("
|
||||
"SELECT id FROM main.bookmarks AS b1 WHERE b1.title = ("
|
||||
"SELECT folder FROM old_db.bookmarks WHERE title = main.bookmarks.title));"
|
||||
"COMMIT;";
|
||||
const gchar* detach_stmt = "DETACH DATABASE old_db;";
|
||||
|
||||
*errmsg = NULL;
|
||||
sql_errcode = sqlite3_exec (db, attach_stmt, NULL, NULL, &sql_errmsg);
|
||||
sqlite3_free (attach_stmt);
|
||||
|
||||
if (sql_errcode != SQLITE_OK)
|
||||
{
|
||||
_APPEND_TO_SQL_ERRORMSG (_("failed to ATTACH old db"));
|
||||
goto convert_failed;
|
||||
}
|
||||
|
||||
if (sqlite3_exec (db, convert_stmts, NULL, NULL, &sql_errmsg) != SQLITE_OK)
|
||||
{
|
||||
failure = TRUE;
|
||||
_APPEND_TO_SQL_ERRORMSG (_("failed to import from old db"));
|
||||
|
||||
/* try to get back to previous state */
|
||||
if (sqlite3_exec (db, "ROLLBACK TRANSACTION;", NULL, NULL, &sql_errmsg) != SQLITE_OK)
|
||||
_APPEND_TO_SQL_ERRORMSG (_("failed to rollback the transaction"));
|
||||
}
|
||||
|
||||
if (sqlite3_exec (db, detach_stmt, NULL, NULL, &sql_errmsg) != SQLITE_OK)
|
||||
_APPEND_TO_SQL_ERRORMSG (_("failed to DETACH "));
|
||||
|
||||
if (failure)
|
||||
{
|
||||
convert_failed:
|
||||
*errmsg = g_string_free (errmsg_str, FALSE);
|
||||
g_print ("ERRORR: %s\n", errmsg_str->str);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
#undef _APPEND_TO_SQL_ERRORMSG
|
||||
|
||||
KatzeArray*
|
||||
midori_bookmarks_new (char** errmsg)
|
||||
{
|
||||
sqlite3* db;
|
||||
gchar* oldfile;
|
||||
gchar* newfile;
|
||||
gboolean newfile_did_exist, oldfile_exists;
|
||||
const gchar* create_stmt;
|
||||
gchar* sql_errmsg = NULL;
|
||||
gchar* import_errmsg = NULL;
|
||||
KatzeArray* array;
|
||||
|
||||
g_return_val_if_fail (errmsg != NULL, NULL);
|
||||
|
||||
oldfile = midori_paths_get_config_filename_for_writing ("bookmarks.db");
|
||||
oldfile_exists = g_access (oldfile, F_OK) == 0;
|
||||
newfile = midori_paths_get_config_filename_for_writing ("bookmarks_v2.db");
|
||||
newfile_did_exist = g_access (newfile, F_OK) == 0;
|
||||
|
||||
/* sqlite3_open will create the file if it did not exists already */
|
||||
if (sqlite3_open (newfile, &db) != SQLITE_OK)
|
||||
{
|
||||
*errmsg = g_strdup_printf (_("Failed to open database: %s\n"),
|
||||
db ? sqlite3_errmsg (db) : "(db = NULL)");
|
||||
goto init_failed;
|
||||
}
|
||||
|
||||
if (midori_debug ("bookmarks"))
|
||||
sqlite3_trace (db, midori_bookmarks_dbtracer, NULL);
|
||||
|
||||
create_stmt = /* Table structure */
|
||||
"CREATE TABLE IF NOT EXISTS bookmarks "
|
||||
"(id INTEGER PRIMARY KEY AUTOINCREMENT, "
|
||||
"parentid INTEGER DEFAULT NULL, "
|
||||
"title TEXT, uri TEXT, desc TEXT, app INTEGER, toolbar INTEGER, "
|
||||
"pos_panel INTEGER, pos_bar INTEGER, "
|
||||
"created DATE DEFAULT CURRENT_TIMESTAMP, "
|
||||
"last_visit DATE, visit_count INTEGER DEFAULT 0, "
|
||||
"nick TEXT, "
|
||||
"FOREIGN KEY(parentid) REFERENCES bookmarks(id) "
|
||||
"ON DELETE CASCADE); PRAGMA foreign_keys = ON;"
|
||||
|
||||
/* trigger: insert panel position */
|
||||
"CREATE TRIGGER IF NOT EXISTS bookmarkInsertPosPanel "
|
||||
"AFTER INSERT ON bookmarks FOR EACH ROW "
|
||||
"BEGIN UPDATE bookmarks SET pos_panel = ("
|
||||
"SELECT ifnull(MAX(pos_panel),0)+1 FROM bookmarks WHERE "
|
||||
"(NEW.parentid IS NOT NULL AND parentid = NEW.parentid) "
|
||||
"OR (NEW.parentid IS NULL AND parentid IS NULL)) "
|
||||
"WHERE id = NEW.id; END;"
|
||||
|
||||
/* trigger: insert Bookmarkbar position */
|
||||
"CREATE TRIGGER IF NOT EXISTS bookmarkInsertPosBar "
|
||||
"AFTER INSERT ON bookmarks FOR EACH ROW WHEN NEW.toolbar=1 "
|
||||
"BEGIN UPDATE bookmarks SET pos_bar = ("
|
||||
"SELECT ifnull(MAX(pos_bar),0)+1 FROM bookmarks WHERE "
|
||||
"((NEW.parentid IS NOT NULL AND parentid = NEW.parentid) "
|
||||
"OR (NEW.parentid IS NULL AND parentid IS NULL)) AND toolbar=1) "
|
||||
"WHERE id = NEW.id; END;"
|
||||
|
||||
/* trigger: update panel position */
|
||||
"CREATE TRIGGER IF NOT EXISTS bookmarkUpdatePosPanel "
|
||||
"BEFORE UPDATE OF parentid ON bookmarks FOR EACH ROW "
|
||||
"WHEN ((NEW.parentid IS NULL OR OLD.parentid IS NULL) "
|
||||
"AND NEW.parentid IS NOT OLD.parentid) OR "
|
||||
"((NEW.parentid IS NOT NULL AND OLD.parentid IS NOT NULL) "
|
||||
"AND NEW.parentid!=OLD.parentid) "
|
||||
"BEGIN UPDATE bookmarks SET pos_panel = pos_panel-1 "
|
||||
"WHERE ((OLD.parentid IS NOT NULL AND parentid = OLD.parentid) "
|
||||
"OR (OLD.parentid IS NULL AND parentid IS NULL)) AND pos_panel > OLD.pos_panel; "
|
||||
"UPDATE bookmarks SET pos_panel = ("
|
||||
"SELECT ifnull(MAX(pos_panel),0)+1 FROM bookmarks "
|
||||
"WHERE (NEW.parentid IS NOT NULL AND parentid = NEW.parentid) "
|
||||
"OR (NEW.parentid IS NULL AND parentid IS NULL)) "
|
||||
"WHERE id = OLD.id; END;"
|
||||
|
||||
/* trigger: update Bookmarkbar position */
|
||||
"CREATE TRIGGER IF NOT EXISTS bookmarkUpdatePosBar0 "
|
||||
"AFTER UPDATE OF parentid, toolbar ON bookmarks FOR EACH ROW "
|
||||
"WHEN ((NEW.parentid IS NULL OR OLD.parentid IS NULL) "
|
||||
"AND NEW.parentid IS NOT OLD.parentid) "
|
||||
"OR ((NEW.parentid IS NOT NULL AND OLD.parentid IS NOT NULL) "
|
||||
"AND NEW.parentid!=OLD.parentid) OR (OLD.toolbar=1 AND NEW.toolbar=0) "
|
||||
"BEGIN UPDATE bookmarks SET pos_bar = NULL WHERE id = NEW.id; "
|
||||
"UPDATE bookmarks SET pos_bar = pos_bar-1 "
|
||||
"WHERE ((OLD.parentid IS NOT NULL AND parentid = OLD.parentid) "
|
||||
"OR (OLD.parentid IS NULL AND parentid IS NULL)) AND pos_bar > OLD.pos_bar; END;"
|
||||
|
||||
/* trigger: update Bookmarkbar position */
|
||||
"CREATE TRIGGER IF NOT EXISTS bookmarkUpdatePosBar1 "
|
||||
"BEFORE UPDATE OF parentid, toolbar ON bookmarks FOR EACH ROW "
|
||||
"WHEN ((NEW.parentid IS NULL OR OLD.parentid IS NULL) "
|
||||
"AND NEW.parentid IS NOT OLD.parentid) OR "
|
||||
"((NEW.parentid IS NOT NULL AND OLD.parentid IS NOT NULL) "
|
||||
"AND NEW.parentid!=OLD.parentid) OR (OLD.toolbar=0 AND NEW.toolbar=1) "
|
||||
"BEGIN UPDATE bookmarks SET pos_bar = ("
|
||||
"SELECT ifnull(MAX(pos_bar),0)+1 FROM bookmarks WHERE "
|
||||
"(NEW.parentid IS NOT NULL AND parentid = NEW.parentid) "
|
||||
"OR (NEW.parentid IS NULL AND parentid IS NULL)) "
|
||||
"WHERE id = OLD.id; END;"
|
||||
|
||||
/* trigger: delete panel position */
|
||||
"CREATE TRIGGER IF NOT EXISTS bookmarkDeletePosPanel "
|
||||
"AFTER DELETE ON bookmarks FOR EACH ROW "
|
||||
"BEGIN UPDATE bookmarks SET pos_panel = pos_panel-1 "
|
||||
"WHERE ((OLD.parentid IS NOT NULL AND parentid = OLD.parentid) "
|
||||
"OR (OLD.parentid IS NULL AND parentid IS NULL)) AND pos_panel > OLD.pos_panel; END;"
|
||||
|
||||
/* trigger: delete Bookmarkbar position */
|
||||
"CREATE TRIGGER IF NOT EXISTS bookmarkDeletePosBar "
|
||||
"AFTER DELETE ON bookmarks FOR EACH ROW WHEN OLD.toolbar=1 "
|
||||
"BEGIN UPDATE bookmarks SET pos_bar = pos_bar-1 "
|
||||
"WHERE ((OLD.parentid IS NOT NULL AND parentid = OLD.parentid) "
|
||||
"OR (OLD.parentid IS NULL AND parentid IS NULL)) AND pos_bar > OLD.pos_bar; END;";
|
||||
|
||||
|
||||
if (newfile_did_exist)
|
||||
{
|
||||
/* we are done */
|
||||
goto init_success;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* initial creation */
|
||||
if (sqlite3_exec (db, create_stmt, NULL, NULL, &sql_errmsg) != SQLITE_OK)
|
||||
{
|
||||
*errmsg = g_strdup_printf (_("Couldn't create bookmarks table: %s\n"),
|
||||
sql_errmsg ? sql_errmsg : "(err = NULL)");
|
||||
sqlite3_free (sql_errmsg);
|
||||
|
||||
/* we can as well remove the new file */
|
||||
g_unlink (newfile);
|
||||
goto init_failed;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (oldfile_exists)
|
||||
/* import from old db */
|
||||
if (!midori_bookmarks_import_from_old_db (db, oldfile, &import_errmsg))
|
||||
{
|
||||
*errmsg = g_strdup_printf (_("Couldn't import from old database: %s\n"),
|
||||
import_errmsg ? import_errmsg : "(err = NULL)");
|
||||
g_free (import_errmsg);
|
||||
}
|
||||
|
||||
init_success:
|
||||
g_free (newfile);
|
||||
g_free (oldfile);
|
||||
array = katze_array_new (KATZE_TYPE_ARRAY);
|
||||
g_signal_connect (array, "add-item",
|
||||
G_CALLBACK (midori_bookmarks_add_item_cb), db);
|
||||
g_signal_connect (array, "remove-item",
|
||||
G_CALLBACK (midori_bookmarks_remove_item_cb), db);
|
||||
g_object_set_data (G_OBJECT (array), "db", db);
|
||||
return array;
|
||||
|
||||
init_failed:
|
||||
g_free (newfile);
|
||||
g_free (oldfile);
|
||||
|
||||
if (db)
|
||||
sqlite3_close (db);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
midori_bookmarks_import (const gchar* filename,
|
||||
sqlite3* db)
|
||||
{
|
||||
KatzeArray* bookmarks;
|
||||
GError* error = NULL;
|
||||
|
||||
bookmarks = katze_array_new (KATZE_TYPE_ARRAY);
|
||||
|
||||
if (!midori_array_from_file (bookmarks, filename, "xbel", &error))
|
||||
{
|
||||
g_warning (_("The bookmarks couldn't be saved. %s"), error->message);
|
||||
g_error_free (error);
|
||||
return;
|
||||
}
|
||||
midori_bookmarks_import_array_db (db, bookmarks, 0);
|
||||
}
|
||||
|
||||
void
|
||||
midori_bookmarks_on_quit (KatzeArray* array)
|
||||
{
|
||||
g_return_if_fail (KATZE_IS_ARRAY (array));
|
||||
|
||||
sqlite3* db = g_object_get_data (G_OBJECT (array), "db");
|
||||
g_return_if_fail (db != NULL);
|
||||
sqlite3_close (db);
|
||||
}
|
||||
|
40
midori/midori-bookmarks.h
Normal file
40
midori/midori-bookmarks.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
Copyright (C) 2010 Christian Dywan <christian@twotoasts.de>
|
||||
Copyright (C) 2010 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.
|
||||
*/
|
||||
|
||||
#ifndef __MIDORI_BOOKMARKS_H__
|
||||
#define __MIDORI_BOOKMARKS_H__ 1
|
||||
|
||||
#include <sqlite3.h>
|
||||
#include <katze/katze.h>
|
||||
|
||||
void
|
||||
midori_bookmarks_add_item_cb (KatzeArray* array,
|
||||
KatzeItem* item,
|
||||
sqlite3* db);
|
||||
|
||||
void
|
||||
midori_bookmarks_remove_item_cb (KatzeArray* array,
|
||||
KatzeItem* item,
|
||||
sqlite3* db);
|
||||
|
||||
KatzeArray*
|
||||
midori_bookmarks_new (char** errmsg);
|
||||
|
||||
void
|
||||
midori_bookmarks_on_quit (KatzeArray* array);
|
||||
|
||||
void
|
||||
midori_bookmarks_import (const gchar* filename,
|
||||
sqlite3* db);
|
||||
|
||||
#endif /* !__MIDORI_BOOKMARKS_H__ */
|
||||
|
File diff suppressed because it is too large
Load diff
|
@ -12,11 +12,6 @@
|
|||
#ifndef __MIDORI_BROWSER_H__
|
||||
#define __MIDORI_BROWSER_H__
|
||||
|
||||
#include <webkit/webkit.h>
|
||||
#if defined(HAVE_HILDON) && HAVE_HILDON
|
||||
#include <hildon/hildon.h>
|
||||
#endif
|
||||
|
||||
#include <katze/katze.h>
|
||||
#include "midori-view.h"
|
||||
|
||||
|
@ -40,16 +35,16 @@ typedef struct _MidoriBrowserClass MidoriBrowserClass;
|
|||
|
||||
struct _MidoriBrowserClass
|
||||
{
|
||||
#if defined(HAVE_HILDON) && HAVE_HILDON
|
||||
HildonWindowClass parent_class;
|
||||
#else
|
||||
GtkWindowClass parent_class;
|
||||
#endif
|
||||
|
||||
/* Signals */
|
||||
void
|
||||
(*window_object_cleared) (MidoriBrowser* browser,
|
||||
#ifndef HAVE_WEBKIT2
|
||||
WebKitWebFrame* web_frame,
|
||||
#else
|
||||
void* web_frame,
|
||||
#endif
|
||||
JSContextRef* context,
|
||||
JSObjectRef* window_object);
|
||||
void
|
||||
|
@ -81,24 +76,19 @@ midori_browser_get_type (void) G_GNUC_CONST;
|
|||
MidoriBrowser*
|
||||
midori_browser_new (void);
|
||||
|
||||
gint
|
||||
void
|
||||
midori_browser_add_tab (MidoriBrowser* browser,
|
||||
GtkWidget* widget);
|
||||
|
||||
void
|
||||
midori_browser_remove_tab (MidoriBrowser* browser,
|
||||
midori_browser_close_tab (MidoriBrowser* browser,
|
||||
GtkWidget* widget);
|
||||
|
||||
void
|
||||
midori_browser_foreach (MidoriBrowser* browser,
|
||||
GtkCallback callback,
|
||||
gpointer callback_data);
|
||||
|
||||
gint
|
||||
GtkWidget*
|
||||
midori_browser_add_item (MidoriBrowser* browser,
|
||||
KatzeItem* item);
|
||||
|
||||
gint
|
||||
GtkWidget*
|
||||
midori_browser_add_uri (MidoriBrowser* browser,
|
||||
const gchar* uri);
|
||||
|
||||
|
@ -106,6 +96,10 @@ void
|
|||
midori_browser_activate_action (MidoriBrowser* browser,
|
||||
const gchar* name);
|
||||
|
||||
void
|
||||
midori_browser_assert_action (MidoriBrowser* browser,
|
||||
const gchar* name);
|
||||
|
||||
void
|
||||
midori_browser_block_action (MidoriBrowser* browser,
|
||||
GtkAction* action);
|
||||
|
@ -132,6 +126,11 @@ midori_browser_get_current_uri (MidoriBrowser* browser);
|
|||
void
|
||||
midori_browser_set_current_page_smartly (MidoriBrowser* browser,
|
||||
gint n);
|
||||
|
||||
void
|
||||
midori_browser_set_current_tab_smartly (MidoriBrowser* browser,
|
||||
GtkWidget* view);
|
||||
|
||||
void
|
||||
midori_browser_set_current_page (MidoriBrowser* browser,
|
||||
gint n);
|
||||
|
@ -139,6 +138,10 @@ midori_browser_set_current_page (MidoriBrowser* browser,
|
|||
gint
|
||||
midori_browser_get_current_page (MidoriBrowser* browser);
|
||||
|
||||
void
|
||||
midori_browser_set_current_item (MidoriBrowser* browser,
|
||||
KatzeItem* item);
|
||||
|
||||
GtkWidget*
|
||||
midori_browser_get_nth_tab (MidoriBrowser* browser,
|
||||
gint n);
|
||||
|
@ -152,11 +155,15 @@ GtkWidget*
|
|||
midori_browser_get_current_tab (MidoriBrowser* browser);
|
||||
#define midori_browser_get_tab midori_browser_get_current_tab
|
||||
|
||||
gint
|
||||
midori_browser_page_num (MidoriBrowser* browser,
|
||||
GtkWidget* view);
|
||||
|
||||
GList*
|
||||
midori_browser_get_tabs (MidoriBrowser* browser);
|
||||
|
||||
KatzeArray*
|
||||
midori_browser_get_proxy_items (MidoriBrowser* browser);
|
||||
gint
|
||||
midori_browser_get_n_pages (MidoriBrowser* browser);
|
||||
|
||||
KatzeArray*
|
||||
midori_browser_get_proxy_array (MidoriBrowser* browser);
|
||||
|
@ -173,6 +180,20 @@ midori_browser_get_toolbar_actions (MidoriBrowser* browser);
|
|||
MidoriWebSettings*
|
||||
midori_browser_get_settings (MidoriBrowser* browser);
|
||||
|
||||
void
|
||||
midori_browser_update_history (KatzeItem* item,
|
||||
const gchar* type,
|
||||
const gchar* event);
|
||||
|
||||
void
|
||||
midori_browser_save_uri (MidoriBrowser* browser,
|
||||
MidoriView* view,
|
||||
const gchar* uri);
|
||||
|
||||
void
|
||||
midori_browser_set_inactivity_reset (MidoriBrowser* browser,
|
||||
gint inactivity_reset);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __MIDORI_BROWSER_H__ */
|
||||
|
|
170
midori/midori-completion.vala
Normal file
170
midori/midori-completion.vala
Normal file
|
@ -0,0 +1,170 @@
|
|||
/*
|
||||
Copyright (C) 2012 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.
|
||||
*/
|
||||
|
||||
namespace Midori {
|
||||
public class Suggestion : GLib.Object {
|
||||
public string? uri { get; set; }
|
||||
public string? markup { get; set; }
|
||||
public bool use_markup { get; set; }
|
||||
public string? background { get; set; }
|
||||
public GLib.Icon? icon { get; set; }
|
||||
public bool action { get; set; default = false; }
|
||||
|
||||
public Suggestion (string? uri, string? markup, bool use_markup=false,
|
||||
string? background=null, GLib.Icon? icon=null) {
|
||||
|
||||
GLib.Object (uri: uri, markup: markup, use_markup: use_markup,
|
||||
background: background, icon: icon);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class Completion : GLib.Object {
|
||||
public string? description { get; set; }
|
||||
public int max_items { get; internal set; default = 25; }
|
||||
internal int position { get; set; }
|
||||
|
||||
public abstract void prepare (GLib.Object app);
|
||||
public abstract bool can_complete (string prefix);
|
||||
public abstract bool can_action (string action);
|
||||
public abstract async List<Suggestion>? complete (string text, string? action, Cancellable cancellable);
|
||||
}
|
||||
|
||||
public class Autocompleter : GLib.Object {
|
||||
private GLib.Object app;
|
||||
private List<Completion> completions;
|
||||
private int next_position;
|
||||
public Gtk.ListStore model { get; private set; }
|
||||
private bool need_to_clear = false;
|
||||
private uint current_count = 0;
|
||||
private Cancellable? cancellable = null;
|
||||
|
||||
public enum Columns {
|
||||
ICON,
|
||||
URI,
|
||||
MARKUP,
|
||||
BACKGROUND,
|
||||
YALIGN,
|
||||
N
|
||||
}
|
||||
|
||||
public Autocompleter (GLib.Object app) {
|
||||
this.app = app;
|
||||
completions = new List<Completion> ();
|
||||
next_position = 0;
|
||||
model = new Gtk.ListStore (Columns.N,
|
||||
typeof (Gdk.Pixbuf), typeof (string), typeof (string),
|
||||
typeof (string), typeof (float));
|
||||
}
|
||||
|
||||
public void add (Completion completion) {
|
||||
completion.prepare (app);
|
||||
completion.position = next_position;
|
||||
next_position += completion.max_items;
|
||||
completions.append (completion);
|
||||
}
|
||||
|
||||
public bool can_complete (string text) {
|
||||
foreach (var completion in completions)
|
||||
if (completion.can_complete (text))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private void fill_model (Midori.Completion completion, List<Midori.Suggestion>? suggestions) {
|
||||
if (need_to_clear) {
|
||||
model.clear ();
|
||||
need_to_clear = false;
|
||||
current_count = 0;
|
||||
}
|
||||
|
||||
#if HAVE_GRANITE
|
||||
if (completion.description != null) {
|
||||
model.insert_with_values (null, completion.position,
|
||||
Columns.URI, "about:completion-description",
|
||||
Columns.MARKUP, "<b>%s</b>\n".printf (Markup.escape_text (completion.description)),
|
||||
Columns.ICON, null,
|
||||
Columns.BACKGROUND, null,
|
||||
Columns.YALIGN, 0.25);
|
||||
}
|
||||
#endif
|
||||
|
||||
int count = 1;
|
||||
foreach (var suggestion in suggestions) {
|
||||
if (suggestion.uri == null) {
|
||||
warning ("suggestion.uri != null");
|
||||
continue;
|
||||
}
|
||||
if (suggestion.markup == null) {
|
||||
warning ("suggestion.markup != null");
|
||||
continue;
|
||||
}
|
||||
model.insert_with_values (null, completion.position + count,
|
||||
Columns.URI, suggestion.uri,
|
||||
Columns.MARKUP, suggestion.use_markup
|
||||
? suggestion.markup : Markup.escape_text (suggestion.markup),
|
||||
Columns.ICON, suggestion.icon,
|
||||
Columns.BACKGROUND, suggestion.background,
|
||||
Columns.YALIGN, 0.25);
|
||||
|
||||
count++;
|
||||
if (count > completion.max_items)
|
||||
break;
|
||||
}
|
||||
|
||||
current_count += count;
|
||||
populated (current_count);
|
||||
}
|
||||
|
||||
public signal void populated (uint count);
|
||||
|
||||
private async void complete_wrapped (Completion completion, string text, string? action, Cancellable cancellable) {
|
||||
List<Midori.Suggestion>? suggestions = yield completion.complete (text, action, cancellable);
|
||||
if (!cancellable.is_cancelled () && suggestions != null)
|
||||
fill_model (completion, suggestions);
|
||||
}
|
||||
|
||||
public async void complete (string text) {
|
||||
if (cancellable != null)
|
||||
cancellable.cancel ();
|
||||
cancellable = new Cancellable ();
|
||||
need_to_clear = true;
|
||||
|
||||
foreach (var completion in completions) {
|
||||
if (completion.can_complete (text))
|
||||
complete_wrapped.begin (completion, text, null, cancellable);
|
||||
}
|
||||
}
|
||||
|
||||
public bool can_action (string action) {
|
||||
if (action == "about:completion-description")
|
||||
return true;
|
||||
foreach (var completion in completions)
|
||||
if (completion.can_action (action))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public async void action (string action, string text) {
|
||||
if (action == "about:completion-description")
|
||||
return;
|
||||
|
||||
if (cancellable != null)
|
||||
cancellable.cancel ();
|
||||
cancellable = new Cancellable ();
|
||||
need_to_clear = true;
|
||||
|
||||
foreach (var completion in completions) {
|
||||
if (completion.can_action (action))
|
||||
complete_wrapped.begin (completion, text, action, cancellable);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
102
midori/midori-dialog.vala
Normal file
102
midori/midori-dialog.vala
Normal file
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
Copyright (C) 2011-2012 Christian Dywan <christian@twotoats.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.
|
||||
*/
|
||||
|
||||
namespace Midori {
|
||||
namespace Timeout {
|
||||
public uint add_seconds (uint interval, owned SourceFunc function) {
|
||||
if (Test.test_idle_timeouts)
|
||||
return GLib.Idle.add (function);
|
||||
return GLib.Timeout.add_seconds (interval, function);
|
||||
}
|
||||
public uint add (uint interval, owned SourceFunc function) {
|
||||
if (Test.test_idle_timeouts)
|
||||
return GLib.Idle.add (function);
|
||||
return GLib.Timeout.add (interval, function);
|
||||
}
|
||||
}
|
||||
|
||||
namespace Test {
|
||||
internal static uint test_max_timeout = 0;
|
||||
internal static string? test_first_try = null;
|
||||
public void grab_max_timeout () {
|
||||
int seconds = (Environment.get_variable ("MIDORI_TIMEOUT") ?? "42").to_int ();
|
||||
test_first_try = "once";
|
||||
test_max_timeout = GLib.Timeout.add_seconds (seconds > 0 ? seconds / 2 : 0, ()=>{
|
||||
stdout.printf ("Timed out %s%s\n", test_first_try,
|
||||
MainContext.default ().pending () ? " (loop)" : "");
|
||||
if (test_first_try == "twice")
|
||||
Process.exit (0);
|
||||
test_first_try = "twice";
|
||||
MainContext.default ().wakeup ();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
public void release_max_timeout () {
|
||||
assert (test_max_timeout > 0);
|
||||
GLib.Source.remove (test_max_timeout);
|
||||
test_max_timeout = 0;
|
||||
}
|
||||
|
||||
internal static bool test_idle_timeouts = false;
|
||||
public void idle_timeouts () {
|
||||
test_idle_timeouts = true;
|
||||
}
|
||||
|
||||
public void log_set_fatal_handler_for_icons () {
|
||||
GLib.Test.log_set_fatal_handler ((domain, log_levels, message)=> {
|
||||
return !message.contains ("Error loading theme icon")
|
||||
&& !message.contains ("Could not find the icon")
|
||||
&& !message.contains ("Junk at end of value")
|
||||
&& !message.contains ("gtk_notebook_get_tab_label: assertion `GTK_IS_WIDGET (child)' failed")
|
||||
&& !message.contains ("get_column_number: assertion `i < gtk_tree_view_get_n_columns (treeview)' failed");
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
internal static Gtk.ResponseType test_response = Gtk.ResponseType.NONE;
|
||||
public void set_dialog_response (Gtk.ResponseType response) {
|
||||
test_response = response;
|
||||
}
|
||||
|
||||
internal static string? test_filename = null;
|
||||
public void set_file_chooser_filename (string filename) {
|
||||
test_filename = filename;
|
||||
}
|
||||
}
|
||||
|
||||
public class FileChooserDialog : Gtk.FileChooserDialog {
|
||||
public FileChooserDialog (string title, Gtk.Window window, Gtk.FileChooserAction action) {
|
||||
/* Creates a new file chooser dialog to Open or Save and Cancel.
|
||||
The positive response is %Gtk.ResponseType.OK. */
|
||||
unowned string stock_id = Gtk.Stock.OPEN;
|
||||
if (action == Gtk.FileChooserAction.SAVE)
|
||||
stock_id = Gtk.Stock.SAVE;
|
||||
this.title = title;
|
||||
transient_for = window;
|
||||
this.action = action;
|
||||
add_buttons (Gtk.Stock.CANCEL, Gtk.ResponseType.CANCEL,
|
||||
stock_id, Gtk.ResponseType.OK);
|
||||
icon_name = stock_id;
|
||||
}
|
||||
}
|
||||
|
||||
namespace Dialog {
|
||||
public static new int run (Gtk.Dialog dialog) {
|
||||
if (Test.test_response != Gtk.ResponseType.NONE) {
|
||||
if (Test.test_filename != null && dialog is Gtk.FileChooser)
|
||||
(dialog as Gtk.FileChooser).set_filename (Test.test_filename);
|
||||
return Test.test_response;
|
||||
}
|
||||
return dialog.run ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
364
midori/midori-download.vala
Normal file
364
midori/midori-download.vala
Normal file
|
@ -0,0 +1,364 @@
|
|||
/*
|
||||
Copyright (C) 2012 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.
|
||||
*/
|
||||
|
||||
namespace Sokoke {
|
||||
extern static bool show_uri (Gdk.Screen screen, string uri, uint32 timestamp) throws Error;
|
||||
extern static bool message_dialog (Gtk.MessageType type, string short, string detailed, bool modal);
|
||||
}
|
||||
|
||||
namespace Midori {
|
||||
namespace Download {
|
||||
public static bool is_finished (WebKit.Download download) {
|
||||
#if !HAVE_WEBKIT2
|
||||
switch (download.status) {
|
||||
case WebKit.DownloadStatus.FINISHED:
|
||||
case WebKit.DownloadStatus.CANCELLED:
|
||||
case WebKit.DownloadStatus.ERROR:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
public static int get_type (WebKit.Download download) {
|
||||
return download.get_data<int> ("midori-download-type");
|
||||
}
|
||||
|
||||
public static void set_type (WebKit.Download download, int type) {
|
||||
download.set_data<int> ("midori-download-type", type);
|
||||
}
|
||||
|
||||
public static double get_progress (WebKit.Download download) {
|
||||
#if !HAVE_WEBKIT2
|
||||
/* Avoid a bug in WebKit */
|
||||
if (download.status == WebKit.DownloadStatus.CREATED)
|
||||
return 0.0;
|
||||
return download.progress;
|
||||
#else
|
||||
return 0.0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !HAVE_GLIB_2_30
|
||||
private static string format_size (uint64 size) {
|
||||
return format_size_for_display ((int64)size);
|
||||
}
|
||||
#endif
|
||||
|
||||
public static string get_tooltip (WebKit.Download download) {
|
||||
#if !HAVE_WEBKIT2
|
||||
string filename = Path.get_basename (download.destination_uri);
|
||||
/* i18n: Download tooltip (size): 4KB of 43MB */
|
||||
string size = _("%s of %s").printf (
|
||||
format_size (download.current_size),
|
||||
format_size (download.total_size));
|
||||
|
||||
/* Finished, no speed or remaining time */
|
||||
if (is_finished (download) || download.status == WebKit.DownloadStatus.CREATED)
|
||||
return "%s\n%s".printf (filename, size);
|
||||
|
||||
uint64 total_size = download.total_size, current_size = download.current_size;
|
||||
double elapsed = download.get_elapsed_time (),
|
||||
diff = elapsed / current_size,
|
||||
estimated = (total_size - current_size) * diff;
|
||||
int hour = 3600, minute = 60;
|
||||
int hours = (int)(estimated / hour),
|
||||
minutes = (int)((estimated - (hours * hour)) / minute),
|
||||
seconds = (int)((estimated - (hours * hour) - (minutes * minute)));
|
||||
string hours_ = ngettext ("%d hour", "%d hours", hours).printf (hours);
|
||||
string minutes_ = ngettext ("%d minute", "%d minutes", minutes).printf (minutes);
|
||||
string seconds_ = ngettext ("%d second", "%d seconds", seconds).printf (seconds);
|
||||
double last_time = download.get_data<int> ("last-time");
|
||||
|
||||
string eta = "";
|
||||
if (estimated > 0) {
|
||||
if (hours > 0)
|
||||
eta = hours_ + ", " + minutes_;
|
||||
else if (minutes >= 10)
|
||||
eta = minutes_;
|
||||
else if (minutes < 10 && minutes > 0)
|
||||
eta = minutes_ + ", " + seconds_;
|
||||
else if (seconds > 0)
|
||||
eta = seconds_;
|
||||
if (eta != "")
|
||||
/* i18n: Download tooltip (estimated time) : - 1 hour, 5 minutes remaning */
|
||||
eta = _(" - %s remaining").printf (eta);
|
||||
}
|
||||
|
||||
string speed = "";
|
||||
uint64? last_size = download.get_data<uint64?> ("last-size");
|
||||
if (last_size != null && elapsed != last_time) {
|
||||
speed = format_size ((uint64)(
|
||||
(current_size - last_size) / (elapsed - last_time)));
|
||||
}
|
||||
else
|
||||
/* i18n: Unknown number of bytes, used for transfer rate like ?B/s */
|
||||
speed = _("?B");
|
||||
/* i18n: Download tooltip (transfer rate): (130KB/s) */
|
||||
speed = _(" (%s/s)").printf (speed);
|
||||
|
||||
if (elapsed - last_time > 0.0) {
|
||||
download.set_data<int> ("last-time", (int)elapsed);
|
||||
download.set_data<uint64?> ("last-size", current_size);
|
||||
}
|
||||
|
||||
return "%s\n%s %s%s".printf (filename, size, speed, eta);
|
||||
#else
|
||||
return "";
|
||||
#endif
|
||||
}
|
||||
|
||||
public static string get_content_type (WebKit.Download download, string? mime_type) {
|
||||
#if !HAVE_WEBKIT2
|
||||
string? content_type = ContentType.guess (download.suggested_filename, null, null);
|
||||
if (content_type == null) {
|
||||
content_type = ContentType.from_mime_type (mime_type);
|
||||
if (content_type == null)
|
||||
content_type = ContentType.from_mime_type ("application/octet-stream");
|
||||
}
|
||||
return content_type;
|
||||
#else
|
||||
return ContentType.from_mime_type ("application/octet-stream");
|
||||
#endif
|
||||
}
|
||||
|
||||
public static bool has_wrong_checksum (WebKit.Download download) {
|
||||
#if !HAVE_WEBKIT2
|
||||
int status = download.get_data<int> ("checksum-status");
|
||||
if (status == 0) {
|
||||
/* Link Fingerprint */
|
||||
string? original_uri = download.network_request.get_data<string> ("midori-original-uri");
|
||||
if (original_uri == null)
|
||||
original_uri = download.get_uri ();
|
||||
string? fingerprint;
|
||||
ChecksumType checksum_type = URI.get_fingerprint (original_uri, out fingerprint, null);
|
||||
/* By default, no wrong checksum */
|
||||
status = 2;
|
||||
if (fingerprint != null) {
|
||||
try {
|
||||
string filename = Filename.from_uri (download.destination_uri);
|
||||
string contents;
|
||||
size_t length;
|
||||
bool y = FileUtils.get_contents (filename, out contents, out length);
|
||||
string checksum = Checksum.compute_for_string (checksum_type, contents, length);
|
||||
/* Checksums are case-insensitive */
|
||||
if (!y || fingerprint.ascii_casecmp (checksum) != 0)
|
||||
status = 1; /* wrong checksum */
|
||||
}
|
||||
catch (Error error) {
|
||||
status = 1; /* wrong checksum */
|
||||
}
|
||||
}
|
||||
download.set_data<int> ("checksum-status", status);
|
||||
}
|
||||
return status == 1;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
public static bool action_clear (WebKit.Download download, Gtk.Widget widget) throws Error {
|
||||
#if !HAVE_WEBKIT2
|
||||
switch (download.status) {
|
||||
case WebKit.DownloadStatus.CREATED:
|
||||
case WebKit.DownloadStatus.STARTED:
|
||||
download.cancel ();
|
||||
break;
|
||||
case WebKit.DownloadStatus.FINISHED:
|
||||
if (open (download, widget))
|
||||
return true;
|
||||
break;
|
||||
case WebKit.DownloadStatus.CANCELLED:
|
||||
return true;
|
||||
default:
|
||||
critical ("action_clear: %d", download.status);
|
||||
warn_if_reached ();
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
public static string action_stock_id (WebKit.Download download) {
|
||||
#if !HAVE_WEBKIT2
|
||||
switch (download.status) {
|
||||
case WebKit.DownloadStatus.CREATED:
|
||||
case WebKit.DownloadStatus.STARTED:
|
||||
return Gtk.Stock.CANCEL;
|
||||
case WebKit.DownloadStatus.FINISHED:
|
||||
if (has_wrong_checksum (download))
|
||||
return Gtk.Stock.DIALOG_WARNING;
|
||||
return Gtk.Stock.OPEN;
|
||||
case WebKit.DownloadStatus.CANCELLED:
|
||||
return Gtk.Stock.CLEAR;
|
||||
case WebKit.DownloadStatus.ERROR:
|
||||
return Gtk.Stock.DIALOG_ERROR;
|
||||
default:
|
||||
critical ("action_stock_id: %d", download.status);
|
||||
warn_if_reached ();
|
||||
return Gtk.Stock.MISSING_IMAGE;
|
||||
}
|
||||
#else
|
||||
return Gtk.Stock.MISSING_IMAGE;
|
||||
#endif
|
||||
}
|
||||
|
||||
public static bool open (WebKit.Download download, Gtk.Widget widget) throws Error {
|
||||
#if !HAVE_WEBKIT2
|
||||
if (!has_wrong_checksum (download))
|
||||
return Sokoke.show_uri (widget.get_screen (),
|
||||
download.destination_uri, Gtk.get_current_event_time ());
|
||||
|
||||
Sokoke.message_dialog (Gtk.MessageType.WARNING,
|
||||
_("The downloaded file is erroneous."),
|
||||
_("The checksum provided with the link did not match. This means the file is probably incomplete or was modified afterwards."),
|
||||
true);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
public unowned string fallback_extension (string? extension, string mime_type) {
|
||||
if (extension != null && extension[0] != '\0')
|
||||
return extension;
|
||||
if ("css" in mime_type)
|
||||
return ".css";
|
||||
if ("javascript" in mime_type)
|
||||
return ".js";
|
||||
if ("html" in mime_type)
|
||||
return ".htm";
|
||||
if ("plain" in mime_type)
|
||||
return ".txt";
|
||||
return "";
|
||||
}
|
||||
|
||||
public string clean_filename (string filename) {
|
||||
#if HAVE_WIN32
|
||||
return filename.delimit ("/\\<>:\"|?*", '_');
|
||||
#else
|
||||
return filename.delimit ("/", '_');
|
||||
#endif
|
||||
}
|
||||
|
||||
public string get_suggested_filename (WebKit.Download download) {
|
||||
#if !HAVE_WEBKIT2
|
||||
/* https://bugs.webkit.org/show_bug.cgi?id=83161
|
||||
https://d19vezwu8eufl6.cloudfront.net/nlp/slides%2F03-01-FormalizingNB.pdf */
|
||||
return clean_filename (download.get_suggested_filename ());
|
||||
#else
|
||||
return "";
|
||||
#endif
|
||||
}
|
||||
|
||||
public string get_filename_suggestion_for_uri (string mime_type, string uri) {
|
||||
return_val_if_fail (Midori.URI.is_location (uri), uri);
|
||||
string filename = File.new_for_uri (uri).get_basename ();
|
||||
if (uri.index_of_char ('.') == -1)
|
||||
return Path.build_filename (filename, fallback_extension (null, mime_type));
|
||||
return filename;
|
||||
}
|
||||
|
||||
public static string? get_extension_for_uri (string uri, out string basename = null) {
|
||||
if (&basename != null)
|
||||
basename = null;
|
||||
/* Find the last slash and the last period *after* the last slash. */
|
||||
int last_slash = uri.last_index_of_char ('/');
|
||||
/* Huh, URI without slashes? */
|
||||
if (last_slash == -1)
|
||||
return null;
|
||||
int period = uri.last_index_of_char ('.', last_slash);
|
||||
if (period == -1)
|
||||
return null;
|
||||
/* Exclude the query: ?query=foobar */
|
||||
int query = uri.last_index_of_char ('?', period);
|
||||
/* The extension, or "." if it ended with a period */
|
||||
string extension = uri.substring (period, query - period);
|
||||
if (&basename != null)
|
||||
basename = uri.substring (0, period);
|
||||
return extension;
|
||||
|
||||
}
|
||||
|
||||
public string get_unique_filename (string filename) {
|
||||
if (Posix.access (filename, Posix.F_OK) == 0) {
|
||||
string basename;
|
||||
string? extension = get_extension_for_uri (filename, out basename);
|
||||
string? new_filename = null;
|
||||
int i = 0;
|
||||
do {
|
||||
new_filename = "%s-%d%s".printf (basename, i++, extension ?? "");
|
||||
} while (Posix.access (new_filename, Posix.F_OK) == 0);
|
||||
return new_filename;
|
||||
}
|
||||
return filename;
|
||||
}
|
||||
|
||||
public string prepare_destination_uri (WebKit.Download download, string? folder) {
|
||||
string suggested_filename = get_suggested_filename (download);
|
||||
string basename = File.new_for_uri (suggested_filename).get_basename ();
|
||||
string download_dir;
|
||||
if (folder == null) {
|
||||
download_dir = Paths.get_tmp_dir ();
|
||||
Katze.mkdir_with_parents (download_dir, 0700);
|
||||
}
|
||||
else
|
||||
download_dir = folder;
|
||||
string destination_filename = Path.build_filename (download_dir, basename);
|
||||
try {
|
||||
return Filename.to_uri (get_unique_filename (destination_filename));
|
||||
}
|
||||
catch (Error error) {
|
||||
return "file://" + destination_filename;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool has_enough_space (WebKit.Download download, string uri) {
|
||||
#if !HAVE_WEBKIT2
|
||||
var folder = File.new_for_uri (uri).get_parent ();
|
||||
bool can_write;
|
||||
uint64 free_space;
|
||||
try {
|
||||
var info = folder.query_filesystem_info ("filesystem::free");
|
||||
free_space = info.get_attribute_uint64 ("filesystem::free");
|
||||
info = folder.query_info ("access::can-write", 0);
|
||||
can_write = info.get_attribute_boolean ("access::can-write");
|
||||
}
|
||||
catch (Error error) {
|
||||
can_write = false;
|
||||
free_space = 0;
|
||||
}
|
||||
|
||||
if (free_space < download.total_size || !can_write) {
|
||||
string message;
|
||||
string detailed_message;
|
||||
if (!can_write) {
|
||||
message = _("The file \"%s\" can't be saved in this folder.").printf (
|
||||
Path.get_basename (uri));
|
||||
detailed_message = _("You don't have permission to write in this location.");
|
||||
}
|
||||
else if (free_space < download.total_size) {
|
||||
message = _("There is not enough free space to download \"%s\".").printf (
|
||||
Path.get_basename (uri));
|
||||
detailed_message = _("The file needs %s but only %s are left.").printf (
|
||||
format_size (download.total_size), format_size (free_space));
|
||||
}
|
||||
else
|
||||
assert_not_reached ();
|
||||
Sokoke.message_dialog (Gtk.MessageType.ERROR, message, detailed_message, false);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright (C) 2008-2009 Christian Dywan <christian@twotoasts.de>
|
||||
Copyright (C) 2008-2012 Christian Dywan <christian@twotoasts.de>
|
||||
Copyright (C) 2009 Dale Whittaker <dayul@users.sf.net>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
|
@ -14,17 +14,21 @@
|
|||
|
||||
#include <katze/katze.h>
|
||||
#include "midori-platform.h"
|
||||
#include "midori-core.h"
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
G_DEFINE_TYPE (MidoriExtension, midori_extension, G_TYPE_OBJECT);
|
||||
|
||||
struct _MidoriExtensionPrivate
|
||||
{
|
||||
gchar* stock_id;
|
||||
gchar* name;
|
||||
gchar* description;
|
||||
gboolean use_markup;
|
||||
gchar* version;
|
||||
gchar* authors;
|
||||
gchar* website;
|
||||
gchar* key;
|
||||
|
||||
MidoriApp* app;
|
||||
gint active;
|
||||
|
@ -123,11 +127,14 @@ enum
|
|||
{
|
||||
PROP_0,
|
||||
|
||||
PROP_STOCK_ID,
|
||||
PROP_NAME,
|
||||
PROP_DESCRIPTION,
|
||||
PROP_USE_MARKUP,
|
||||
PROP_VERSION,
|
||||
PROP_AUTHORS,
|
||||
PROP_WEBSITE
|
||||
PROP_WEBSITE,
|
||||
PROP_KEY
|
||||
};
|
||||
|
||||
enum {
|
||||
|
@ -208,6 +215,15 @@ midori_extension_class_init (MidoriExtensionClass* class)
|
|||
|
||||
flags = G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS;
|
||||
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_STOCK_ID,
|
||||
g_param_spec_string (
|
||||
"stock-id",
|
||||
"Stock ID",
|
||||
"An optional icon stock ID",
|
||||
NULL,
|
||||
flags));
|
||||
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_NAME,
|
||||
g_param_spec_string (
|
||||
|
@ -226,6 +242,15 @@ midori_extension_class_init (MidoriExtensionClass* class)
|
|||
NULL,
|
||||
flags));
|
||||
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_USE_MARKUP,
|
||||
g_param_spec_boolean (
|
||||
"use-markup",
|
||||
"Use Markup",
|
||||
"Whether to use Pango markup",
|
||||
FALSE,
|
||||
flags));
|
||||
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_VERSION,
|
||||
g_param_spec_string (
|
||||
|
@ -260,6 +285,23 @@ midori_extension_class_init (MidoriExtensionClass* class)
|
|||
NULL,
|
||||
flags));
|
||||
|
||||
/**
|
||||
* MidoriExtension:key:
|
||||
*
|
||||
* The extension key.
|
||||
* Needed if there is more than one extension object in a single module.
|
||||
*
|
||||
* Since: 0.4.5
|
||||
*/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_KEY,
|
||||
g_param_spec_string (
|
||||
"key",
|
||||
"Key",
|
||||
"The extension key",
|
||||
NULL,
|
||||
flags));
|
||||
|
||||
g_type_class_add_private (class, sizeof (MidoriExtensionPrivate));
|
||||
}
|
||||
|
||||
|
@ -290,19 +332,8 @@ midori_extension_activate_cb (MidoriExtension* extension,
|
|||
if (error->code == G_FILE_ERROR_NOENT)
|
||||
{
|
||||
gchar* filename = g_object_get_data (G_OBJECT (extension), "filename");
|
||||
gchar* folder;
|
||||
if (g_str_has_prefix (filename, MIDORI_MODULE_PREFIX))
|
||||
filename = &filename[strlen (MIDORI_MODULE_PREFIX)];
|
||||
if (g_str_has_suffix (filename, G_MODULE_SUFFIX))
|
||||
filename = g_strndup (filename,
|
||||
strlen (filename) - strlen ("." G_MODULE_SUFFIX));
|
||||
else
|
||||
filename = g_strdup (filename);
|
||||
folder = g_strconcat ("extensions/", filename, NULL);
|
||||
g_free (filename);
|
||||
katze_assign (config_file,
|
||||
sokoke_find_config_filename (folder, "config"));
|
||||
g_free (folder);
|
||||
midori_paths_get_extension_preset_filename (filename, "config"));
|
||||
g_key_file_load_from_file (extension->priv->key_file, config_file,
|
||||
G_KEY_FILE_KEEP_COMMENTS, NULL);
|
||||
}
|
||||
|
@ -321,29 +352,32 @@ midori_extension_activate_cb (MidoriExtension* extension,
|
|||
if (setting->type == G_TYPE_BOOLEAN)
|
||||
{
|
||||
MESettingBoolean* setting_ = (MESettingBoolean*)setting;
|
||||
if (extension->priv->key_file)
|
||||
setting_->value = sokoke_key_file_get_boolean_default (
|
||||
extension->priv->key_file,
|
||||
"settings", setting->name, setting_->default_value, NULL);
|
||||
if (extension->priv->key_file
|
||||
&& g_key_file_has_key (extension->priv->key_file, "settings", setting_->name, NULL))
|
||||
setting_->value = g_key_file_get_boolean (extension->priv->key_file,
|
||||
"settings", setting->name, NULL);
|
||||
else
|
||||
setting_->value = setting_->default_value;
|
||||
}
|
||||
else if (setting->type == G_TYPE_INT)
|
||||
{
|
||||
MESettingInteger* setting_ = (MESettingInteger*)setting;
|
||||
if (extension->priv->key_file)
|
||||
setting_->value = sokoke_key_file_get_integer_default (
|
||||
extension->priv->key_file,
|
||||
"settings", setting->name, setting_->default_value, NULL);
|
||||
if (extension->priv->key_file
|
||||
&& g_key_file_has_key (extension->priv->key_file, "settings", setting_->name, NULL))
|
||||
setting_->value = g_key_file_get_integer (extension->priv->key_file,
|
||||
"settings", setting_->name, NULL);
|
||||
else
|
||||
setting_->value = setting_->default_value;
|
||||
}
|
||||
else if (setting->type == G_TYPE_STRING)
|
||||
{
|
||||
if (extension->priv->key_file)
|
||||
setting->value = sokoke_key_file_get_string_default (
|
||||
extension->priv->key_file,
|
||||
"settings", setting->name, setting->default_value, NULL);
|
||||
{
|
||||
setting->value = g_key_file_get_string (
|
||||
extension->priv->key_file, "settings", setting->name, NULL);
|
||||
if (setting->value == NULL)
|
||||
setting->value = setting->default_value;
|
||||
}
|
||||
else
|
||||
setting->value = g_strdup (setting->default_value);
|
||||
}
|
||||
|
@ -352,10 +386,13 @@ midori_extension_activate_cb (MidoriExtension* extension,
|
|||
MESettingStringList* setting_ = (MESettingStringList*)setting;
|
||||
if (extension->priv->key_file)
|
||||
{
|
||||
setting_->value = sokoke_key_file_get_string_list_default (
|
||||
extension->priv->key_file,
|
||||
"settings", setting->name, &setting_->length,
|
||||
setting_->default_value, &setting_->default_length, NULL);
|
||||
setting_->value = g_key_file_get_string_list (extension->priv->key_file,
|
||||
"settings", setting->name, &setting_->length, NULL);
|
||||
if (setting_->value == NULL)
|
||||
{
|
||||
setting_->value = g_strdupv (setting_->default_value);
|
||||
setting_->length = setting_->default_length;
|
||||
}
|
||||
}
|
||||
else
|
||||
setting_->value = g_strdupv (setting_->default_value);
|
||||
|
@ -395,11 +432,13 @@ midori_extension_finalize (GObject* object)
|
|||
MidoriExtension* extension = MIDORI_EXTENSION (object);
|
||||
|
||||
katze_object_assign (extension->priv->app, NULL);
|
||||
katze_assign (extension->priv->stock_id, NULL);
|
||||
katze_assign (extension->priv->name, NULL);
|
||||
katze_assign (extension->priv->description, NULL);
|
||||
katze_assign (extension->priv->version, NULL);
|
||||
katze_assign (extension->priv->authors, NULL);
|
||||
katze_assign (extension->priv->website, NULL);
|
||||
katze_assign (extension->priv->key, NULL);
|
||||
|
||||
katze_assign (extension->priv->config_dir, NULL);
|
||||
g_list_free (extension->priv->lsettings);
|
||||
|
@ -418,12 +457,18 @@ midori_extension_set_property (GObject* object,
|
|||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_STOCK_ID:
|
||||
katze_assign (extension->priv->stock_id, g_value_dup_string (value));
|
||||
break;
|
||||
case PROP_NAME:
|
||||
katze_assign (extension->priv->name, g_value_dup_string (value));
|
||||
break;
|
||||
case PROP_DESCRIPTION:
|
||||
katze_assign (extension->priv->description, g_value_dup_string (value));
|
||||
break;
|
||||
case PROP_USE_MARKUP:
|
||||
extension->priv->use_markup = g_value_get_boolean (value);
|
||||
break;
|
||||
case PROP_VERSION:
|
||||
{
|
||||
/* Don't show version suffix if it matches the running Midori */
|
||||
|
@ -446,6 +491,9 @@ midori_extension_set_property (GObject* object,
|
|||
case PROP_WEBSITE:
|
||||
katze_assign (extension->priv->website, g_value_dup_string (value));
|
||||
break;
|
||||
case PROP_KEY:
|
||||
katze_assign (extension->priv->key, g_value_dup_string (value));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
|
@ -462,12 +510,18 @@ midori_extension_get_property (GObject* object,
|
|||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_STOCK_ID:
|
||||
g_value_set_string (value, extension->priv->stock_id);
|
||||
break;
|
||||
case PROP_NAME:
|
||||
g_value_set_string (value, extension->priv->name);
|
||||
break;
|
||||
case PROP_DESCRIPTION:
|
||||
g_value_set_string (value, extension->priv->description);
|
||||
break;
|
||||
case PROP_USE_MARKUP:
|
||||
g_value_set_boolean (value, extension->priv->use_markup);
|
||||
break;
|
||||
case PROP_VERSION:
|
||||
g_value_set_string (value, extension->priv->version);
|
||||
break;
|
||||
|
@ -477,12 +531,209 @@ midori_extension_get_property (GObject* object,
|
|||
case PROP_WEBSITE:
|
||||
g_value_set_string (value, extension->priv->website);
|
||||
break;
|
||||
case PROP_KEY:
|
||||
g_value_set_string (value, extension->priv->key);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
midori_extension_load_from_folder (MidoriApp* app,
|
||||
gchar** keys,
|
||||
gboolean activate)
|
||||
{
|
||||
if (!g_module_supported ())
|
||||
return;
|
||||
|
||||
gchar* extension_path = midori_paths_get_lib_path (PACKAGE_NAME);
|
||||
if (!extension_path)
|
||||
return;
|
||||
|
||||
if (activate)
|
||||
{
|
||||
gint i = 0;
|
||||
const gchar* filename;
|
||||
while (keys && (filename = keys[i++]))
|
||||
midori_extension_activate_gracefully (app, extension_path, filename, activate);
|
||||
/* FIXME need proper stock extension mechanism */
|
||||
GObject* extension = midori_extension_activate_gracefully (app, extension_path, "libtransfers." G_MODULE_SUFFIX, activate);
|
||||
g_assert (extension != NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
GDir* extension_dir = g_dir_open (extension_path, 0, NULL);
|
||||
g_return_if_fail (extension_dir != NULL);
|
||||
const gchar* filename;
|
||||
while ((filename = g_dir_read_name (extension_dir)))
|
||||
midori_extension_activate_gracefully (app, extension_path, filename, activate);
|
||||
g_dir_close (extension_dir);
|
||||
}
|
||||
|
||||
g_free (extension_path);
|
||||
}
|
||||
|
||||
GObject*
|
||||
midori_extension_load_from_file (const gchar* extension_path,
|
||||
const gchar* filename,
|
||||
gboolean activate,
|
||||
gboolean test)
|
||||
{
|
||||
gchar* fullname;
|
||||
GModule* module;
|
||||
typedef GObject* (*extension_init_func)(void);
|
||||
extension_init_func extension_init;
|
||||
static GHashTable* modules = NULL;
|
||||
GObject* extension;
|
||||
|
||||
g_return_val_if_fail (extension_path != NULL, NULL);
|
||||
g_return_val_if_fail (filename != NULL, NULL);
|
||||
|
||||
if (strchr (filename, '/'))
|
||||
{
|
||||
gchar* clean = g_strndup (filename, strchr (filename, '/') - filename);
|
||||
fullname = g_build_filename (extension_path, clean, NULL);
|
||||
g_free (clean);
|
||||
}
|
||||
else
|
||||
fullname = g_build_filename (extension_path, filename, NULL);
|
||||
|
||||
/* Ignore files which don't have the correct suffix */
|
||||
if (!g_str_has_suffix (fullname, G_MODULE_SUFFIX))
|
||||
{
|
||||
g_free (fullname);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
module = g_module_open (fullname, G_MODULE_BIND_LOCAL);
|
||||
g_free (fullname);
|
||||
|
||||
/* GModule detects repeated loading but exposes no API to check it.
|
||||
Skip any modules that were loaded before. */
|
||||
if (modules == NULL)
|
||||
modules = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref);
|
||||
if ((extension = g_hash_table_lookup (modules, module)))
|
||||
return extension;
|
||||
|
||||
if (module && g_module_symbol (module, "extension_init",
|
||||
(gpointer) &extension_init))
|
||||
{
|
||||
typedef void (*extension_test_func)(void);
|
||||
extension_test_func extension_test;
|
||||
if ((extension = extension_init ()))
|
||||
{
|
||||
if (test && g_module_symbol (module, "extension_test", (gpointer) &extension_test))
|
||||
extension_test ();
|
||||
g_object_set_data_full (G_OBJECT (extension), "filename", g_strdup (filename), g_free);
|
||||
g_hash_table_insert (modules, module, extension);
|
||||
}
|
||||
}
|
||||
|
||||
return extension;
|
||||
}
|
||||
|
||||
GObject*
|
||||
midori_extension_activate_gracefully (MidoriApp* app,
|
||||
const gchar* extension_path,
|
||||
const gchar* filename,
|
||||
gboolean activate)
|
||||
{
|
||||
GObject* extension = midori_extension_load_from_file (extension_path, filename, activate, FALSE);
|
||||
|
||||
midori_extension_activate (extension, filename, activate, app);
|
||||
if (!extension && g_module_error () != NULL)
|
||||
{
|
||||
KatzeArray* extensions = katze_object_get_object (app, "extensions");
|
||||
extension = g_object_new (MIDORI_TYPE_EXTENSION,
|
||||
"name", filename,
|
||||
"description", g_module_error (),
|
||||
NULL);
|
||||
g_warning ("%s", g_module_error ());
|
||||
katze_array_add_item (extensions, extension);
|
||||
g_object_unref (extensions);
|
||||
g_object_unref (extension);
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
return extension;
|
||||
}
|
||||
|
||||
static void
|
||||
midori_extension_add_to_list (MidoriApp* app,
|
||||
MidoriExtension* extension,
|
||||
const gchar* filename)
|
||||
{
|
||||
g_return_if_fail (MIDORI_IS_APP (app));
|
||||
g_return_if_fail (filename != NULL);
|
||||
KatzeArray* extensions = katze_object_get_object (app, "extensions");
|
||||
g_return_if_fail (KATZE_IS_ARRAY (extensions));
|
||||
if (katze_array_get_item_index (extensions, extension) >= 0)
|
||||
return;
|
||||
/* FIXME need proper stock extension mechanism */
|
||||
if (!strcmp (filename, "libtransfers." G_MODULE_SUFFIX))
|
||||
return;
|
||||
|
||||
katze_array_add_item (extensions, extension);
|
||||
g_object_unref (extensions);
|
||||
|
||||
if (midori_paths_is_readonly ())
|
||||
return;
|
||||
|
||||
/* Signal that we want the extension to load and save */
|
||||
if (midori_extension_is_prepared (extension))
|
||||
{
|
||||
g_warn_if_fail (extension->priv->config_dir == NULL);
|
||||
extension->priv->config_dir = midori_paths_get_extension_config_dir (filename);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
midori_extension_activate (GObject* extension,
|
||||
const gchar* filename,
|
||||
gboolean activate,
|
||||
MidoriApp* app)
|
||||
{
|
||||
if (MIDORI_IS_EXTENSION (extension))
|
||||
{
|
||||
if (filename != NULL)
|
||||
midori_extension_add_to_list (app, MIDORI_EXTENSION (extension), filename);
|
||||
if (activate && !midori_extension_is_active (MIDORI_EXTENSION (extension)))
|
||||
g_signal_emit_by_name (extension, "activate", app);
|
||||
}
|
||||
else if (KATZE_IS_ARRAY (extension))
|
||||
{
|
||||
gboolean success = FALSE;
|
||||
MidoriExtension* extension_item;
|
||||
KATZE_ARRAY_FOREACH_ITEM (extension_item, KATZE_ARRAY (extension))
|
||||
if (MIDORI_IS_EXTENSION (extension_item))
|
||||
{
|
||||
gchar* key = extension_item->priv->key;
|
||||
g_return_if_fail (key != NULL);
|
||||
if (filename != NULL && strchr (filename, '/'))
|
||||
{
|
||||
gchar* clean = g_strndup (filename, strchr (filename, '/') - filename);
|
||||
g_object_set_data_full (G_OBJECT (extension_item), "filename", clean, g_free);
|
||||
midori_extension_add_to_list (app, extension_item, clean);
|
||||
}
|
||||
else if (filename != NULL)
|
||||
{
|
||||
midori_extension_add_to_list (app, extension_item, filename);
|
||||
g_object_set_data_full (G_OBJECT (extension_item), "filename", g_strdup (filename), g_free);
|
||||
}
|
||||
if (activate && !midori_extension_is_active (MIDORI_EXTENSION (extension_item))
|
||||
&& filename && strstr (filename, key))
|
||||
{
|
||||
g_signal_emit_by_name (extension_item, "activate", app);
|
||||
success = TRUE;
|
||||
}
|
||||
}
|
||||
/* Passed a multi extension w/o key or non-existing key */
|
||||
g_warn_if_fail (!activate || success);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* midori_extension_is_prepared:
|
||||
* @extension: a #MidoriExtension
|
||||
|
@ -539,29 +790,6 @@ midori_extension_is_active (MidoriExtension* extension)
|
|||
return extension->priv->active > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* midori_extension_is_deactivating:
|
||||
* @extension: a #MidoriExtension
|
||||
*
|
||||
* Determines if @extension is currently in the process of
|
||||
* being deactivated.
|
||||
*
|
||||
* Extensions remain fully functional even while being
|
||||
* deactivated, so you can for instance still save settings
|
||||
* but you may need to cleanup during deactivation.
|
||||
*
|
||||
* Return value: %TRUE if @extension is deactivating
|
||||
*
|
||||
* Since: 0.1.7
|
||||
**/
|
||||
gboolean
|
||||
midori_extension_is_deactivating (MidoriExtension* extension)
|
||||
{
|
||||
g_return_val_if_fail (MIDORI_IS_EXTENSION (extension), FALSE);
|
||||
|
||||
return extension->priv->active == 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* midori_extension_deactivate:
|
||||
* @extension: a #MidoriExtension
|
||||
|
@ -573,7 +801,6 @@ midori_extension_deactivate (MidoriExtension* extension)
|
|||
{
|
||||
g_return_if_fail (midori_extension_is_active (extension));
|
||||
|
||||
extension->priv->active = 2;
|
||||
g_signal_emit (extension, signals[DEACTIVATE], 0);
|
||||
extension->priv->active = 0;
|
||||
katze_object_assign (extension->priv->app, NULL);
|
||||
|
@ -616,15 +843,6 @@ midori_extension_get_config_dir (MidoriExtension* extension)
|
|||
|
||||
g_return_val_if_fail (midori_extension_is_prepared (extension), NULL);
|
||||
|
||||
if (!extension->priv->config_dir)
|
||||
{
|
||||
gchar* filename = g_object_get_data (G_OBJECT (extension), "filename");
|
||||
if (!filename)
|
||||
return "/";
|
||||
extension->priv->config_dir = g_build_filename (
|
||||
sokoke_set_config_dir (NULL), "extensions", filename, NULL);
|
||||
}
|
||||
|
||||
return extension->priv->config_dir;
|
||||
}
|
||||
|
||||
|
@ -656,6 +874,22 @@ midori_extension_install_boolean (MidoriExtension* extension,
|
|||
default_value, FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
midori_extension_save_settings (MidoriExtension *extension)
|
||||
{
|
||||
GError* error = NULL;
|
||||
gchar* config_file = g_build_filename (extension->priv->config_dir, "config", NULL);
|
||||
katze_mkdir_with_parents (extension->priv->config_dir, 0700);
|
||||
sokoke_key_file_save_to_file (extension->priv->key_file, config_file, &error);
|
||||
if (error)
|
||||
{
|
||||
printf (_("The configuration of the extension '%s' couldn't be saved: %s\n"),
|
||||
extension->priv->name, error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
g_free (config_file);
|
||||
}
|
||||
|
||||
/**
|
||||
* midori_extension_get_boolean:
|
||||
* @extension: a #MidoriExtension
|
||||
|
@ -708,23 +942,14 @@ midori_extension_set_boolean (MidoriExtension* extension,
|
|||
setting->value = value;
|
||||
if (extension->priv->key_file)
|
||||
{
|
||||
GError* error = NULL;
|
||||
/* FIXME: Handle readonly folder/ file */
|
||||
gchar* config_file = g_build_filename (extension->priv->config_dir,
|
||||
"config", NULL);
|
||||
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);
|
||||
if (error)
|
||||
{
|
||||
printf (_("The configuration of the extension '%s' couldn't be saved: %s\n"),
|
||||
extension->priv->name, error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
midori_extension_save_settings (extension);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* midori_extension_install_integer:
|
||||
* @extension: a #MidoriExtension
|
||||
|
@ -805,20 +1030,9 @@ midori_extension_set_integer (MidoriExtension* extension,
|
|||
setting->value = value;
|
||||
if (extension->priv->key_file)
|
||||
{
|
||||
GError* error = NULL;
|
||||
/* FIXME: Handle readonly folder/ file */
|
||||
gchar* config_file = g_build_filename (extension->priv->config_dir,
|
||||
"config", NULL);
|
||||
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);
|
||||
if (error)
|
||||
{
|
||||
printf (_("The configuration of the extension '%s' couldn't be saved: %s\n"),
|
||||
extension->priv->name, error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
midori_extension_save_settings (extension);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -902,20 +1116,9 @@ midori_extension_set_string (MidoriExtension* extension,
|
|||
katze_assign (setting->value, g_strdup (value));
|
||||
if (extension->priv->key_file)
|
||||
{
|
||||
GError* error = NULL;
|
||||
/* FIXME: Handle readonly folder/ file */
|
||||
gchar* config_file = g_build_filename (extension->priv->config_dir,
|
||||
"config", NULL);
|
||||
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);
|
||||
if (error)
|
||||
{
|
||||
printf (_("The configuration of the extension '%s' couldn't be saved: %s\n"),
|
||||
extension->priv->name, error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
midori_extension_save_settings (extension);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1014,19 +1217,8 @@ midori_extension_set_string_list (MidoriExtension* extension,
|
|||
|
||||
if (extension->priv->key_file)
|
||||
{
|
||||
GError* error = NULL;
|
||||
/* FIXME: Handle readonly folder/ file */
|
||||
gchar* config_file = g_build_filename (extension->priv->config_dir,
|
||||
"config", NULL);
|
||||
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);
|
||||
if (error)
|
||||
{
|
||||
printf (_("The configuration of the extension '%s' couldn't be saved: %s\n"),
|
||||
extension->priv->name, error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
midori_extension_save_settings (extension);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright (C) 2008 Christian Dywan <christian@twotoasts.de>
|
||||
Copyright (C) 2008-2012 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
|
||||
|
@ -48,6 +48,24 @@ struct _MidoriExtensionClass
|
|||
GType
|
||||
midori_extension_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GObject*
|
||||
midori_extension_load_from_file (const gchar* extension_path,
|
||||
const gchar* filename,
|
||||
gboolean activate,
|
||||
gboolean test);
|
||||
|
||||
void
|
||||
midori_extension_activate (GObject* extension,
|
||||
const gchar* filename,
|
||||
gboolean activate,
|
||||
MidoriApp* app);
|
||||
|
||||
GObject*
|
||||
midori_extension_activate_gracefully (MidoriApp* app,
|
||||
const gchar* extension_path,
|
||||
const gchar* filename,
|
||||
gboolean activate);
|
||||
|
||||
gboolean
|
||||
midori_extension_is_prepared (MidoriExtension* extension);
|
||||
|
||||
|
@ -57,9 +75,6 @@ midori_extension_has_preferences (MidoriExtension* extension);
|
|||
gboolean
|
||||
midori_extension_is_active (MidoriExtension* extension);
|
||||
|
||||
gboolean
|
||||
midori_extension_is_deactivating (MidoriExtension* extension);
|
||||
|
||||
void
|
||||
midori_extension_deactivate (MidoriExtension* extension);
|
||||
|
||||
|
@ -128,6 +143,11 @@ midori_extension_set_string_list (MidoriExtension* extension,
|
|||
gchar** value,
|
||||
gsize length);
|
||||
|
||||
void
|
||||
midori_extension_load_from_folder (MidoriApp* app,
|
||||
gchar** keys,
|
||||
gboolean activate);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __MIDORI_EXTENSION_H__ */
|
||||
|
|
|
@ -1,3 +1,13 @@
|
|||
/*
|
||||
Copyright (C) 2012 André Stösel <andre@stoesel.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.
|
||||
*/
|
||||
|
||||
public class Midori.ExtensionsColumn : Gtk.TreeViewColumn {
|
||||
public signal void row_clicked (Gtk.TreeView view, Gtk.TreePath path);
|
||||
|
|
616
midori/midori-frontend.c
Normal file
616
midori/midori-frontend.c
Normal file
|
@ -0,0 +1,616 @@
|
|||
/*
|
||||
Copyright (C) 2008-2012 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-array.h"
|
||||
#include "midori-bookmarks.h"
|
||||
#include "midori-history.h"
|
||||
#include "midori-preferences.h"
|
||||
#include "midori-privatedata.h"
|
||||
#include "midori-session.h"
|
||||
#include "midori-searchaction.h"
|
||||
#include "midori-panel.h"
|
||||
#include "panels/midori-bookmarks.h"
|
||||
#include "panels/midori-history.h"
|
||||
#include "sokoke.h"
|
||||
#include <glib/gi18n-lib.h>
|
||||
|
||||
static MidoriBrowser*
|
||||
midori_frontend_browser_new_window_cb (MidoriBrowser* browser,
|
||||
MidoriBrowser* new_browser,
|
||||
gpointer user_data)
|
||||
{
|
||||
if (new_browser == NULL)
|
||||
new_browser = midori_browser_new ();
|
||||
g_object_set (new_browser,
|
||||
"settings", midori_browser_get_settings (browser),
|
||||
NULL);
|
||||
gtk_widget_show (GTK_WIDGET (new_browser));
|
||||
return new_browser;
|
||||
}
|
||||
|
||||
MidoriBrowser*
|
||||
midori_web_app_new (const gchar* config,
|
||||
const gchar* webapp,
|
||||
gchar** open_uris,
|
||||
gchar** execute_commands,
|
||||
gint inactivity_reset,
|
||||
const gchar* block_uris)
|
||||
{
|
||||
guint i;
|
||||
|
||||
midori_paths_init (MIDORI_RUNTIME_MODE_APP, config);
|
||||
#ifndef HAVE_WEBKIT2
|
||||
g_object_set_data (G_OBJECT (webkit_get_default_session ()), "pass-through-console", (void*)1);
|
||||
#endif
|
||||
MidoriBrowser* browser = midori_browser_new ();
|
||||
g_signal_connect (browser, "new-window",
|
||||
G_CALLBACK (midori_frontend_browser_new_window_cb), NULL);
|
||||
|
||||
midori_browser_set_action_visible (browser, "Menubar", FALSE);
|
||||
midori_browser_set_action_visible (browser, "CompactMenu", FALSE);
|
||||
|
||||
MidoriWebSettings* settings = midori_browser_get_settings (browser);
|
||||
g_object_set (settings,
|
||||
"show-menubar", FALSE,
|
||||
"show-navigationbar", FALSE,
|
||||
"toolbar-items", "Back,Forward,ReloadStop,Location,Homepage",
|
||||
"show-statusbar", FALSE,
|
||||
"show-panel", FALSE,
|
||||
"last-window-state", MIDORI_WINDOW_NORMAL,
|
||||
"inactivity-reset", inactivity_reset,
|
||||
"block-uris", block_uris,
|
||||
NULL);
|
||||
midori_load_soup_session (settings);
|
||||
|
||||
KatzeArray* search_engines = midori_search_engines_new_from_folder (NULL);
|
||||
g_object_set (browser,
|
||||
"show-tabs", open_uris != NULL,
|
||||
"settings", settings,
|
||||
NULL);
|
||||
midori_browser_set_action_visible (browser, "Panel", FALSE);
|
||||
g_object_unref (search_engines);
|
||||
|
||||
if (webapp != NULL)
|
||||
{
|
||||
gchar* tmp_uri = sokoke_magic_uri (webapp, FALSE, TRUE);
|
||||
g_object_set (settings, "homepage", tmp_uri, NULL);
|
||||
midori_browser_add_uri (browser, tmp_uri);
|
||||
g_free (tmp_uri);
|
||||
}
|
||||
|
||||
for (i = 0; open_uris && open_uris[i]; i++)
|
||||
{
|
||||
gchar* new_uri = sokoke_magic_uri (open_uris[i], FALSE, TRUE);
|
||||
midori_browser_add_uri (browser, new_uri);
|
||||
g_free (new_uri);
|
||||
}
|
||||
if (midori_browser_get_n_pages (browser) == 0)
|
||||
midori_browser_add_uri (browser, "about:blank");
|
||||
gtk_widget_show (GTK_WIDGET (browser));
|
||||
|
||||
for (i = 0; execute_commands && execute_commands[i]; i++)
|
||||
{
|
||||
midori_browser_assert_action (browser, execute_commands[i]);
|
||||
midori_browser_activate_action (browser, execute_commands[i]);
|
||||
}
|
||||
return browser;
|
||||
}
|
||||
|
||||
static void
|
||||
midori_trash_add_item_no_save_cb (KatzeArray* trash,
|
||||
GObject* item)
|
||||
{
|
||||
if (katze_array_get_nth_item (trash, 10))
|
||||
{
|
||||
KatzeItem* obsolete_item = katze_array_get_nth_item (trash, 0);
|
||||
katze_array_remove_item (trash, obsolete_item);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
midori_trash_remove_item_cb (KatzeArray* trash,
|
||||
GObject* item)
|
||||
{
|
||||
gchar* config_file = midori_paths_get_config_filename_for_writing ("tabtrash.xbel");
|
||||
GError* error = NULL;
|
||||
midori_trash_add_item_no_save_cb (trash, item);
|
||||
if (!midori_array_to_file (trash, config_file, "xbel-tiny", &error))
|
||||
{
|
||||
/* i18n: Trash, or wastebin, containing closed tabs */
|
||||
g_warning (_("The trash couldn't be saved. %s"), error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
g_free (config_file);
|
||||
}
|
||||
|
||||
static void
|
||||
midori_trash_add_item_cb (KatzeArray* trash,
|
||||
GObject* item)
|
||||
{
|
||||
midori_trash_remove_item_cb (trash, item);
|
||||
}
|
||||
|
||||
MidoriBrowser*
|
||||
midori_private_app_new (const gchar* config,
|
||||
const gchar* webapp,
|
||||
gchar** open_uris,
|
||||
gchar** execute_commands,
|
||||
gint inactivity_reset,
|
||||
const gchar* block_uris)
|
||||
{
|
||||
guint i;
|
||||
|
||||
midori_paths_init (MIDORI_RUNTIME_MODE_PRIVATE, config);
|
||||
#ifndef HAVE_WEBKIT2
|
||||
g_object_set_data (G_OBJECT (webkit_get_default_session ()), "pass-through-console", (void*)1);
|
||||
#endif
|
||||
|
||||
/* Mask the timezone, which can be read by Javascript */
|
||||
g_setenv ("TZ", "UTC", TRUE);
|
||||
|
||||
MidoriBrowser* browser = midori_browser_new ();
|
||||
g_signal_connect (browser, "new-window",
|
||||
G_CALLBACK (midori_frontend_browser_new_window_cb), NULL);
|
||||
|
||||
MidoriWebSettings* settings = midori_settings_new_full (NULL);
|
||||
g_object_set (settings,
|
||||
"preferred-languages", "en",
|
||||
"enable-private-browsing", TRUE,
|
||||
#ifdef HAVE_LIBSOUP_2_29_91
|
||||
"first-party-cookies-only", TRUE,
|
||||
#endif
|
||||
"enable-html5-database", FALSE,
|
||||
"enable-html5-local-storage", FALSE,
|
||||
"enable-offline-web-application-cache", FALSE,
|
||||
/* Arguably DNS prefetching is or isn't a privacy concern. For the
|
||||
* lack of more fine-grained control we'll go the safe route. */
|
||||
#if WEBKIT_CHECK_VERSION (1, 3, 11)
|
||||
"enable-dns-prefetching", FALSE,
|
||||
#endif
|
||||
"strip-referer", TRUE,
|
||||
"show-panel", FALSE,
|
||||
"last-window-state", MIDORI_WINDOW_NORMAL,
|
||||
"inactivity-reset", inactivity_reset,
|
||||
"block-uris", block_uris,
|
||||
NULL);
|
||||
midori_load_soup_session (settings);
|
||||
|
||||
/* In-memory trash for re-opening closed tabs */
|
||||
KatzeArray* trash = katze_array_new (KATZE_TYPE_ITEM);
|
||||
g_signal_connect_after (trash, "add-item",
|
||||
G_CALLBACK (midori_trash_add_item_no_save_cb), NULL);
|
||||
|
||||
KatzeArray* search_engines = midori_search_engines_new_from_folder (NULL);
|
||||
g_object_set (browser,
|
||||
"settings", settings,
|
||||
"trash", trash,
|
||||
"search-engines", search_engines,
|
||||
NULL);
|
||||
g_object_unref (settings);
|
||||
g_object_unref (trash);
|
||||
g_object_unref (search_engines);
|
||||
|
||||
midori_browser_set_action_visible (browser, "Tools", FALSE);
|
||||
midori_browser_set_action_visible (browser, "ClearPrivateData", FALSE);
|
||||
midori_browser_set_action_visible (browser, "Panel", FALSE);
|
||||
#if GTK_CHECK_VERSION (3, 0, 0)
|
||||
g_object_set (gtk_widget_get_settings (GTK_WIDGET (browser)),
|
||||
"gtk-application-prefer-dark-theme", TRUE,
|
||||
NULL);
|
||||
#endif
|
||||
|
||||
if (webapp != NULL)
|
||||
{
|
||||
gchar* tmp_uri = sokoke_magic_uri (webapp, FALSE, TRUE);
|
||||
g_object_set (settings, "homepage", tmp_uri, NULL);
|
||||
midori_browser_add_uri (browser, tmp_uri);
|
||||
g_free (tmp_uri);
|
||||
}
|
||||
|
||||
for (i = 0; open_uris && open_uris[i]; i++)
|
||||
{
|
||||
gchar* new_uri = sokoke_magic_uri (open_uris[i], FALSE, TRUE);
|
||||
midori_browser_add_uri (browser, new_uri);
|
||||
g_free (new_uri);
|
||||
}
|
||||
if (midori_browser_get_n_pages (browser) == 0)
|
||||
midori_browser_add_uri (browser, "about:private");
|
||||
gtk_widget_show (GTK_WIDGET (browser));
|
||||
|
||||
for (i = 0; execute_commands && execute_commands[i]; i++)
|
||||
{
|
||||
midori_browser_assert_action (browser, execute_commands[i]);
|
||||
midori_browser_activate_action (browser, execute_commands[i]);
|
||||
}
|
||||
|
||||
/* FIXME need proper stock extension mechanism */
|
||||
midori_browser_activate_action (browser, "libtransfers." G_MODULE_SUFFIX "=true");
|
||||
g_assert (g_module_error () == NULL);
|
||||
|
||||
return browser;
|
||||
}
|
||||
|
||||
static void
|
||||
midori_browser_show_preferences_cb (MidoriBrowser* browser,
|
||||
KatzePreferences* preferences,
|
||||
MidoriApp* app)
|
||||
{
|
||||
midori_preferences_add_extension_category (preferences, app);
|
||||
}
|
||||
|
||||
static void
|
||||
midori_browser_privacy_preferences_cb (MidoriBrowser* browser,
|
||||
KatzePreferences* preferences,
|
||||
MidoriApp* app)
|
||||
{
|
||||
MidoriWebSettings* settings = midori_browser_get_settings (browser);
|
||||
midori_preferences_add_privacy_category (preferences, settings);
|
||||
}
|
||||
|
||||
static void
|
||||
midori_app_add_browser_cb (MidoriApp* app,
|
||||
MidoriBrowser* browser,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkWidget* panel;
|
||||
GtkWidget* addon;
|
||||
|
||||
panel = katze_object_get_object (browser, "panel");
|
||||
|
||||
addon = g_object_new (MIDORI_TYPE_BOOKMARKS, "app", app, "visible", TRUE, NULL);
|
||||
midori_panel_append_page (MIDORI_PANEL (panel), MIDORI_VIEWABLE (addon));
|
||||
|
||||
addon = g_object_new (MIDORI_TYPE_HISTORY, "app", app, "visible", TRUE, NULL);
|
||||
midori_panel_append_page (MIDORI_PANEL (panel), MIDORI_VIEWABLE (addon));
|
||||
|
||||
/* Extensions */
|
||||
g_signal_connect (browser, "show-preferences",
|
||||
G_CALLBACK (midori_browser_privacy_preferences_cb), app);
|
||||
g_signal_connect (browser, "show-preferences",
|
||||
G_CALLBACK (midori_browser_show_preferences_cb), app);
|
||||
|
||||
g_object_unref (panel);
|
||||
}
|
||||
|
||||
static void
|
||||
button_disable_extensions_clicked_cb (GtkWidget* button,
|
||||
MidoriApp* app)
|
||||
{
|
||||
/* Reset frozen list of active extensions */
|
||||
g_object_set_data (G_OBJECT (app), "extensions", NULL);
|
||||
gtk_widget_set_sensitive (button, FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
button_modify_preferences_clicked_cb (GtkWidget* button,
|
||||
MidoriWebSettings* settings)
|
||||
{
|
||||
GtkWidget* dialog = midori_preferences_new (
|
||||
GTK_WINDOW (gtk_widget_get_toplevel (button)), settings);
|
||||
if (midori_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_DELETE_EVENT)
|
||||
gtk_widget_destroy (dialog);
|
||||
}
|
||||
|
||||
static void
|
||||
midori_frontend_crash_log_cb (GtkWidget* button,
|
||||
gchar* crash_log)
|
||||
{
|
||||
GError* error = NULL;
|
||||
if (!sokoke_show_uri (gtk_widget_get_screen (button), crash_log, 0, &error))
|
||||
{
|
||||
sokoke_message_dialog (GTK_MESSAGE_ERROR,
|
||||
_("Could not run external program."),
|
||||
error->message, FALSE);
|
||||
g_error_free (error);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
midori_frontend_debugger_cb (GtkWidget* button,
|
||||
GtkDialog* dialog)
|
||||
{
|
||||
gtk_dialog_response (dialog, GTK_RESPONSE_HELP);
|
||||
}
|
||||
|
||||
static MidoriStartup
|
||||
midori_frontend_diagnostic_dialog (MidoriApp* app,
|
||||
MidoriWebSettings* settings,
|
||||
KatzeArray* session)
|
||||
{
|
||||
GtkWidget* dialog;
|
||||
GtkWidget* content_area;
|
||||
GtkWidget* align;
|
||||
GtkWidget* box;
|
||||
GtkWidget* button;
|
||||
MidoriStartup load_on_startup = katze_object_get_enum (settings, "load-on-startup");
|
||||
gint response;
|
||||
|
||||
dialog = gtk_message_dialog_new (
|
||||
NULL, 0, GTK_MESSAGE_WARNING, GTK_BUTTONS_NONE,
|
||||
_("Midori crashed the last time it was opened. You can report the problem at %s."),
|
||||
PACKAGE_BUGREPORT);
|
||||
gtk_window_set_skip_taskbar_hint (GTK_WINDOW (dialog), FALSE);
|
||||
gtk_window_set_title (GTK_WINDOW (dialog), g_get_application_name ());
|
||||
content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
|
||||
align = gtk_alignment_new (0.5, 0.5, 0.5, 0.5);
|
||||
gtk_container_add (GTK_CONTAINER (content_area), align);
|
||||
box = gtk_hbox_new (FALSE, 0);
|
||||
gtk_container_add (GTK_CONTAINER (align), box);
|
||||
button = gtk_button_new_with_mnemonic (_("Modify _preferences"));
|
||||
g_signal_connect (button, "clicked",
|
||||
G_CALLBACK (button_modify_preferences_clicked_cb), settings);
|
||||
gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 4);
|
||||
button = gtk_button_new_with_mnemonic (_("Disable all _extensions"));
|
||||
if (g_object_get_data (G_OBJECT (app), "extensions"))
|
||||
g_signal_connect (button, "clicked",
|
||||
G_CALLBACK (button_disable_extensions_clicked_cb), app);
|
||||
else
|
||||
gtk_widget_set_sensitive (button, FALSE);
|
||||
gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 4);
|
||||
gtk_widget_show_all (align);
|
||||
button = katze_property_proxy (settings, "show-crash-dialog", NULL);
|
||||
gtk_button_set_label (GTK_BUTTON (button), _("Show a dialog after Midori crashed"));
|
||||
gtk_widget_show (button);
|
||||
gtk_container_add (GTK_CONTAINER (content_area), button);
|
||||
gtk_container_set_focus_child (GTK_CONTAINER (dialog), gtk_dialog_get_action_area (GTK_DIALOG (dialog)));
|
||||
gtk_dialog_add_buttons (GTK_DIALOG (dialog),
|
||||
_("Discard old tabs"), MIDORI_STARTUP_BLANK_PAGE,
|
||||
_("Show last tabs without loading"), MIDORI_STARTUP_DELAYED_PAGES,
|
||||
_("Show last open tabs"), MIDORI_STARTUP_LAST_OPEN_PAGES,
|
||||
NULL);
|
||||
|
||||
gchar* crash_log = g_build_filename (midori_paths_get_runtime_dir (), "gdb.bt", NULL);
|
||||
if (g_access (crash_log, F_OK) == 0)
|
||||
{
|
||||
GtkWidget* button = gtk_button_new_with_mnemonic (_("Show last crash _log"));
|
||||
g_signal_connect_data (button, "clicked",
|
||||
G_CALLBACK (midori_frontend_crash_log_cb), crash_log,
|
||||
(GClosureNotify)g_free, 0);
|
||||
gtk_widget_show (button);
|
||||
gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 4);
|
||||
}
|
||||
else
|
||||
g_free (crash_log);
|
||||
|
||||
gchar* gdb = g_find_program_in_path ("gdb");
|
||||
if (gdb != NULL)
|
||||
{
|
||||
GtkWidget* button = gtk_button_new_with_mnemonic (_("Run in _debugger"));
|
||||
g_signal_connect (button, "clicked",
|
||||
G_CALLBACK (midori_frontend_debugger_cb), dialog);
|
||||
gtk_widget_show (button);
|
||||
gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 4);
|
||||
}
|
||||
gtk_dialog_set_default_response (GTK_DIALOG (dialog),
|
||||
load_on_startup == MIDORI_STARTUP_HOMEPAGE
|
||||
? MIDORI_STARTUP_BLANK_PAGE : load_on_startup);
|
||||
|
||||
/* GtkLabel can't wrap the text properly. Until some day
|
||||
this works, we implement this hack to do it ourselves. */
|
||||
GList* ch = gtk_container_get_children (GTK_CONTAINER (content_area));
|
||||
GtkWidget* hbox = (GtkWidget*)g_list_nth_data (ch, 0);
|
||||
g_list_free (ch);
|
||||
ch = gtk_container_get_children (GTK_CONTAINER (hbox));
|
||||
GtkWidget* vbox = (GtkWidget*)g_list_nth_data (ch, 1);
|
||||
g_list_free (ch);
|
||||
ch = gtk_container_get_children (GTK_CONTAINER (vbox));
|
||||
GtkWidget* label = (GtkWidget*)g_list_nth_data (ch, 0);
|
||||
g_list_free (ch);
|
||||
GtkRequisition req;
|
||||
gtk_widget_size_request (content_area, &req);
|
||||
gtk_widget_set_size_request (label, req.width * 0.9, -1);
|
||||
|
||||
response = midori_dialog_run (GTK_DIALOG (dialog));
|
||||
gtk_widget_destroy (dialog);
|
||||
if (response == GTK_RESPONSE_DELETE_EVENT)
|
||||
response = G_MAXINT;
|
||||
else if (response == GTK_RESPONSE_HELP)
|
||||
{
|
||||
sokoke_spawn_gdb (gdb, FALSE);
|
||||
response = G_MAXINT;
|
||||
}
|
||||
else if (response == MIDORI_STARTUP_BLANK_PAGE)
|
||||
katze_array_clear (session);
|
||||
return response;
|
||||
}
|
||||
|
||||
MidoriApp*
|
||||
midori_normal_app_new (const gchar* config,
|
||||
gchar* nickname,
|
||||
gboolean diagnostic_dialog,
|
||||
const gchar* webapp,
|
||||
gchar** open_uris,
|
||||
gchar** execute_commands,
|
||||
gint inactivity_reset,
|
||||
const gchar* block_uris)
|
||||
{
|
||||
if (g_str_has_suffix (nickname, "portable"))
|
||||
midori_paths_init (MIDORI_RUNTIME_MODE_PORTABLE, config);
|
||||
else if (g_str_has_suffix (nickname, "normal"))
|
||||
midori_paths_init (MIDORI_RUNTIME_MODE_NORMAL, config);
|
||||
else
|
||||
g_assert_not_reached ();
|
||||
|
||||
MidoriApp* app = midori_app_new (nickname);
|
||||
if (midori_app_instance_is_running (app))
|
||||
{
|
||||
/* It makes no sense to show a crash dialog while running */
|
||||
if (!diagnostic_dialog)
|
||||
{
|
||||
gboolean success = FALSE;
|
||||
if (execute_commands != NULL && midori_app_send_command (app, execute_commands))
|
||||
success = TRUE;
|
||||
if (open_uris != NULL && midori_app_instance_send_uris (app, open_uris))
|
||||
success = TRUE;
|
||||
if (!execute_commands && !open_uris && midori_app_instance_send_new_browser (app))
|
||||
success = TRUE;
|
||||
if (success)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* FIXME: We mustn't lose the URL here; either instance is freezing or inside a crash dialog */
|
||||
sokoke_message_dialog (GTK_MESSAGE_INFO,
|
||||
_("An instance of Midori is already running but not responding.\n"),
|
||||
open_uris ? *open_uris : "", TRUE);
|
||||
return (void*)0xdeadbeef;
|
||||
}
|
||||
|
||||
GString* error_messages = g_string_new (NULL);
|
||||
GError* error = NULL;
|
||||
gchar** extensions;
|
||||
MidoriWebSettings* settings = midori_settings_new_full (&extensions);
|
||||
g_object_set (settings,
|
||||
"enable-developer-extras", TRUE,
|
||||
"enable-html5-database", TRUE,
|
||||
"block-uris", block_uris,
|
||||
NULL);
|
||||
if (inactivity_reset > 0)
|
||||
g_object_set (settings, "inactivity-reset", inactivity_reset, NULL);
|
||||
|
||||
KatzeArray* search_engines = midori_search_engines_new_from_folder (error_messages);
|
||||
/* Pick first search engine as default if not set */
|
||||
gchar* uri = katze_object_get_string (settings, "location-entry-search");
|
||||
if (!(uri && *uri) && !katze_array_is_empty (search_engines))
|
||||
{
|
||||
KatzeItem* item = katze_array_get_nth_item (search_engines, 0);
|
||||
g_object_set (settings, "location-entry-search",
|
||||
katze_item_get_uri (item), NULL);
|
||||
}
|
||||
g_free (uri);
|
||||
|
||||
KatzeArray* bookmarks;
|
||||
gchar* errmsg = NULL;
|
||||
if (!(bookmarks = midori_bookmarks_new (&errmsg)))
|
||||
{
|
||||
g_string_append_printf (error_messages,
|
||||
_("Bookmarks couldn't be loaded: %s\n"), errmsg);
|
||||
katze_assign (errmsg, NULL);
|
||||
}
|
||||
|
||||
gchar* config_file = NULL;
|
||||
KatzeArray* session = katze_array_new (KATZE_TYPE_ITEM);
|
||||
MidoriStartup load_on_startup = katze_object_get_enum (settings, "load-on-startup");
|
||||
if (load_on_startup >= MIDORI_STARTUP_LAST_OPEN_PAGES)
|
||||
{
|
||||
katze_assign (config_file, midori_paths_get_config_filename_for_reading ("session.xbel"));
|
||||
error = NULL;
|
||||
if (!midori_array_from_file (session, config_file, "xbel-tiny", &error))
|
||||
{
|
||||
if (error->code != G_FILE_ERROR_NOENT)
|
||||
g_string_append_printf (error_messages,
|
||||
_("The session couldn't be loaded: %s\n"), error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
}
|
||||
|
||||
KatzeArray* trash = katze_array_new (KATZE_TYPE_ITEM);
|
||||
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);
|
||||
katze_assign (config_file, g_build_filename (config, "tabtrash.xbel", NULL));
|
||||
error = NULL;
|
||||
if (!midori_array_from_file (trash, config_file, "xbel-tiny", &error))
|
||||
{
|
||||
if (error->code != G_FILE_ERROR_NOENT)
|
||||
g_string_append_printf (error_messages,
|
||||
_("The trash couldn't be loaded: %s\n"), error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
|
||||
KatzeArray* history;
|
||||
if (!(history = midori_history_new (&errmsg)))
|
||||
{
|
||||
g_string_append_printf (error_messages,
|
||||
_("The history couldn't be loaded: %s\n"), errmsg);
|
||||
katze_assign (errmsg, NULL);
|
||||
}
|
||||
|
||||
katze_assign (config_file, midori_paths_get_config_filename_for_reading ("speeddial"));
|
||||
MidoriSpeedDial* dial = midori_speed_dial_new (config_file, NULL);
|
||||
|
||||
if (error_messages->len)
|
||||
{
|
||||
GtkWidget* dialog = gtk_message_dialog_new (
|
||||
NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_NONE,
|
||||
_("The following errors occured:"));
|
||||
gtk_message_dialog_format_secondary_text (
|
||||
GTK_MESSAGE_DIALOG (dialog), "%s", error_messages->str);
|
||||
gtk_dialog_add_buttons (GTK_DIALOG (dialog),
|
||||
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
||||
_("_Ignore"), GTK_RESPONSE_ACCEPT,
|
||||
NULL);
|
||||
if (midori_dialog_run (GTK_DIALOG (dialog)) != GTK_RESPONSE_ACCEPT)
|
||||
return (void*)0xdeadbeef;
|
||||
gtk_widget_destroy (dialog);
|
||||
}
|
||||
g_string_free (error_messages, TRUE);
|
||||
|
||||
g_object_set_data (G_OBJECT (app), "execute-commands", execute_commands);
|
||||
g_object_set_data (G_OBJECT (app), "open-uris", open_uris);
|
||||
g_object_set_data_full (G_OBJECT (app), "extensions", extensions, (GDestroyNotify)g_strfreev);
|
||||
katze_item_set_parent (KATZE_ITEM (session), app);
|
||||
|
||||
katze_assign (config_file, midori_paths_get_config_filename_for_reading ("search"));
|
||||
midori_search_engines_set_filename (search_engines, config_file);
|
||||
|
||||
if ((midori_app_get_crashed (app)
|
||||
&& katze_object_get_boolean (settings, "show-crash-dialog")
|
||||
&& open_uris && !execute_commands)
|
||||
|| diagnostic_dialog)
|
||||
{
|
||||
load_on_startup = midori_frontend_diagnostic_dialog (app, settings, session);
|
||||
if (load_on_startup == G_MAXINT)
|
||||
return NULL;
|
||||
}
|
||||
g_object_set_data (G_OBJECT (settings), "load-on-startup", GINT_TO_POINTER (load_on_startup));
|
||||
|
||||
g_object_set (app, "settings", settings,
|
||||
"bookmarks", bookmarks,
|
||||
"trash", trash,
|
||||
"search-engines", search_engines,
|
||||
"history", history,
|
||||
"speed-dial", dial,
|
||||
NULL);
|
||||
g_signal_connect (app, "add-browser",
|
||||
G_CALLBACK (midori_app_add_browser_cb), NULL);
|
||||
|
||||
g_idle_add (midori_load_soup_session_full, settings);
|
||||
g_idle_add (midori_load_extensions, app);
|
||||
g_idle_add (midori_load_session, session);
|
||||
return app;
|
||||
}
|
||||
|
||||
void
|
||||
midori_normal_app_on_quit (MidoriApp* app)
|
||||
{
|
||||
MidoriWebSettings* settings = katze_object_get_object (app, "settings");
|
||||
KatzeArray* bookmarks = katze_object_get_object (app, "bookmarks");
|
||||
KatzeArray* history = katze_object_get_object (app, "history");
|
||||
|
||||
g_object_notify (G_OBJECT (settings), "load-on-startup");
|
||||
midori_bookmarks_on_quit (bookmarks);
|
||||
midori_history_on_quit (history, settings);
|
||||
midori_private_data_on_quit (settings);
|
||||
/* Removing KatzeHttpCookies makes it save outstanding changes */
|
||||
#ifndef HAVE_WEBKIT2
|
||||
soup_session_remove_feature_by_type (webkit_get_default_session (),
|
||||
KATZE_TYPE_HTTP_COOKIES);
|
||||
#endif
|
||||
|
||||
MidoriStartup load_on_startup = katze_object_get_int (settings, "load-on-startup");
|
||||
if (load_on_startup < MIDORI_STARTUP_LAST_OPEN_PAGES)
|
||||
{
|
||||
gchar* config_file = midori_paths_get_config_filename_for_writing ("session.xbel");
|
||||
g_unlink (config_file);
|
||||
}
|
||||
}
|
||||
|
49
midori/midori-frontend.h
Normal file
49
midori/midori-frontend.h
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
Copyright (C) 2012 Christian Dywan <christian@twotoasts.de>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
See the file COPYING for the full license text.
|
||||
*/
|
||||
|
||||
#ifndef __MIDORI_FRONTEND_H__
|
||||
#define __MIDORI_FRONTEND_H__
|
||||
|
||||
#include "midori/midori-app.h"
|
||||
|
||||
MidoriBrowser*
|
||||
midori_web_app_new (const gchar* config,
|
||||
const gchar* webapp,
|
||||
gchar** open_uris,
|
||||
gchar** execute_commands,
|
||||
gint inactivity_reset,
|
||||
const gchar* block_uris);
|
||||
|
||||
MidoriBrowser*
|
||||
midori_private_app_new (const gchar* config,
|
||||
const gchar* webapp,
|
||||
gchar** open_uris,
|
||||
gchar** execute_commands,
|
||||
gint inactivity_reset,
|
||||
const gchar* block_uris);
|
||||
|
||||
MidoriApp*
|
||||
midori_normal_app_new (const gchar* config,
|
||||
gchar* nickname,
|
||||
gboolean diagnostic_dialog,
|
||||
const gchar* webapp,
|
||||
gchar** open_uris,
|
||||
gchar** execute_commands,
|
||||
gint inactivity_reset,
|
||||
const gchar* block_uris);
|
||||
|
||||
void
|
||||
midori_normal_app_on_quit (MidoriApp* app);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __MIDORI_FRONTEND_H__ */
|
||||
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue