Imported Upstream version 0.1.6

This commit is contained in:
Ryan Niebur 2009-05-14 21:14:10 -07:00
commit de4e9a8439
143 changed files with 77181 additions and 0 deletions

64
AUTHORS Normal file
View file

@ -0,0 +1,64 @@
This file is licensed under the terms of the expat license, see the file EXPAT.
Developers:
Christian Dywan <christian@twotoasts.de>
Contributors:
Ori Bernstein <ori@eigenstate.org>
Przemek Sitek <el.pescado@gazeta.pl>
Enrico Tröger <enrico.troeger@uvena.de>
Arnaud Renevier <arenevier@fdn.fr>
Dale Whittaker <dayul@users.sf.net>
Anders F Björklund <afb@macports.org>
Alexander Hesse <alex@phicode.de>
Brian Vuyk <brian@brianvuyk.com>
Nick Schermer <nick@xfce.org>
Matthias Kruk <mkruk@matthiaskruk.de>
Johannes Reinhardt <jreinhardt@ist-dein-freund.de>
Graphics:
extension: Nancy Runge <nancy@twotoasts.de>
midori: Nancy Runge <nancy@twotoasts.de>
news-feed: Nancy Runge <nancy@twotoasts.de>
logo-shade: Nancy Runge <nancy@twotoasts.de>
Translations:
da: Per Kongstad <p_kongstad@op.pl>
de: Enrico Tröger <enrico.troeger@uvena.de>
de: Christian Dywan <christian@twotoasts.de>
el: Evaggelos Balaskas <ebalaskas@ebalaskas.gr>
en_GB: Bastien Nocera <hadess@hadess.net>
en_GB: Abigail Brady <morwen@evilmagic.org>
es: Miguel Anxo Bouzada <mbouzada@gmail.com>
es: Antonio Sanchez <introlinux@gmail.com>
es: Christian Dywan <christian@twotoasts.de>
es: Elega <elega@elega.com.ar>
et: Kristjan Siimson <epost@ksiimson.se>
fi: Elias Julkunen <elias.julkunen@gmail.com>
fr: Christian Dywan <christian@twotoasts.de>
fr: Adrien Nader <camaradetux@gmail.com>
fr: Robert-André Mauchin <zebob.m@pengzone.org>
fr: Pascal Gervais <pggervais@yahoo.ca>
gl: Miguel Anxo Bouzada <mbouzada@gmail.com>
he: Shlomi Israel <sijproject@gmail.com>
hu: SZERVÁC Attila <sas@321.hu>
id: Andhika Padmawan <andhika.padmawan@gmail.com>
it: Sergio Durzu <sergio.durzu@ildeposito.org>
ja: Masato Hashimoto <cabezon.hashimoto@gmail.com>
nl: Vincent Tunru <projects@vinnl.nl>
pl: Przemysław Sitek <el.pescado@gazeta.pl>
pl: Lukasz Romanowicz <romanowicz88@gmail.com>
pt_PT: Sérgio Marques <smarquespt@gmail.com>
ru: Troitskiy Nikita <niktr@mail.ru>
ru: Anton Shestakov <engored@ya.ru>
sv: Mikael Magnusson <mikachu@comhem.se>
tr: Mirat Can Bayrak <MiratCanBayrak@gmail.com>
uk: Dmitry Nikitin <luckas_fb@mail.ru>
zh_CN: Stanley Zhang <yatzhang@gmail.com>
zh_TW: Wei-Lun Chao <william.chao@ossii.com.tw>
Code from other projects:
GTK+/ GdkPixbuf, Matthias Clasen <mclasen@redhat.com>
GTK+/ GtkEntry, Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
Modified by the GTK+ Team and others 1997-2000
libSoup/ CookieJarText, Copyright (C) 2008 Xan Lopez <xan@gnome.org>, Dan Winship <danw@gnome.org>

504
COPYING Normal file
View file

@ -0,0 +1,504 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

314
ChangeLog Normal file
View file

@ -0,0 +1,314 @@
This file is licensed under the terms of the expat license, see the file EXPAT.
v0.1.6:
+ Add Delete All to transferbar
+ Show search in context menu
+ Implement 'Default' search engine
+ Show only icons in Statusbar Features
+ Implement Clear private data
+ Support News Feed icon and external aggregator
+ Fix reloading of Not found pages
+ Fixup spaces when middle click opening
+ Fix possibly wrong identificaton string
+ Optionally search engines in completion
+ Optionally Gtk 2.16 entry progress and icon
+ Experimental panel detaching
+ Support external download manager again
+ Implement '-a', '--app' argument
+ Implement '-c', '--config' argument
+ Fix a bookmark saving issue
+ Support data: URIs in the address entry
+ Several performance and memory leak fixes
+ Load cookies idle to accelerate startup
+ Support mailto: links
+ Save tab reordering in the session
+ Add a Cookie Manager extension
+ Fix crashers in Colourful Tabs
v0.1.5:
+ Add a Colorful Tabs extension
+ Support downloading with WebKitGTK+ 1.1.3
+ Load and save settings of extensions
+ Drop internal source view
+ Require WebKitGTK+ 1.1.1, Glib 2.16 and libsoup 2.25.2
v0.1.4:
+ Automatic inline find can be disabled
+ Implement an Encoding menu
+ Add Open all in Tabs for bookmarks and history
+ Bookmarks can be moved to other folders
+ Fix blank page 'loading' and HTTP authentication
+ Display history dates in the local format
+ Allow editing of completion items
v0.1.3:
+ Sidepanel can be aligned on the right
+ Bookmarks can be organized in folders
+ Support find as you type
+ Support international domain names
+ Tweak location completion
+ Provide default search engines
+ Integrate with Maemo if available
+ Implement Mouse Gestures extension
+ Implement a Plugins panel
+ Editing the toolbar via a context menu
+ Introduce Zoom Text and Images preference
v0.1.2:
+ Open new tabs by clicking on the tabbar
+ Refactor and speed up location completion
+ Show a Crash dialog after crashes
+ Dynamically save files when needed
+ Support Back/ Forward mouse buttons
+ Support javascript: bookmarklets
+ Implement Proxy and Identification string
+ Implement cookie storage on disk
+ Remove autotooled build system
+ Add a new Extensions panel
+ Implement opening of new windows
+ Display tooltips in Preferences
v0.1.1:
+ Reimplement page holder as an extension
+ Introduce a C extension interface
+ Introduce unit tests for automated testing
+ Implement history based location completion
+ Support the Web Inspector in new WebKit versions
+ Bookmarkbar properly reflects changes
+ Improve overall OS X integration
+ Add a Text Editor Preference
+ Add a Compat sidebar Preference
+ Add an Open external pages in Preference
+ Implement source view and cached favicons with libsoup
v0.1.0:
+ Allow for hiding the menubar
+ Make the navigationbar customizable
+ Implement a History panel
+ Remove the HTTP Proxy hack
+ Add an Always Show Tabbar Preference
+ Implement 404 error pages
+ Remove the Primary Clipboard hack
+ Provide user documentation
+ Display Not found errors when possible
+ Remove Stylesheet and Zoom Stepping preferences
+ Make dialogs more compact
+ Ellipsize extremely long menu items
+ Save the trash again when quitting
+ Implement enabling/ disabling addons
v0.0.21:
+ Update some translations
+ Show progress in location when statusbar is hidden
+ Alt + Enter in location should issue a new tab
+ Warn at configure time if GVfs is not installed
+ Remove GVfs code that could caused huge problems
+ Update wad to 1.4.4 to fix building on some systems
v0.0.20:
+ Single instance support using Unique
+ Make it clear that WAF is preferred
+ Provide an 'extension' icon
+ Load user styles from ~/.local/share/midori/styles
+ Use Ctrl+Shift+T for Undo Close Tab
+ Add "open-tabs-next-to-current" preference
+ Use rsvg-convert instead of imagemagick's convert
+ @name in the meta data of userscripts is recognized
+ Remove "small-toolbar" preference
v0.0.19:
+ Improved Greasemonkey compatibility
+ Improve multiple window support
+ Use WAF buildscripts, still keeping autotools
+ Install and use Midori logo
+ Support zooming and printing
+ Enhance Gjs functionality
+ Refactor in some places, particularly Web Search
+ Implement favicons and source view with GIO
+ Introduce new fancy location entry
+ Detect and show news feeds on web sites
+ Save the session as needed, not only on quit
+ Reintroduce Download Manager preference
v0.0.18:
+ First attempt at userscripts and extensions.
+ Show hidden location/ web search temporarily when needed.
+ Turn prefs into MidoriPreferences
+ Fix background tabs, strings and new tab focus.
+ Switch configuration to MidoriWebSettings.
+ Remove 'External programs' logic
+ Append the closed tabs items as a proper submenu.
+ The location is empty and focused by default
+ Implement proper menu positioning.
+ Implement the Console panel for script messages.
+ Implement localization via Gettext.
+ Initial refactoring work, regressions expected
+ Build fix: Webkit's header and pkgconfig name have changed.
+ Implement Fullscreen mode
v0.0.17:
+ Add a preference to choose a user stylesheet.
+ Implement a few preferences with new settings API in WebKit
+ Implement Add Bookmark and a small panel toolbar
+ Escape search engine name and description.
+ Cleanup and WebKit API update
+ Make sure selection actions have a widget.
+ Allow Find Next and Find Previous when the findbox is hidden.
+ Fixed the header of the KatzeThrobber
+ Move XBEL implementation to katze.
+ Implement a throbber widget.
+ Always enable Select All if an editable widget is focussed.
+ Previous/ next tab menu items should be disabled when not needed.
+ Handle the context menu on button press, not release.
+ Open the default page only if there is no session and no uri on the cli.
v0.0.16:
+ Implement editing menu items for the web view.
+ Implement the bookmarks panel with editing capabilities.
+ Prevent repeated checks for the desktop environment.
+ Fix coding style in sokoke.c/ sokoke.h, particularly variable names.
+ Don't update the remembered window size when maximized.
+ Don't remember the window position but the size only.
+ Command line uris should replace the default page.
+ More effective status updates and less entry flickering
+ Enable inline find for websites
+ Make the progressbar work properly again
+ Build fix: Adapt WebKit api changes
+ Add Tab Size to preferences dialog
v0.0.15:
+ Build fix: Remove search api
v0.0.14:
+ FIX Reopening a tab from the trash causes a crash
+ FIX An untitled website keeps the previous title
+ FIX When switching tabs the location/ title isn't updated correctly
+ FIX Issues with the preferences dialog
+ Disable location completion for now
+ Save tabtrash to file
+ Restructure some code
+ Remove color picker and throbber
+ Change the license to LGPL
v0.0.13:
+ Adapt WebKit api change, remove engine wrappers, remove dialog hack
+ Improve XBEL loading and saving
+ Show dialog and backup files on startup errors
+ Rearranged and removed some menus
v0.0.12:
+ FIX Improve flawed window creation
+ Build with and eliminate all compiler warnings
+ Implement clipboard handling menus
+ Allow editing of search engines
+ Update search engines properly
+ Implement bookmarks saving
+ Implement session saving and loading
+ Cleaned up and revised most code
+ Remove legacy webi code
v0.0.11:
+ FIX Back/ forward and initial check menu item states
+ Remove rather useless debugging helpers
+ Improvements on the preferences
+ First attempt at websearch
+ Preserve typed uri on tab switch
+ First attempt at bookmarks, readonly for now
+ Add an animated throbber
v0.0.10:
+ FIX Can crash on context menu or new protocol
+ FIX Location isn't updated on tab switch
+ Remember last window position and size
+ Implement Open menu item
+ Allow using location and web search if hidden
v0.0.9:
+ FIX Close tab not insensitive for only one tab
+ FIX Debug output is broken
+ Display uri when hovering a link
+ Implement link uri related part of context menu
+ Implement alt/ middle/ shift click link
+ First attempt at external protocol handlers
+ Initial download manager integration
+ Adapt WebKit api prefix change
+ More code reorganization and cleanup
v0.0.8:
+ FIX Crash when invoking document context menu via keyboard
+ FIX Can't build with debug = yes on GTK+2.12
+ Changes related to icons in the gui
+ Reorganize code by splitting into several files
+ Switch from WebkitGdk to WebkitGtk
v0.0.7:
+ FIX Make settings finally work flawlessly
+ FIX Can crash when settings are opened
+ Handle all panels in a general way
+ Install xdg compliant desktop file
+ Implement location and web search menu items
+ Display a loading icon on tabs again
+ Changed the settings dialog again
v0.0.6:
+ FIX Closing an individual tab doesn't work correctly.
+ FIX Doesn't build with gtkwebcore.
+ Reimplement menus and and navibar with GtkUIManager.
+ Improve document handling in general.
+ Finished tab trash menu.
+ Implement searchbox default text.
+ Remove some gtkwebcore code.
+ Use Xfce style dialog in Xfce.
+ Implement a few settings.
+ Change the panel's look.
+ Implement a 'pageholder' panel.
v0.0.5:
+ Implement a few more signals for WebkitGdk.
+ Add tooltips to navigation toolbar buttons.
+ First attempt on a settings dialog.
+ Reimplemented color picker.
+ Autocompletion for location and searchbox.
+ Changed menu items and incremental findbar.
+ Implement tab switching via keyboard.
v0.0.4:
+ FIX Midori segfaults when quitting.
+ FIX Config loading and saving is broken.
+ Switch WebkitGdk to gtk api and make it the build default.
+ Register custom stock icons instead of icon theme magic.
+ Implement dynamic window menu.
+ First attempt on resizable panels.
+ Add about dialog.
v0.0.3:
+ FIX Refresh via menu or shortcut crashes the browser.
+ FIX Assertions with and visibility of the progressbar.
+ FIX Tabs are not reorderable.
+ Package versions in ./configure result and --version output.
+ Improve view menu and add tools menu.
+ Replace deprecated functions and macros.
+ Implement settings saving and loading.
+ Fill the common context menu with items
+ Allow multiple homepages, seperated by '|'.
+ Make code typesafe and C++ friendly.
+ Initially support WebkitGdk directly.
+ Urlify location inputs automatically.
v0.0.2:
+ Dynamic tab trash menu.
+ Update UI when page is changed.
+ Enhanced WebkitGtk support.
+ New function sokoke_dialog_run_modeless.
+ Finished on_document_request_script_prompt.
+ One name and version, visible in the user agent.
+ Changed some accelerators and menu items.
+ Create and destroy color picker properly.
+ Ctrl + Wheel resets the zoom level.
+ Escape in the location entry resets the uri.
+ Use gtk-webcore prefix instead of osb now.
+ Save keybindings on quit.
+ Fancy autotools build setup.
v0.0.1:
+ Initial release

18
EXPAT Normal file
View file

@ -0,0 +1,18 @@
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

94
HACKING Normal file
View file

@ -0,0 +1,94 @@
This file is licensed under the terms of the expat license, see the file EXPAT.
It is 4 spaces, no tabs, preferrably at 80 columns per line.
The preferred coding style is explained by example.
Source file example:
/*
Copyright
LICENSE TEXT
*/
#include "foo.h"
#include "bar.h"
#include <glib.h>
void
foobar (FooEnum bar, const gchar* foo)
{
gint n, i;
if (!foo)
return;
#ifdef BAR_STRICT
if (bar == FOO_N)
{
g_print ("illegal value for 'bar'.\n");
return;
}
#endif
/* this is an example */
switch (bar)
{
case FOO_FOO:
n = bar + 1;
break;
case FOO_BAR:
n = bar + 10;
break;
default:
n = 1;
}
for (i = 0; i < n; i++)
{
g_print ("%s\n", foo);
}
}
Header file example:
/*
Copyright
LICENSE TEXT
*/
#ifndef __FOO_H__
#define __FOO_H__ 1
#ifdef HAVE_BAR_H
#define BAR_STRICT
#endif
/* Types */
typedef enum
{
FOO_FOO,
FOO_BAR,
FOO_N
} FooEnum;
typedef struct
{
FooEnum foo_bar;
} FooStruct;
/* Declarations */
void
foo_bar (FooEnum bar,
const gchar* foo);
const gchar*
foo_foo (FooStruct foo_struct,
guint number,
gboolean flag);
#endif /* !__FOO_H__ */

56
INSTALL Normal file
View file

@ -0,0 +1,56 @@
This file is licensed under the terms of the expat license, see the file EXPAT.
+++ Installing Midori +++
Building and installing Midori is straightforward.
Make sure you have Python 2.4 or higher installed.
Change to the Midori folder on your hard disk in a terminal.
Run './waf configure'
Run './waf build'
You can now run Midori from the build folder like so
'./waf build --run'
This is a convenience that will load extensions as well as
localizations from the build folder.
You can install it with './waf install'
For further options run './waf --help'
+++ Debugging Midori +++
Run './waf configure -d full' from the Midori folder.
Run './waf build'
Midori is now built with debugging symbols.
Make sure you have installed 'gdb', the GNU Debugger.
Run Midori as 'gdb _build_/default/midori/midori'.
Try to reproduce a crash that you experienced earlier,
this time Midori will freeze at the point of the crash.
Switch to your terminal, type bt ('backtrace') and hit Return.
What you obtained now is a backtrace that should include
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'
If you are interested in HTTP communication, try this:
'MIDORI_SOUP_DEBUG=2 _build_/default/midori/midori'
Where '2' can be a level between 0 and 3.
For further information a tutorial for gdb and
reading up on how you can install debugging
symbols for libraries used by Midori are recommended.

26
README Normal file
View file

@ -0,0 +1,26 @@
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.
* Tabs, windows and session management.
* Flexibly configurable Web Search.
* User scripts and user styles support.
* Straightforward bookmark management.
* Customizable and extensible interface.
* Extensions written in C.
Requirements: GTK+ 2.10, WebkitGTK+ 1.1.1, libXML2, libsoup 2.25.2
Optional: Unique 0.9, libidn, sqlite 3.0, docutils
For installation instructions read INSTALL.
Please report comments, suggestions and bugs to:
http://www.twotoasts.de/bugs
And join the IRC channel #midori on irc.freenode.net
Check for new versions at:
http://www.twotoasts.de

43
TODO Normal file
View file

@ -0,0 +1,43 @@
This file is licensed under the terms of the expat license, see the file EXPAT.
TODO:
. Use an update timeout in KatzePropertyProxy instead of only focus-out
. Show a loading mouse pointer
. Scroll tabs w/o switching tabs
. Import and export of the bookmarks file, or using one from a specific path
. Custom context menu actions, like in Thunar or Epiphany
. Custom tab names
. Analogus to blocked popups, blocked scripts moving layers on load (extension)
. Per-site blocking of individual elements on a page
. Statusbar icon 'cookies blocked', icon 'popups blocked'
. Per-site settings accessible via statusbar icons, ie. cookies, popups, plugins
. CookieSafe like, a list of cookies, with type, block, allow
. Automatic update checks (browser, extensions)?
. Auto-group tabs by opener, with colors?
. Mark (dogear) a selection so that it isn't cleared implicitly, multiply on one page
. Have an internal uri scheme, eg. 'res:', to reference eg. themed icons
. 'about:' uris: about, blank, cache, config, plugins
. Panel of open tabs (with tree-structure), optional thumbnail-view
. Spell check support
. Check specific bookmarks for updates automatically (extension)
. Mark "new" as well as "actually modified" tabs specially (even over sessions)
. SearchEngine: "Show in context menu"
. Use libnotify for events, e.g. download finished
. Save screenshot of a document?
. Right-click a textbox in a search form and choose 'add to websearch'
. Honor design principle "no warnings but undo of backups"?
. Support widgets 1.0 spec in tool windows and standalone?
. Blank page: several custom links, displayed as thumbnails, like Opera?
. Handle downloads, optionally in a downloadbar
. Protected tabs prompt when attempting to close them
. Provide a 'sleep mode' after a crash where open documents are loaded manually
. Option to run plugins or scripts only on demand, like NoScript, per-site
. Optional http redirection manually or on timeout
. Style: none, compatible (b/w), default, [styles], "media", ["media" styles], ...
. Mouse pointer coordinates in the status bar (extension)
. Draw rectangle with the mouse, x/y/x2/y2 in the statusbar (extension)
. Formfill (like Opera's magic wand)
. Private browsing mode (no browsing, download or search history)
. Shared bookmarks and config
. Custom-mode, e.g. hide menubar and use help icon to have a help viewer
. Prevent dead tabs: download, aborted page

41
TRANSLATE Normal file
View file

@ -0,0 +1,41 @@
This file is licensed under the terms of the expat license, see the file EXPAT.
+++ Translating Midori +++
If you want to translate Midori, here are a few helpful tips.
To update the localization template:
./waf build --update-po
If you want to add a new language 'aa', create it like this:
cd po
msginit -l aa_CC -o aa.po -i midori.pot
sed -i 's/PACKAGE/midori/g' aa.po
Make sure you add your language to the file po/LINGUAS.
Just open the file with a text editor and add your code.
To check your language 'aa' for errors, do this:
msgfmt -c --check-accelerators=_ aa.po
To test your changes, run Midori like so:
./waf build --run
This is a convenience command that will setup localization in
the build folder so you don't need to install translations.
To run Midori in a particular language, run it like this:
LANG=fr_FR.utf8 ./waf build --run
As a general rule, your localization should be based off of the
current git repository or the latest midori.pot in git.
Some strings have comments, starting with 'i18n', which are meant
to describe the role of a string to translators.
Please don't hesitate to ask for additional descriptive comments
for any unclear strings that you are uncertain about.

153
configure vendored Executable file
View file

@ -0,0 +1,153 @@
#! /bin/sh
# waf configure wrapper
# Fancy colors used to beautify the output a bit.
#
if [ "$NOCOLOR" ] ; then
NORMAL=""
BOLD=""
RED=""
YELLOW=""
GREEN=""
else
NORMAL="\033[0m"
BOLD="\033[1m"
RED="\033[91m"
YELLOW="\033[01;93m"
GREEN="\033[92m"
fi
EXIT_SUCCESS=0
EXIT_FAILURE=1
EXIT_ERROR=2
EXIT_BUG=10
CUR_DIR=$PWD
#possible relative path
WORKINGDIR=`dirname $0`
cd $WORKINGDIR
#abs path
WORKINGDIR=`pwd`
cd $CUR_DIR
# Checks for Python interpreter. Honours $PYTHON if set. Stores path to
# interpreter in $PYTHON.
#
checkPython()
{
if [ -z "$PYTHON" ] ; then
PYTHON=`which python 2>/dev/null`
fi
printf "Checking for Python\t\t\t: "
if [ ! -x "$PYTHON" ] ; then
printf $RED"not found!"$NORMAL"\n"
echo "Please make sure that the Python interpreter is available in your PATH"
echo "or invoke configure using the PYTHON flag, e.g."
echo "$ PYTHON=/usr/local/bin/python configure"
exit $EXIT_FAILURE
fi
printf $GREEN"$PYTHON"$NORMAL"\n"
}
# Checks for WAF. Honours $WAF if set. Stores path to 'waf' in $WAF.
# Requires that $PYTHON is set.
#
checkWAF()
{
printf "Checking for WAF\t\t\t: "
#installed miniwaf in sourcedir
if [ -z "$WAF" ] ; then
if [ -f "${WORKINGDIR}/waf" ] ; then
WAF="${WORKINGDIR}/waf"
if [ ! -x "$WAF" ] ; then
chmod +x $WAF
fi
fi
fi
if [ -z "$WAF" ] ; then
if [ -f "${WORKINGDIR}/waf-light" ] ; then
${WORKINGDIR}/waf-light --make-waf
WAF="${WORKINGDIR}/waf"
fi
fi
#global installed waf with waf->waf.py link
if [ -z "$WAF" ] ; then
WAF=`which waf 2>/dev/null`
fi
# neither waf nor miniwaf could be found
if [ ! -x "$WAF" ] ; then
printf $RED"not found"$NORMAL"\n"
echo "Go to http://code.google.com/p/waf/"
echo "and download a waf version"
exit $EXIT_FAILURE
else
printf $GREEN"$WAF"$NORMAL"\n"
fi
}
# Generates a Makefile. Requires that $WAF is set.
#
generateMakefile()
{
cat > Makefile << EOF
#!/usr/bin/make -f
# Waf Makefile wrapper
WAF_HOME=$CUR_DIR
all:
@$WAF build
all-debug:
@$WAF -v build
all-progress:
@$WAF -p build
install:
@if test -n "\$(DESTDIR)"; then \\
$WAF install --destdir="\$(DESTDIR)"; \\
else \\
$WAF install; \\
fi;
.PHONY: install
uninstall:
@if test -n "\$(DESTDIR)"; then \\
$WAF uninstall --destdir="\$(DESTDIR)"; \\
else \\
$WAF uninstall; \\
fi;
clean:
@$WAF clean
distclean:
@$WAF distclean
@-rm -rf _build_
@-rm -f Makefile
check:
@$WAF check
dist:
@$WAF dist
EOF
}
checkPython
checkWAF
echo "calling waf configure with parameters"
$WAF configure $* || exit $EXIT_ERROR
if [ -f "Makefile" ] ; then
echo ""
else
generateMakefile
fi
exit $EXIT_SUCCESS

View file

@ -0,0 +1,3 @@
[D-BUS Service]
Name=com.nokia.midori
Exec=/usr/bin/midori

150
data/logo-shade.svg Normal file
View file

@ -0,0 +1,150 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="307.65372"
height="350"
id="svg2418"
sodipodi:version="0.32"
inkscape:version="0.46"
version="1.0"
inkscape:export-filename="/home/user/logo-shade.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90"
sodipodi:docname="logo-shade.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape">
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
gridtolerance="10000"
guidetolerance="10"
objecttolerance="10"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.03"
inkscape:cx="74.949357"
inkscape:cy="143.09941"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1253"
inkscape:window-height="682"
inkscape:window-x="0"
inkscape:window-y="22" />
<defs
id="defs2420">
<linearGradient
id="linearGradient3412">
<stop
id="stop3414"
offset="0"
style="stop-color:#ffffff;stop-opacity:0.59836066;" />
<stop
id="stop3416"
offset="1"
style="stop-color:#97f839;stop-opacity:0;" />
</linearGradient>
<linearGradient
id="linearGradient3458">
<stop
id="stop3460"
offset="0"
style="stop-color:#88fe38;stop-opacity:1;" />
<stop
id="stop3462"
offset="1"
style="stop-color:#ffffff;stop-opacity:0;" />
</linearGradient>
<inkscape:perspective
id="perspective2426"
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
inkscape:vp_z="744.09448 : 526.18109 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 526.18109 : 1"
sodipodi:type="inkscape:persp3d" />
<linearGradient
id="linearGradient3458-648">
<stop
id="stop2423"
offset="0"
style="stop-color:#bababa;stop-opacity:1;" />
<stop
id="stop2425"
offset="1"
style="stop-color:#ffffff;stop-opacity:0;" />
</linearGradient>
<linearGradient
id="linearGradient3412-967">
<stop
id="stop2429"
offset="0"
style="stop-color:#ffffff;stop-opacity:0.59836066;" />
<stop
id="stop2431"
offset="1"
style="stop-color:#bababa;stop-opacity:0;" />
</linearGradient>
</defs>
<metadata
id="metadata2423">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:creator>
<cc:Agent>
<dc:title>Nancy Runge &lt;nancy@twotoasts.de&gt;</dc:title>
</cc:Agent>
</dc:creator>
<cc:license
rdf:resource="http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
transform="translate(-280.66056,-644.09745)"
id="layer1"
inkscape:groupmode="layer"
inkscape:label="Layer 1">
<g
id="g2546"
style="fill:#ffffff;fill-opacity:1;stroke:#bcbcbc;stroke-opacity:1"
transform="matrix(2.7318355,0,0,2.7318355,-731.07518,-1421.3016)">
<path
sodipodi:nodetypes="ccsscccsc"
id="path3598"
d="M 479.0149,757.44485 C 463.33929,760.3524 390.05715,768.6009 373.75783,823.05659 C 368.99751,841.48441 371.67629,866.55457 392.88608,865.62945 C 394.38911,865.56465 394.54399,866.0597 395.07871,867.32475 C 403.8111,887.98406 426.11314,884.657 430.13518,876.12801 C 430.41248,875.53998 429.75994,876.1331 430.13518,876.12801 C 452.01909,891.1113 463.94687,870.37434 470.8404,851.89287 C 479.26032,835.85799 484.40756,769.09622 479.90163,773.41411 C 403.13312,846.97906 403.28006,782.18757 479.0149,757.44485"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#bcbcbc;stroke-width:2.79349113000000004;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
id="path3606"
d="M 394.6271,866.42646 C 389.11843,841.31269 395.51037,833.40754 398.10369,830.14819"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#bcbcbc;stroke-width:2.79349113000000004;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
sodipodi:nodetypes="cc" />
<path
id="path3608"
d="M 430.04511,875.57142 C 422.884,860.41673 424.07276,847.90995 429.16085,838.58891"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#bcbcbc;stroke-width:2.79349113000000004;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
sodipodi:nodetypes="cc" />
</g>
<g
id="g2551"
style="fill:#e8e8e8;fill-opacity:1;stroke:none"
transform="matrix(2.7318355,0,0,2.7318355,-731.59243,-1420.9344)">
<path
sodipodi:nodetypes="cccccccccccc"
id="path2553"
d="M 447.08573,768.31725 C 436.04919,774.1595 397.92257,781.58705 381.33359,820.27881 C 377.02863,833.88105 375.31278,851.44676 387.44516,857.54862 C 385.16801,848.06163 387.57514,834.11288 393.43272,827.57808 C 397.5473,821.96506 405.70797,826.00823 403.09775,831.29165 C 401.29067,836.46522 394.76631,843.8643 399.87669,863.28435 C 404.09154,874.85534 415.25599,879.58634 422.43347,873.92723 C 414.92666,858.12585 420.32228,825.17457 433.92305,832.69366 C 440.70334,836.82119 424.80942,848.38632 435.43821,869.81488 C 448.73626,880.75776 460.15899,863.55615 464.02222,850.63024 C 472.18961,832.82769 477.16809,790.8233 475.1786,786.29359 C 410.97397,845.50147 395.61545,794.24336 447.07098,768.23969"
style="fill:#e8e8e8;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.79349113;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.3 KiB

14
data/midori.desktop.in Normal file
View file

@ -0,0 +1,14 @@
[Desktop Entry]
Version=1.0
Type=Application
_Name=Midori
_GenericName=Web Browser
_Comment=Lightweight web browser
Categories=GTK;Network;WebBrowser;
MimeType=text/html;text/xml;application/xhtml+xml;application/xml;
Exec=midori %u
Icon=midori
Terminal=false
StartupNotify=true
X-Osso-Type=application/x-executable
X-Osso-Service=midori

21
data/search Normal file
View file

@ -0,0 +1,21 @@
[Google]
name=Google
text=Web Search
uri=http://www.google.com/search?q=%s
icon=
token=g
[Wikipedia]
name=Wikipedia
text=The free encyclopedia
uri=http://en.wikipedia.org/wiki/%s
icon=
token=wp
[TheFreeDictionary]
name=The Free Dictionary
text=Dictionary, Encyclopedia and Thesaurus
uri=http://www.thefreedictionary.com/%s
icon=
token=fd

34
docs/api/wscript_build Normal file
View file

@ -0,0 +1,34 @@
#! /usr/bin/env python
# WAF build script for midori
# This file is licensed under the terms of the expat license, see the file EXPAT.
import pproc as subprocess
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')
subprocess.call (['gtkdoc-scan', '--module=' + module,
'--source-dir=' + module, '--output-dir=_build_/docs/api/' + module,
'--rebuild-sections', '--rebuild-types'])
os.chdir ('_build_/docs/api/' + module)
subprocess.call (['gtkdoc-mktmpl', '--module=' + module,
'--output-dir=.' + module])
subprocess.call (['gtkdoc-mkdb', '--module=' + module,
'--source-dir=.', '--output-dir=xml',
'--source-suffixes=c,h', '--output-format=xml',
'--default-includes=%s/%s.h' % (module, module),
'--sgml-mode', '--main-sgml-file=%s.sgml' % module])
if not os.access ('html', os.F_OK):
Utils.check_dir ('html')
os.chdir ('html')
subprocess.call (['gtkdoc-mkhtml', module, '../%s.sgml' % module])
Utils.pprint ('YELLOW', "Created documentation for %s." % module)
os.chdir ('../../../../..')
except Exception, msg:
print msg
Utils.pprint ('RED', "Failed to create documentation for %s." % module)

114
docs/user/midori.css Normal file
View file

@ -0,0 +1,114 @@
/*
:Author: Christian Dywan
:Contact: christian@twotoasts.de
:Copyright: This file is licensed under the terms of the expat license, see the file EXPAT.
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%;
}
a {
color: #013100;
}
a:visited {
color: #7E558E;
}
a:hover {
text-decoration: none;
}
h1, h2, h3 {
font-family: sans-serif;
color: #002a00;
}
h1 {
border-top: 1px dotted;
margin-top: 2em;
}
h1.title {
text-align: left }
h2 {
margin-top: 30px;
}
h2.subtitle {
text-align: left }
h3 {
padding-left: 3px;
}
blockquote, pre {
border: 1px solid;
padding: 0.4em;
}
blockquote {
font-family: sans-serif;
background-color: #DBEDD5;
border: 1px dotted;
border-left: 4px solid;
border-color: #9FD98C;
}
pre {
background-color: #deefd4;
border: 1px dotted;
border-left: 4px solid;
border-color: #9acb7d;
}
tt, pre, code {
color: #002a00;
}
table {
border: 1px solid #9acb7f;
}
th {
border: none;
background-color: #9acb7d;
}
tr:nth-child(even) {
background-color: #d3eac6;
}
td {
border: none;
}
.docinfo-name {
color: #002a00;
}
p.admonition-title {
color: #990000;
font-weight: bold;
}
div.note {
margin: 1em 3em;
padding: 0em;
}
dt {
font-style: italic;
}
}

254
docs/user/midori.txt Normal file
View file

@ -0,0 +1,254 @@
.. |(version)| replace:: 0.1.6
'''''''
Midori
'''''''
-----------------------------------------
A lightweight, portable GTK+ web browser
-----------------------------------------
:Authors: Christian Dywan
:Date: $Date: 2009-04-14 18:00:35 +0100 (Tue, 14 Apr 2009) $
:Version: |(version)|
Copyright © 2008-2009
This documentation is distributed under the terms of the
`GNU Lesser General Public License`_; 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.
.. contents::
Introduction
''''''''''''
What is Midori
--------------
Midori is a lightweight and portable web browser based on Gtk+. The
interface is designed to be intuitive yet powerful.
* Full integration with GTK+2.
* Fast rendering with WebKit.
* Tabs, windows and session management.
* Flexibly configurable Web Search.
* User scripts and user styles support.
* Straightforward bookmark management.
* Customizable and extensible interface.
* Extensions written in C.
Running Midori
--------------
* If you are using a graphical desktop environment you will usually find
Midori in the menu under Network.
* You can also run Midori from a console or a Run dialog.
See also `Command line usage`.
$ midori
A browser window appears where you can start navigating the web right away.
The main interface
--------------------------
The main browser window consists of a few basic elements:
* The menubar. It's pretty much standardized and gives you access to
allmost all features, many of the items have a keyboard shortcut by default.
See also `Keyboard shortcuts`_.
* The navigationbar. It lets you open tabs, go back and forward, enter
addresses, search the web and reopen closed tabs.
See also `The navigationbar`.
* The sidepanel. It takes a pretty central role in the functionality it provides,
yet it can be hidden and resized to not distract you.
See also `The sidepanel`.
* The statusbar. It displays informational text when hovering something
with a pointer. That's it.
Taking a closer look
''''''''''''''''''''
Command line usage
------------------
Running Midori normally works as follows:
* $ midori
Just run a new instance of Midori. If an instance of Midori is already
running a new window in that instance will be opened.
* $ midori [URIs]
You can supply any number of URIs to open as arguments. If you have a
saved session or a running instance they will be added to the last
active window.
* $ midori [URI1]|[URI2]|...
You can separate URIS by a pipe (|) as well. They are handled as if you
provided all URIs as separate arguments.
* $ midori --run [JAVASCRIPT]
If you pass the filename of a javascript Midori will attempt to run
the contents of the file as javascript code.
Note that support for opening tabs in an existing instance depends on
your build and may not be available on some platforms.
The following arguments are supported if you call Midori from a command line.
+-------+--------------------+------------------------------------------------+
| Short | Long option | Function |
+=======+====================+================================================+
| -a | --app | Run ADDRESS as a web application |
+-------+--------------------+------------------------------------------------+
| -c | --config | Use FOLDER as configuration folder |
+-------+--------------------+------------------------------------------------+
| -r | --run | Run the specified filename as javascript |
+-------+--------------------+------------------------------------------------+
| -V | --version | Show version information and exit. |
+-------+--------------------+------------------------------------------------+
Configuration files
-------------------
The configuration files in Midori that save related states are by default
stored in the folder ~/.config/midori in the home directory. It is possible
to use a different folder by specifying '--config' on the command line.
The files stored in the primary configuration folder are the following:
+----------------+------------------------------------------------------------+
| Filename | Contents |
+================+============================================================+
| accels | Keyboard shortcuts, GtkAccelMap resource |
+----------------+------------------------------------------------------------+
| bookmarks.xbel | Bookmarks, XBEL |
+----------------+------------------------------------------------------------+
| config | Preferences, text key file |
+----------------+------------------------------------------------------------+
| cookies.txt | Cookies, Mozilla text cookies |
+----------------+------------------------------------------------------------+
| history.db | History, sqlite3 |
+----------------+------------------------------------------------------------+
| running | A file created to track whether Midori quit cleanly |
+----------------+------------------------------------------------------------+
| session.xbel | The current or last session, ie. open tabs, |
+----------------+------------------------------------------------------------+
| tabtrash.xbel | The 10 last closed tabs |
+----------------+------------------------------------------------------------+
Note that generally manual modifications to these files aren't recommended. As
an exception, while Midori is *not* running, it is possible to edit or
replace the 'bookmarks.xbel' as long as it is valid XBEL/ XML.
Currently while Midori is running it will happily overwrite files as needed and
never read back any changes.
Incidentally Midori will recognize readonly files and not write modifications
to readonly files back to disk. This can be useful for kiosk systems where
particular changes shouldn't be saved.
Keyboard shortcuts
------------------
...
The navigationbar
-----------------
The navigationbar is the primary toolbar containing notably back and forward
buttons, the location entry and a search entry. Except for the location entry
any item can be removed and others can be added by right-clicking the toolbar
and using the Add and Remove menu items.
The sidepanel
-------------
...
Extensions
----------
...
Frequently asked questions
''''''''''''''''''''''''''
How do you pronounce Midori and what does it mean anyway?
---------------------------------------------------------
Pronounce it "midoɺi", with a Bavarian/ Japanese "r" or "Mee-Doh-Ree"
in English or read it Italian. The name comes from the Japanese word
緑 (みどり) for the colour "green".
What does the logo mean?
------------------------
The paw of a green cat. Obviously. Also it resembles the letter "M"
in "Midori". The curving is supposed to emphasize speed.
On which platforms does Midori run currently?
---------------------------------------------
Midori is basically very portable and should run on all platforms that
its dependencies support.
Under which license is Midori distributed?
------------------------------------------
Midori, documentation and all delivered artwork are licensed under the LGPL2.
GNU Lesser General Public License
'''''''''''''''''''''''''''''''''
::
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
FIXME: Provide full license text

151
extensions/colorful-tabs.c Normal file
View file

@ -0,0 +1,151 @@
/*
Copyright (C) 2009 Christian Dywan <christian@twotoasts.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#include <midori/midori.h>
static void
colorful_tabs_button_toggled_cb (GtkWidget* button,
MidoriExtension* extension)
{
midori_extension_set_boolean (extension, "tint",
!midori_extension_get_boolean (extension, "tint"));
/* FIXME: Update all tab colors */
}
static void
colorful_tabs_view_notify_uri_cb (MidoriView* view,
GParamSpec* pspec,
MidoriExtension* extension)
{
GtkWidget* label;
SoupURI* uri;
gchar* hash;
gchar* colorstr;
GdkColor color;
label = midori_view_get_proxy_tab_label (view);
if (!midori_extension_get_boolean (extension, "tint"))
{
gtk_widget_modify_bg (label, GTK_STATE_NORMAL, NULL);
gtk_widget_modify_bg (label, GTK_STATE_ACTIVE, NULL);
return;
}
/* Find a color that is unique to an address. We merely compute
a hash value, pick the first 6 + 1 characters and turn the
first into a hash sign, ie. #8b424b. In case a color is too
dark, we lighten it up a litte. Finally we make the event box
visible and modify its background. */
if ((uri = soup_uri_new (midori_view_get_display_uri (view))) && uri->host)
{
hash = g_compute_checksum_for_string (G_CHECKSUM_MD5, uri->host, -1);
soup_uri_free (uri);
colorstr = g_strndup (hash, 6 + 1);
g_free (hash);
colorstr[0] = '#';
gdk_color_parse (colorstr, &color);
if (color.red < 35000)
color.red += 25000 + (color.blue + 1) / 2;
if (color.green < 35000)
color.green += 25000 + (color.red + 1) / 2;
if (color.blue < 35000)
color.blue += 25000 + (color.green + 1) / 2;
gtk_event_box_set_visible_window (GTK_EVENT_BOX (label), TRUE);
gtk_widget_modify_bg (label, GTK_STATE_NORMAL, &color);
gtk_widget_modify_bg (label, GTK_STATE_ACTIVE, &color);
}
else
{
gtk_widget_modify_bg (label, GTK_STATE_NORMAL, NULL);
gtk_widget_modify_bg (label, GTK_STATE_ACTIVE, NULL);
}
}
static void
colorful_tabs_browser_add_tab_cb (MidoriBrowser* browser,
MidoriView* view,
MidoriExtension* extension)
{
g_signal_connect (view, "notify::uri",
G_CALLBACK (colorful_tabs_view_notify_uri_cb), extension);
}
static void
colorful_tabs_deactivate_cb (MidoriExtension* extension,
GtkWidget* bbox)
{
gtk_widget_destroy (bbox);
g_signal_handlers_disconnect_by_func (
extension, colorful_tabs_deactivate_cb, bbox);
/* FIXME: Disconnect signals */
/* FIXME: Reset all tab colors */
}
static void
colorful_tabs_app_add_browser_cb (MidoriApp* app,
MidoriBrowser* browser,
MidoriExtension* extension)
{
GtkWidget* statusbar;
GtkWidget* bbox;
GtkWidget* button;
statusbar = katze_object_get_object (browser, "statusbar");
bbox = gtk_hbox_new (FALSE, 0);
button = gtk_check_button_new_with_label (_("Tint tabs distinctly"));
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
midori_extension_get_boolean (extension, "tint"));
gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 2);
gtk_widget_show (button);
gtk_widget_show (bbox);
gtk_box_pack_start (GTK_BOX (statusbar), bbox, FALSE, FALSE, 3);
g_signal_connect (button, "toggled",
G_CALLBACK (colorful_tabs_button_toggled_cb), extension);
g_signal_connect (browser, "add-tab",
G_CALLBACK (colorful_tabs_browser_add_tab_cb), extension);
g_signal_connect (extension, "deactivate",
G_CALLBACK (colorful_tabs_deactivate_cb), bbox);
}
static void
colorful_tabs_activate_cb (MidoriExtension* extension,
MidoriApp* app)
{
KatzeArray* browsers;
MidoriBrowser* browser;
guint i;
browsers = katze_object_get_object (app, "browsers");
i = 0;
while ((browser = katze_array_get_nth_item (browsers, i++)))
colorful_tabs_app_add_browser_cb (app, browser, extension);
g_signal_connect (app, "add-browser",
G_CALLBACK (colorful_tabs_app_add_browser_cb), extension);
}
MidoriExtension*
extension_init (void)
{
MidoriExtension* extension = g_object_new (MIDORI_TYPE_EXTENSION,
"name", _("Colorful Tabs"),
"description", _("Tint each tab distinctly"),
"version", "0.1",
"authors", "Christian Dywan <christian@twotoasts.de>",
NULL);
midori_extension_install_boolean (extension, "tint", FALSE);
g_signal_connect (extension, "activate",
G_CALLBACK (colorful_tabs_activate_cb), NULL);
return extension;
}

970
extensions/cookie-manager.c Normal file
View file

@ -0,0 +1,970 @@
/*
Copyright (C) 2009 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#include "config.h"
#include <time.h>
#include <midori/midori.h>
#include <webkit/webkit.h>
#include <midori/gtkiconentry.h>
#define CM_DEBUG 0
#define STOCK_COOKIE_MANAGER "cookie-manager"
#define CM_EMPTY_LABEL_TEXT "\n\n\n\n\n\n"
enum
{
COL_NAME,
COL_COOKIE,
COL_VISIBLE,
N_COLUMNS
};
typedef struct _CMData
{
MidoriApp *app;
MidoriBrowser *browser;
MidoriExtension *extension;
GtkWidget *panel_page;
GtkWidget *desc_label;
GtkWidget *delete_button;
GtkWidget *delete_popup_button;
GtkWidget *delete_all_button;
GtkWidget *expand_buttons[4];
GtkWidget *treeview;
GtkTreeStore *store;
GtkTreeModel *filter;
GtkWidget *filter_entry;
GtkWidget *popup_menu;
SoupCookieJar *jar;
GSList *cookies;
guint timer_id;
gint ignore_changed_count;
} CMData;
static void cm_app_add_browser_cb(MidoriApp *app, MidoriBrowser *browser, MidoriExtension *ext);
static void cm_filter_tree(CMData *cmdata, const gchar *filter_text);
static void cm_deactivate_cb(MidoriExtension *extension, CMData *cmdata);
static void cm_jar_changed_cb(SoupCookieJar *jar, SoupCookie *old, SoupCookie *new, CMData *cmdata);
#if CM_DEBUG
static gchar *cookie_to_string(SoupCookie *c)
{
if (c != NULL)
{
static gchar s[256]; /* this might be too small but for debugging it should be ok */
g_snprintf(s, sizeof(s), "%s\t%s = %s", c->domain, c->name, c->value);
return s;
}
return NULL;
}
#endif
static void cm_free_cookie_list(CMData *cmdata)
{
if (cmdata->cookies != NULL)
{
GSList *l;
for (l = cmdata->cookies; l != NULL; l = g_slist_next(l))
soup_cookie_free(l->data);
g_slist_free(cmdata->cookies);
cmdata->cookies = NULL;
}
}
static void cm_browser_close_cb(GtkObject *browser, CMData *cmdata)
{
g_signal_handlers_disconnect_by_func(cmdata->extension, cm_deactivate_cb, cmdata);
g_signal_handlers_disconnect_by_func(cmdata->browser, cm_browser_close_cb, cmdata);
g_signal_handlers_disconnect_by_func(cmdata->jar, cm_jar_changed_cb, cmdata);
cm_free_cookie_list(cmdata);
/* the panel_page widget gets destroyed automatically when a browser is closed but not
* when the extension is deactivated */
if (cmdata->panel_page != NULL && GTK_IS_WIDGET(cmdata->panel_page))
gtk_widget_destroy(cmdata->panel_page);
gtk_widget_destroy(cmdata->popup_menu);
g_free(cmdata);
}
static void cm_deactivate_cb(MidoriExtension *extension, CMData *cmdata)
{
g_signal_handlers_disconnect_by_func(cmdata->app, cm_app_add_browser_cb, extension);
cm_browser_close_cb(NULL, cmdata);
}
static void cm_refresh_store(CMData *cmdata)
{
GSList *l;
GHashTable *parents;
GtkTreeIter iter;
GtkTreeIter *parent_iter;
SoupCookie *cookie;
const gchar *filter_text;
g_object_ref(cmdata->filter);
gtk_tree_view_set_model(GTK_TREE_VIEW(cmdata->treeview), NULL);
gtk_tree_store_clear(cmdata->store);
/* free the old list */
cm_free_cookie_list(cmdata);
cmdata->cookies = soup_cookie_jar_all_cookies(cmdata->jar);
/* Hashtable holds domain names as keys, the corresponding tree iters as values */
parents = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
for (l = cmdata->cookies; l != NULL; l = g_slist_next(l))
{
cookie = l->data;
/* look for the parent item for the current domain name and create it if it doesn't exist */
if ((parent_iter = (GtkTreeIter*) g_hash_table_lookup(parents, cookie->domain)) == NULL)
{
parent_iter = g_new0(GtkTreeIter, 1);
gtk_tree_store_append(cmdata->store, parent_iter, NULL);
gtk_tree_store_set(cmdata->store, parent_iter,
COL_NAME, cookie->domain,
COL_COOKIE, NULL,
COL_VISIBLE, TRUE,
-1);
g_hash_table_insert(parents, g_strdup(cookie->domain), parent_iter);
}
gtk_tree_store_append(cmdata->store, &iter, parent_iter);
gtk_tree_store_set(cmdata->store, &iter,
COL_NAME, cookie->name,
COL_COOKIE, cookie,
COL_VISIBLE, TRUE,
-1);
}
g_hash_table_destroy(parents);
gtk_tree_view_set_model(GTK_TREE_VIEW(cmdata->treeview), GTK_TREE_MODEL(cmdata->filter));
g_object_unref(cmdata->filter);
/* if a filter is set, apply it again */
filter_text = gtk_entry_get_text(GTK_ENTRY(cmdata->filter_entry));
if (*filter_text != '\0')
{
cm_filter_tree(cmdata, filter_text);
gtk_tree_view_expand_all(GTK_TREE_VIEW(cmdata->treeview));
}
}
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 */
strftime(date_fmt, sizeof(date_fmt), "%c", tm);
expires = date_fmt;
}
else
expires = _("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"
"<b>Secure</b>: %s\n<b>Expires</b>: %s"),
cookie->domain,
cookie->name,
cookie->value,
cookie->path,
cookie->secure ? _("Yes") : _("No"),
expires);
return text;
}
static void cm_set_button_sensitiveness(CMData *cmdata, gboolean set)
{
guint i, len;
gboolean expand_set = (gtk_tree_model_iter_n_children(cmdata->filter, NULL) > 0);
gtk_widget_set_sensitive(cmdata->delete_popup_button, set);
gtk_widget_set_sensitive(cmdata->delete_button, set);
gtk_widget_set_sensitive(cmdata->delete_all_button, expand_set);
len = G_N_ELEMENTS(cmdata->expand_buttons);
for (i = 0; i < len; i++)
{
gtk_widget_set_sensitive(cmdata->expand_buttons[i], expand_set);
}
}
static void cm_tree_selection_changed_cb(GtkTreeSelection *selection, CMData *cmdata)
{
GtkTreeIter iter, iter_store;
GtkTreeModel *model;
gchar *text;
gboolean valid = TRUE;
gboolean delete_possible = FALSE;
SoupCookie *cookie;
if (! gtk_tree_selection_get_selected(selection, &model, &iter))
valid = FALSE;
else
gtk_tree_model_filter_convert_iter_to_child_iter(GTK_TREE_MODEL_FILTER(model),
&iter_store, &iter);
if (valid && gtk_tree_store_iter_is_valid(cmdata->store, &iter_store))
{
delete_possible = TRUE;
gtk_tree_model_get(model, &iter, COL_COOKIE, &cookie, -1);
if (cookie != NULL)
{
text = cm_get_cookie_description_text(cookie);
gtk_label_set_markup(GTK_LABEL(cmdata->desc_label), text);
g_free(text);
}
else
valid = FALSE;
}
/* This is a bit hack'ish but we add some empty lines to get a minimum height of the
* label at the bottom without any font size calculation. */
if (! valid)
gtk_label_set_text(GTK_LABEL(cmdata->desc_label), CM_EMPTY_LABEL_TEXT);
cm_set_button_sensitiveness(cmdata, delete_possible);
}
static gboolean cm_tree_button_press_event_cb(GtkWidget *widget, GdkEventButton *ev, CMData *cmdata)
{
if (ev->type == GDK_2BUTTON_PRESS)
{
GtkTreeSelection *selection;
GtkTreeModel *model;
GtkTreeIter iter;
selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
if (gtk_tree_selection_get_selected(selection, &model, &iter))
{
/* double click on parent node expands/collapses it */
if (gtk_tree_model_iter_has_child(model, &iter))
{
GtkTreePath *path = gtk_tree_model_get_path(model, &iter);
if (gtk_tree_view_row_expanded(GTK_TREE_VIEW(widget), path))
gtk_tree_view_collapse_row(GTK_TREE_VIEW(widget), path);
else
gtk_tree_view_expand_row(GTK_TREE_VIEW(widget), path, FALSE);
gtk_tree_path_free(path);
return TRUE;
}
}
}
return FALSE;
}
static void cm_tree_show_popup_menu(GtkWidget *widget, GdkEventButton *event, CMData *cmdata)
{
gint button, event_time;
if (event != NULL)
{
button = event->button;
event_time = event->time;
}
else
{
button = 0;
event_time = gtk_get_current_event_time ();
}
gtk_menu_popup(GTK_MENU(cmdata->popup_menu), NULL, NULL, NULL, NULL, button, event_time);
}
static gboolean cm_tree_popup_menu_cb(GtkWidget *widget, CMData *cmdata)
{
cm_tree_show_popup_menu(widget, NULL, cmdata);
return TRUE;
}
static gboolean cm_tree_button_release_event_cb(GtkWidget *widget, GdkEventButton *ev, CMData *cmdata)
{
if (ev->button == 3)
{
cm_tree_show_popup_menu(widget, ev, cmdata);
return TRUE;
}
return FALSE;
}
static void cm_tree_popup_collapse_activate_cb(GtkCheckMenuItem *item, CMData *cmdata)
{
gtk_tree_view_collapse_all(GTK_TREE_VIEW(cmdata->treeview));
}
static void cm_tree_popup_expand_activate_cb(GtkCheckMenuItem *item, CMData *cmdata)
{
gtk_tree_view_expand_all(GTK_TREE_VIEW(cmdata->treeview));
}
static void cm_store_remove(CMData *cmdata, GtkTreeIter *iter_model)
{
GtkTreeIter iter_store;
gtk_tree_model_filter_convert_iter_to_child_iter(
GTK_TREE_MODEL_FILTER(cmdata->filter), &iter_store, iter_model);
gtk_tree_store_remove(cmdata->store, &iter_store);
}
static void cm_delete_cookie(GtkTreeModel *model, GtkTreeIter *child, CMData *cmdata)
{
SoupCookie *cookie;
gtk_tree_model_get(model, child, COL_COOKIE, &cookie, -1);
if (cookie != NULL)
{
cmdata->ignore_changed_count++;
soup_cookie_jar_delete_cookie(cmdata->jar, cookie);
/* the SoupCookie object is freed when the whole list gets updated */
}
}
static void cm_button_delete_clicked_cb(GtkToolButton *button, CMData *cmdata)
{
GtkTreeIter iter, iter_store, child;
GtkTreeModel *model;
GtkTreeSelection *selection;
selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(cmdata->treeview));
if (! gtk_tree_selection_get_selected(selection, &model, &iter))
return;
if (gtk_tree_model_iter_has_child(model, &iter))
{
GtkTreePath *path = gtk_tree_model_get_path(model, &iter);
while (gtk_tree_model_iter_children(model, &child, &iter))
{
cm_delete_cookie(model, &child, cmdata);
cm_store_remove(cmdata, &child);
/* we retrieve again the iter at path because it got invalid by the delete operation */
gtk_tree_model_get_iter(model, &iter, path);
}
gtk_tree_path_free(path);
/* remove/hide the parent */
gtk_tree_model_filter_convert_iter_to_child_iter(GTK_TREE_MODEL_FILTER(cmdata->filter),
&iter_store, &iter);
if (gtk_tree_model_iter_has_child(GTK_TREE_MODEL(cmdata->store), &iter_store))
gtk_tree_store_set(cmdata->store, &iter_store, COL_VISIBLE, FALSE, -1);
else
cm_store_remove(cmdata, &iter);
}
else
{
GtkTreePath *path_store, *path_model;
gtk_tree_model_filter_convert_iter_to_child_iter(GTK_TREE_MODEL_FILTER(cmdata->filter),
&iter_store, &iter);
path_store = gtk_tree_model_get_path(GTK_TREE_MODEL(cmdata->store), &iter_store);
path_model = gtk_tree_model_get_path(model, &iter);
cm_delete_cookie(model, &iter, cmdata);
gtk_tree_store_remove(cmdata->store, &iter_store);
/* check whether the parent still has children, otherwise delete it */
if (gtk_tree_path_up(path_store))
{
gtk_tree_model_get_iter(GTK_TREE_MODEL(cmdata->store), &iter_store, path_store);
if (! gtk_tree_model_iter_has_child(GTK_TREE_MODEL(cmdata->store), &iter_store))
/* remove the empty parent */
gtk_tree_store_remove(cmdata->store, &iter_store);
}
/* now for the filter model */
if (gtk_tree_path_up(path_model))
{
gtk_tree_model_get_iter(model, &iter, path_model);
if (! gtk_tree_model_iter_has_child(model, &iter))
{
gtk_tree_model_filter_convert_iter_to_child_iter(
GTK_TREE_MODEL_FILTER(cmdata->filter), &iter_store, &iter);
/* hide the empty parent */
gtk_tree_store_set(cmdata->store, &iter_store, COL_VISIBLE, FALSE, -1);
}
}
gtk_tree_path_free(path_store);
gtk_tree_path_free(path_model);
}
}
static void cm_delete_all_cookies_real(CMData *cmdata)
{
GtkTreeIter iter, iter_store, child;
GtkTreePath *path_first, *path;
GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(cmdata->treeview));
path_first = gtk_tree_path_new_first();
while (gtk_tree_model_get_iter(model, &iter, path_first))
{
path = gtk_tree_model_get_path(model, &iter);
while (gtk_tree_model_iter_children(model, &child, &iter))
{
cm_delete_cookie(model, &child, cmdata);
cm_store_remove(cmdata, &child);
/* we retrieve again the iter at path because it got invalid by the delete operation */
gtk_tree_model_get_iter(model, &iter, path);
}
gtk_tree_path_free(path);
/* remove/hide the parent */
gtk_tree_model_filter_convert_iter_to_child_iter(GTK_TREE_MODEL_FILTER(cmdata->filter),
&iter_store, &iter);
if (gtk_tree_model_iter_has_child(GTK_TREE_MODEL(cmdata->store), &iter_store))
gtk_tree_store_set(cmdata->store, &iter_store, COL_VISIBLE, FALSE, -1);
else
cm_store_remove(cmdata, &iter);
}
gtk_tree_path_free(path_first);
cm_set_button_sensitiveness(cmdata, FALSE);
}
static void cm_button_delete_all_clicked_cb(GtkToolButton *button, CMData *cmdata)
{
GtkWidget *dialog;
GtkWidget *toplevel = gtk_widget_get_toplevel(GTK_WIDGET(button));
const gchar *filter_text;
dialog = gtk_message_dialog_new(GTK_WINDOW(toplevel),
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_QUESTION,
GTK_BUTTONS_YES_NO,
_("Do you really want to delete all cookies?"));
gtk_window_set_title(GTK_WINDOW(dialog), _("Question"));
/* steal Midori's icon :) */
gtk_window_set_icon_name(GTK_WINDOW(dialog), gtk_window_get_icon_name(GTK_WINDOW(toplevel)));
filter_text = gtk_entry_get_text(GTK_ENTRY(cmdata->filter_entry));
if (*filter_text != '\0')
{
gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
_("Only the visible cookies are deleted which match the entered filter string."));
}
if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_YES)
cm_delete_all_cookies_real(cmdata);
gtk_widget_destroy(dialog);
}
static void cm_tree_drag_data_get_cb(GtkWidget *widget, GdkDragContext *drag_context,
GtkSelectionData *data, guint info, guint ltime, CMData *cmdata)
{
GtkTreeIter iter, iter_store;
GtkTreeSelection *selection;
GtkTreeModel *model;
selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(cmdata->treeview));
if (! gtk_tree_selection_get_selected(selection, &model, &iter))
return;
gtk_tree_model_filter_convert_iter_to_child_iter(
GTK_TREE_MODEL_FILTER(model), &iter_store, &iter);
if (gtk_tree_store_iter_is_valid(cmdata->store, &iter_store))
{
SoupCookie *cookie;
gchar *name, *text;
gtk_tree_model_get(model, &iter, COL_NAME, &name, COL_COOKIE, &cookie, -1);
if (cookie == NULL && name != NULL)
{
/* skip a leading dot */
text = (*name == '.') ? name + 1 : name;
gtk_selection_data_set_text(data, text, -1);
}
g_free(name);
}
}
#if GTK_CHECK_VERSION(2, 12, 0)
static gboolean cm_tree_query_tooltip(GtkWidget *widget, gint x, gint y, gboolean keyboard_mode,
GtkTooltip *tooltip, CMData *cmdata)
{
GtkTreeIter iter;
GtkTreeModel *model;
if (gtk_tree_view_get_tooltip_context(GTK_TREE_VIEW(widget), &x, &y,
keyboard_mode, &model, NULL, &iter))
{
gchar *tooltip_text;
SoupCookie *cookie;
gtk_tree_model_get(model, &iter, COL_COOKIE, &cookie, -1);
if (cookie == NULL) /* not an item */
return FALSE;
tooltip_text = cm_get_cookie_description_text(cookie);
gtk_tooltip_set_markup(tooltip, tooltip_text);
g_free(tooltip_text);
return TRUE;
}
return FALSE;
}
#endif
static gboolean cm_filter_match(const gchar *haystack, const gchar *needle)
{
gchar *haystack_lowered, *needle_lowered;
gboolean result;
/* empty strings always match */
if (haystack == NULL || needle == NULL || *needle == '\0')
return TRUE;
haystack_lowered = g_utf8_strdown(haystack, -1);
needle_lowered = g_utf8_strdown(needle, -1);
/* if one of both could not be converted into lower case, skip those */
if (haystack_lowered == NULL || needle_lowered == NULL)
return FALSE;
result = (strstr(haystack_lowered, needle_lowered) != NULL);
g_free(haystack_lowered);
g_free(needle_lowered);
return result;
}
static void cm_filter_tree(CMData *cmdata, const gchar *filter_text)
{
GtkTreeIter iter, child;
GtkTreeModel *model;
gboolean show_child, show_parent;
gboolean child_visible;
gint i, n;
gchar *name;
gchar *domain;
model = GTK_TREE_MODEL(cmdata->store);
if (! gtk_tree_model_get_iter_first(model, &iter))
return;
do
{
if (gtk_tree_model_iter_has_child(model, &iter))
{
child_visible = FALSE;
gtk_tree_model_get(model, &iter, COL_NAME, &domain, -1);
show_parent = cm_filter_match(domain, filter_text);
g_free(domain);
n = gtk_tree_model_iter_n_children(model, &iter);
for (i = 0; i < n; i++)
{
gtk_tree_model_iter_nth_child(model, &child, &iter, i);
gtk_tree_model_get(model, &child, COL_NAME, &name, -1);
show_child = show_parent || cm_filter_match(name, filter_text);
g_free(name);
if (show_child)
child_visible = TRUE;
gtk_tree_store_set(cmdata->store, &child, COL_VISIBLE, show_child, -1);
}
gtk_tree_store_set(cmdata->store, &iter, COL_VISIBLE, child_visible, -1);
}
}
while (gtk_tree_model_iter_next(model, &iter));
}
static void cm_filter_entry_changed_cb(GtkEditable *editable, CMData *cmdata)
{
const gchar *text = gtk_entry_get_text(GTK_ENTRY(editable));
cm_filter_tree(cmdata, text);
if (*text != '\0')
gtk_tree_view_expand_all(GTK_TREE_VIEW(cmdata->treeview));
else
gtk_tree_view_collapse_all(GTK_TREE_VIEW(cmdata->treeview));
}
static void cm_filter_entry_clear_icon_released_cb(GtkIconEntry *e, gint pos, gint btn, CMData *cmdata)
{
if (pos == GTK_ICON_ENTRY_SECONDARY)
gtk_entry_set_text(GTK_ENTRY(e), "");
}
static void cm_tree_prepare(CMData *cmdata)
{
GtkCellRenderer *renderer;
GtkTreeViewColumn *column;
GtkTreeSelection *sel;
GtkWidget *tree;
GtkWidget *item;
GtkWidget *menu;
cmdata->treeview = tree = gtk_tree_view_new();
cmdata->store = gtk_tree_store_new(N_COLUMNS, G_TYPE_STRING, SOUP_TYPE_COOKIE, G_TYPE_BOOLEAN);
renderer = gtk_cell_renderer_text_new();
column = gtk_tree_view_column_new_with_attributes(
_("Name"), renderer, "text", COL_NAME, NULL);
gtk_tree_view_column_set_sort_indicator(column, TRUE);
gtk_tree_view_column_set_sort_column_id(column, COL_NAME);
gtk_tree_view_column_set_resizable(GTK_TREE_VIEW_COLUMN(column), TRUE);
gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);
gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(tree), TRUE);
gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tree), FALSE);
gtk_tree_view_set_search_column(GTK_TREE_VIEW(tree), COL_NAME);
gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(cmdata->store), COL_NAME, GTK_SORT_ASCENDING);
/* selection handling */
sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree));
gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
/* setting filter and model */
cmdata->filter = gtk_tree_model_filter_new(GTK_TREE_MODEL(cmdata->store), NULL);
gtk_tree_model_filter_set_visible_column(GTK_TREE_MODEL_FILTER(cmdata->filter), COL_VISIBLE);
gtk_tree_view_set_model(GTK_TREE_VIEW(tree), GTK_TREE_MODEL(cmdata->filter));
g_object_unref(cmdata->store);
g_object_unref(cmdata->filter);
/* signals */
g_signal_connect(sel, "changed", G_CALLBACK(cm_tree_selection_changed_cb), cmdata);
g_signal_connect(tree, "button-press-event", G_CALLBACK(cm_tree_button_press_event_cb), cmdata);
g_signal_connect(tree, "button-release-event", G_CALLBACK(cm_tree_button_release_event_cb), cmdata);
g_signal_connect(tree, "popup-menu", G_CALLBACK(cm_tree_popup_menu_cb), cmdata);
/* tooltips */
#if GTK_CHECK_VERSION(2, 12, 0)
gtk_widget_set_has_tooltip(tree, TRUE);
g_signal_connect(tree, "query-tooltip", G_CALLBACK(cm_tree_query_tooltip), cmdata);
#endif
/* drag'n'drop */
gtk_tree_view_enable_model_drag_source(
GTK_TREE_VIEW(tree),
GDK_BUTTON1_MASK,
NULL,
0,
GDK_ACTION_COPY
);
gtk_drag_source_add_text_targets(tree);
/*gtk_drag_source_add_uri_targets(tree);*/
g_signal_connect(tree, "drag-data-get", G_CALLBACK(cm_tree_drag_data_get_cb), cmdata);
/* popup menu */
menu = gtk_menu_new();
item = gtk_image_menu_item_new_from_stock(GTK_STOCK_DELETE, NULL);
gtk_widget_show(item);
gtk_container_add(GTK_CONTAINER(menu), item);
g_signal_connect(item, "activate", G_CALLBACK(cm_button_delete_clicked_cb), cmdata);
cmdata->delete_popup_button = item;
item = gtk_separator_menu_item_new();
gtk_widget_show(item);
gtk_container_add(GTK_CONTAINER(menu), item);
item = gtk_image_menu_item_new_with_mnemonic(_("_Expand All"));
gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item),
gtk_image_new_from_stock(GTK_STOCK_ADD, GTK_ICON_SIZE_MENU));
gtk_widget_show(item);
gtk_container_add(GTK_CONTAINER(menu), item);
g_signal_connect(item, "activate", G_CALLBACK(cm_tree_popup_expand_activate_cb), cmdata);
cmdata->expand_buttons[2] = item;
item = gtk_image_menu_item_new_with_mnemonic(_("_Collapse All"));
gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item),
gtk_image_new_from_icon_name(GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU));
gtk_widget_show(item);
gtk_container_add(GTK_CONTAINER(menu), item);
g_signal_connect(item, "activate", G_CALLBACK(cm_tree_popup_collapse_activate_cb), cmdata);
cmdata->expand_buttons[3] = item;
cmdata->popup_menu = menu;
}
static gboolean cm_delayed_refresh(CMData *cmdata)
{
cm_refresh_store(cmdata);
cmdata->timer_id = 0;
return FALSE;
}
static void cm_jar_changed_cb(SoupCookieJar *jar, SoupCookie *old, SoupCookie *new, CMData *cmdata)
{
if (cmdata->ignore_changed_count > 0)
{
cmdata->ignore_changed_count--;
return;
}
/* We delay these events a little bit to avoid too many rebuilds of the tree.
* Some websites (like Flyspray bugtrackers sent a whole bunch of cookies at once. */
if (cmdata->timer_id == 0)
{
cmdata->timer_id = g_timeout_add_seconds(1, (GSourceFunc) cm_delayed_refresh, cmdata);
}
}
static void cm_app_add_browser_cb(MidoriApp *app, MidoriBrowser *browser, MidoriExtension *ext)
{
GtkWidget *panel;
GtkWidget *tree_swin;
GtkWidget *desc_swin;
GtkWidget *toolbar;
GtkWidget *paned;
GtkWidget *filter_hbox;
GtkWidget *filter_label;
GtkToolItem *toolitem;
SoupSession *session;
CMData *cmdata;
cmdata = g_new0(CMData, 1);
cmdata->app = app;
cmdata->extension = ext;
cmdata->browser = browser;
panel = katze_object_get_object(browser, "panel");
toolbar = gtk_toolbar_new();
gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_BOTH_HORIZ);
gtk_toolbar_set_icon_size(GTK_TOOLBAR(toolbar), GTK_ICON_SIZE_BUTTON);
gtk_widget_show(toolbar);
toolitem = gtk_tool_button_new_from_stock(GTK_STOCK_DELETE);
gtk_tool_item_set_is_important(toolitem, TRUE);
g_signal_connect(toolitem, "clicked", G_CALLBACK(cm_button_delete_clicked_cb), cmdata);
gtk_widget_show(GTK_WIDGET(toolitem));
gtk_widget_set_sensitive(GTK_WIDGET(toolitem), FALSE);
gtk_toolbar_insert(GTK_TOOLBAR(toolbar), toolitem, -1);
cmdata->delete_button = GTK_WIDGET(toolitem);
toolitem = gtk_tool_button_new_from_stock(GTK_STOCK_DELETE);
gtk_tool_button_set_label(GTK_TOOL_BUTTON(toolitem), _("Delete All"));
gtk_tool_item_set_tooltip_text(toolitem,
_("Deletes all shown cookies. "
"If a filter is set, only those cookies are deleted which match the filter."));
gtk_tool_item_set_is_important(toolitem, TRUE);
g_signal_connect(toolitem, "clicked", G_CALLBACK(cm_button_delete_all_clicked_cb), cmdata);
gtk_widget_show(GTK_WIDGET(toolitem));
gtk_toolbar_insert(GTK_TOOLBAR(toolbar), toolitem, -1);
cmdata->delete_all_button = GTK_WIDGET(toolitem);
toolitem = gtk_separator_tool_item_new();
gtk_separator_tool_item_set_draw(GTK_SEPARATOR_TOOL_ITEM(toolitem), FALSE);
gtk_tool_item_set_expand(toolitem, TRUE);
gtk_toolbar_insert(GTK_TOOLBAR(toolbar), toolitem, -1);
gtk_widget_show(GTK_WIDGET(toolitem));
toolitem = gtk_tool_button_new_from_stock(GTK_STOCK_ADD);
gtk_tool_item_set_tooltip_text(toolitem, _("Expand All"));
g_signal_connect(toolitem, "clicked", G_CALLBACK(cm_tree_popup_expand_activate_cb), cmdata);
gtk_widget_show(GTK_WIDGET(toolitem));
gtk_toolbar_insert(GTK_TOOLBAR(toolbar), toolitem, -1);
cmdata->expand_buttons[0] = GTK_WIDGET(toolitem);
toolitem = gtk_tool_button_new_from_stock(GTK_STOCK_REMOVE);
gtk_tool_item_set_tooltip_text(toolitem, _("Collapse All"));
g_signal_connect(toolitem, "clicked", G_CALLBACK(cm_tree_popup_collapse_activate_cb), cmdata);
gtk_widget_show(GTK_WIDGET(toolitem));
gtk_toolbar_insert(GTK_TOOLBAR(toolbar), toolitem, -1);
cmdata->expand_buttons[1] = GTK_WIDGET(toolitem);
cmdata->desc_label = gtk_label_new(CM_EMPTY_LABEL_TEXT);
gtk_label_set_selectable(GTK_LABEL(cmdata->desc_label), TRUE);
gtk_label_set_line_wrap(GTK_LABEL(cmdata->desc_label), TRUE);
gtk_label_set_line_wrap_mode(GTK_LABEL(cmdata->desc_label), PANGO_WRAP_CHAR);
gtk_misc_set_alignment(GTK_MISC(cmdata->desc_label), 0, 0);
gtk_misc_set_padding(GTK_MISC(cmdata->desc_label), 3, 3);
gtk_widget_show(cmdata->desc_label);
desc_swin = gtk_scrolled_window_new(NULL, NULL);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(desc_swin),
GTK_POLICY_AUTOMATIC, GTK_POLICY_NEVER);
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(desc_swin), GTK_SHADOW_NONE);
gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(desc_swin), cmdata->desc_label);
gtk_widget_show(desc_swin);
cm_tree_prepare(cmdata);
gtk_widget_show(cmdata->treeview);
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), cmdata->treeview);
gtk_widget_show(tree_swin);
filter_label = gtk_label_new(_("Filter:"));
gtk_widget_show(filter_label);
cmdata->filter_entry = gtk_icon_entry_new();
gtk_widget_set_tooltip_text(cmdata->filter_entry,
_("Enter a filter string to show only cookies whose name or domain "
"field match the entered filter"));
gtk_widget_show(cmdata->filter_entry);
gtk_icon_entry_set_icon_from_stock(GTK_ICON_ENTRY(cmdata->filter_entry),
GTK_ICON_ENTRY_SECONDARY, GTK_STOCK_CLEAR);
gtk_icon_entry_set_icon_highlight(GTK_ICON_ENTRY (cmdata->filter_entry),
GTK_ICON_ENTRY_SECONDARY, TRUE);
g_signal_connect(cmdata->filter_entry, "icon-release",
G_CALLBACK(cm_filter_entry_clear_icon_released_cb), NULL);
g_signal_connect(cmdata->filter_entry, "changed", G_CALLBACK(cm_filter_entry_changed_cb), cmdata);
g_signal_connect(cmdata->filter_entry, "activate", G_CALLBACK(cm_filter_entry_changed_cb), cmdata);
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), cmdata->filter_entry, TRUE, TRUE, 3);
gtk_widget_show(filter_hbox);
paned = gtk_vpaned_new();
gtk_paned_pack1(GTK_PANED(paned), tree_swin, TRUE, FALSE);
gtk_paned_pack2(GTK_PANED(paned), desc_swin, FALSE, FALSE);
gtk_widget_show(paned);
cmdata->panel_page = gtk_vbox_new(FALSE, 0);
gtk_box_pack_start(GTK_BOX(cmdata->panel_page), filter_hbox, FALSE, FALSE, 5);
gtk_box_pack_start(GTK_BOX(cmdata->panel_page), paned, TRUE, TRUE, 0);
gtk_widget_show(cmdata->panel_page);
/* setup soup */
session = webkit_get_default_session();
cmdata->jar = SOUP_COOKIE_JAR(soup_session_get_feature(session, soup_cookie_jar_get_type()));
g_signal_connect(cmdata->jar, "changed", G_CALLBACK(cm_jar_changed_cb), cmdata);
cm_refresh_store(cmdata);
midori_panel_append_widget(MIDORI_PANEL(panel), cmdata->panel_page,
STOCK_COOKIE_MANAGER, _("Cookie Manager"), toolbar);
g_signal_connect(ext, "deactivate", G_CALLBACK(cm_deactivate_cb), cmdata);
g_signal_connect(browser, "destroy", G_CALLBACK(cm_browser_close_cb), cmdata);
g_object_unref(panel);
}
static void cm_activate_cb(MidoriExtension *extension, MidoriApp *app, gpointer data)
{
KatzeArray* browsers;
MidoriBrowser* browser;
guint i;
browsers = katze_object_get_object(app, "browsers");
i = 0;
while ((browser = katze_array_get_nth_item(browsers, i++)))
cm_app_add_browser_cb(app, browser, extension);
g_object_unref(browsers);
g_signal_connect(app, "add-browser", G_CALLBACK(cm_app_add_browser_cb), extension);
}
MidoriExtension *extension_init(void)
{
MidoriExtension *extension;
GtkIconFactory *factory;
GtkIconSource *icon_source;
GtkIconSet *icon_set;
static GtkStockItem items[] =
{
{ STOCK_COOKIE_MANAGER, N_("_Cookie Manager"), 0, 0, NULL }
};
factory = gtk_icon_factory_new();
gtk_stock_add(items, G_N_ELEMENTS(items));
icon_set = gtk_icon_set_new();
icon_source = gtk_icon_source_new();
gtk_icon_source_set_icon_name(icon_source, GTK_STOCK_DIALOG_AUTHENTICATION);
gtk_icon_set_add_source(icon_set, icon_source);
gtk_icon_source_free(icon_source);
gtk_icon_factory_add(factory, STOCK_COOKIE_MANAGER, icon_set);
gtk_icon_set_unref(icon_set);
gtk_icon_factory_add_default(factory);
g_object_unref(factory);
extension = g_object_new(MIDORI_TYPE_EXTENSION,
"name", _("Cookie Manager"),
"description", _("List, view and delete cookies"),
"version", "0.1",
"authors", "Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>",
NULL);
g_signal_connect(extension, "activate", G_CALLBACK(cm_activate_cb), NULL);
return extension;
}

View file

@ -0,0 +1,229 @@
/*
Copyright (C) 2009 Matthias Kruk <mkruk@matthiaskruk.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#include <midori/midori.h>
#include "mouse-gestures.h"
#define MOUSE_GESTURES_VERSION "0.1"
#define DEVIANCE 20 // the deviance to determine if a line is straight or not
#define MINLENGTH 50 // the minimal length of a line to be treated as a gesture
// #define __MOUSE_GESTURES_DEBUG__ // uncomment for debugging purposes
MouseGesture *gesture;
void mouse_gesture_clear(MouseGesture *g)
{
g->start.x = 0;
g->start.y = 0;
g->middle.x = 0;
g->middle.y = 0;
g->end.x = 0;
g->end.y = 0;
g->last = MOUSE_BUTTON_UNSET;
return;
}
MouseGesture* mouse_gesture_new(void)
{
MouseGesture *g = NULL;
if((g = g_new(MouseGesture, 1)) == NULL)
return(NULL);
mouse_gesture_clear(g);
return(g);
}
static gboolean mouse_gestures_handle_events(GtkWidget *widget, GdkEvent *event, MidoriBrowser *browser)
{
if(event->type == GDK_BUTTON_PRESS) // a button was pressed
{
if(gesture->last == MOUSE_BUTTON_UNSET) // if the gesture was previously cleaned -> new gesture -> new start coordinates
{
gesture->start.x = event->button.x;
gesture->start.y = event->button.y;
gesture->last = event->button.button;
}
return(TRUE);
}
else if(event->type == GDK_MOTION_NOTIFY) // the mouse was moved
{
if(gesture->last != MOUSE_BUTTON_UNSET)
{
guint x, y;
x = event->motion.x;
y = event->motion.y;
if((gesture->start.x - x < DEVIANCE && gesture->start.x - x > -DEVIANCE) ||
(gesture->start.y - y < DEVIANCE && gesture->start.y - y > -DEVIANCE))
{
gesture->middle.x = x;
gesture->middle.y = y;
}
else if((gesture->middle.x - x < DEVIANCE && gesture->middle.x - x > -DEVIANCE) ||
(gesture->middle.y - y < DEVIANCE && gesture->middle.y - y > -DEVIANCE))
{
gesture->end.x = x;
gesture->end.y = y;
}
}
return(TRUE);
}
else if(event->type == GDK_BUTTON_RELEASE)
{
if(gesture->last == MOUSE_BUTTON_MIDDLE) // all mouse gestures will use the middle mouse button
{
// middle mouse button has been released
if(gesture->middle.x - gesture->start.x < DEVIANCE && gesture->middle.x - gesture->start.x > -DEVIANCE)
{
// StartNode to MiddleNode is a straight vertical line
if(gesture->middle.y > gesture->start.y + MINLENGTH)
{
// StartNode to MiddleNode is drawn downwards
if(gesture->middle.y - gesture->end.y < DEVIANCE && gesture->middle.y - gesture->end.y > -DEVIANCE && gesture->end.x > gesture->middle.x + MINLENGTH)
{
// MiddleNode to EndNode is a straight horizontal line (to the right) -> close tab
midori_browser_activate_action(browser, "TabClose");
#ifdef __MOUSE_GESTURES_DEBUG__
g_print("TabClose gesture\n");
#endif
}
else if(gesture->middle.y - gesture->end.y < DEVIANCE && gesture->middle.y - gesture->end.y > -DEVIANCE && gesture->end.x < gesture->middle.x - MINLENGTH)
{
// MiddleNode to EndNode is a straight horizontal line (to the left) -> reload
midori_browser_activate_action(browser, "Reload");
#ifdef __MOUSE_GESTURES_DEBUG__
g_print("Reload gesture\n");
#endif
}
else if(gesture->end.y == 0 && gesture->end.x == 0)
{
// no EndNode, just a vertical line -> new tab
midori_browser_activate_action(browser, "TabNew");
#ifdef __MOUSE_GESTURES_DEBUG__
g_print("TabNew gesture\n");
#endif
}
}
if(gesture->middle.y < gesture->start.y - MINLENGTH)
{
// StartNode to MiddleNode is drawn upwards
if(gesture->end.y == 0 && gesture->end.x == 0)
{
// no EndNode, just a vertical line -> stop
midori_browser_activate_action(browser, "Stop");
#ifdef __MOUSE_GESTURES_DEBUG__
g_print("Stop gesture\n");
#endif
}
}
}
else if(gesture->middle.y - gesture->start.y < DEVIANCE && gesture->middle.y - gesture->start.y > -DEVIANCE)
{
// Start Node to MiddleNode is a straight horizontal line
if(gesture->middle.x > gesture->start.x + MINLENGTH)
{
// the line was drawn from left to right
if(gesture->end.x == 0 && gesture->end.y == 0)
{
// we only have one horizontal line from left to right -> forward gesture
midori_browser_activate_action(browser, "Forward");
#ifdef __MOUSE_GESTURES_DEBUG__
g_print("Forward gesture\n");
#endif
}
}
else if(gesture->middle.x < gesture->start.x - MINLENGTH)
{
// the line was drawn from right to left
if(gesture->end.x == 0 && gesture->end.y == 0)
{
// we only have one horizontal line from right to left -> backwards gesture
midori_browser_activate_action(browser, "Back");
#ifdef __MOUSE_GESTURES_DEBUG__
g_print("Back gesture\n");
#endif
}
}
}
}
mouse_gesture_clear(gesture); // gesture finished, clear it
return(TRUE);
}
else
return(FALSE); // this event is supposed to be handled again (by someone else's code) since it was irrelevant to us
}
static void mouse_gestures_tab_cb(MidoriBrowser* browser, GtkWidget *view) // this is performed when a new tab is created
{
g_signal_connect(view, "event", G_CALLBACK(mouse_gestures_handle_events), browser); // perform the above callback when an event from the view is received
return;
}
static void mouse_gestures_browser_cb(MidoriApp *app, MidoriBrowser *browser) // this is performed when ever a new window is created
{
g_signal_connect(browser, "add-tab", G_CALLBACK(mouse_gestures_tab_cb), NULL); // connect the above callback to the "add-tab" signal of browser
return;
}
/* this is performed when the extension is deactivated.
disconnect all signal handlers, so that mouse gestures are no longer handled */
static void mouse_gestures_deactivate(MidoriExtension *extension, MidoriApp *app)
{
gulong signal_id = g_signal_handler_find(app, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, mouse_gestures_browser_cb, NULL); // get the signal handler id
if(signal_id != 0) // if that id is valid
g_signal_handler_disconnect(app, signal_id); // disconnect the signal
KatzeArray *browsers = katze_object_get_object(app, "browsers"); // get the array that contains all browsers
guint i; // our counter variable :)
for(i = 0; i < katze_array_get_length(browsers); i++) // from the first to the last browser
{
MidoriBrowser *browser = katze_array_get_nth_item(browsers, i); // get a pointer on the current browser
signal_id = g_signal_handler_find(browser, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, mouse_gestures_tab_cb, NULL); // search forthe signal handler id
if(signal_id != 0) // and if its not invalid..
g_signal_handler_disconnect(browser, signal_id); // disconnect it
GtkWidget *notebook = katze_object_get_object(browser, "notebook"); // get a pointer on the notebook
gint j; // another counter
for(j = 0; j < gtk_notebook_get_n_pages(GTK_NOTEBOOK(notebook)); j++) // from the first to the last tab
{
GtkWidget *page = gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook), j); // get a pointer on the tab's view
signal_id = g_signal_handler_find(page, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, mouse_gestures_handle_events, NULL); // find the signal id of the event handler
if(signal_id != 0) // if the id is valid
g_signal_handler_disconnect(page, signal_id); // disconnect the handler
}
}
g_free(gesture); // free the structure that contains the gesture information
return;
}
static void mouse_gestures_activate(MidoriExtension *extension, MidoriApp *app) // this is performed on extension-activation
{
g_signal_connect(app, "add-browser", G_CALLBACK(mouse_gestures_browser_cb), NULL); // connect the above callback to the "add-browser" signal of app
g_signal_connect(extension, "deactivate", G_CALLBACK(mouse_gestures_deactivate), app); // connect the deactivate callback to the extension
return;
}
MidoriExtension* extension_init(void)
{
MidoriExtension* extension = NULL;
extension = g_object_new(MIDORI_TYPE_EXTENSION,
"name", _("Mouse Gestures"),
"description", _("Control Midori by moving the mouse"),
"version", MOUSE_GESTURES_VERSION,
"authors", "Matthias Kruk <mkruk@matthiaskruk.de>", NULL);
g_signal_connect(extension, "activate", G_CALLBACK(mouse_gestures_activate), NULL); // connect the callback that's executed on activation
gesture = NULL; // initialise gesture pointer; initialising pointers is always a good choice
if((gesture = mouse_gesture_new()) == NULL) // allocate space for the gesture
{
// no space could be allocated
g_free(extension); // free the space used by this extension
return(NULL);
}
return(extension);
}

View file

@ -0,0 +1,37 @@
/*
Copyright (C) 2009 Matthias Kruk <mkruk@matthiaskruk.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#ifndef __MOUSE_GESTURES_H__
#define __MOUSE_GESTURES_H__
typedef struct _MouseGesture MouseGesture;
typedef enum _MouseButton MouseButton;
enum _MouseButton {
MOUSE_BUTTON_LEFT = 1,
MOUSE_BUTTON_RIGHT = 3,
MOUSE_BUTTON_MIDDLE = 2,
MOUSE_BUTTON_UNSET = 0
};
struct MouseGestureNode {
double x;
double y;
} MouseGestureNode_t;
struct _MouseGesture {
struct MouseGestureNode start;
struct MouseGestureNode middle;
struct MouseGestureNode end;
MouseButton last;
};
#endif

187
extensions/page-holder.c Normal file
View file

@ -0,0 +1,187 @@
/*
Copyright (C) 2008 Christian Dywan <christian@twotoasts.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#include <midori/midori.h>
#define STOCK_PAGE_HOLDER "page-holder"
static void
page_holder_app_add_browser_cb (MidoriApp* app,
MidoriBrowser* browser,
MidoriExtension* extension);
static gint
page_holder_notebook_append_view (GtkWidget* notebook)
{
GtkWidget* view;
MidoriBrowser* browser;
MidoriWebSettings *settings;
GtkWidget* label;
view = midori_view_new (NULL);
browser = MIDORI_BROWSER (gtk_widget_get_toplevel (notebook));
settings = katze_object_get_object (browser, "settings");
midori_view_set_settings (MIDORI_VIEW (view), settings);
g_object_unref (settings);
gtk_widget_show (view);
label = midori_view_get_proxy_tab_label (MIDORI_VIEW (view));
return gtk_notebook_append_page (GTK_NOTEBOOK (notebook), view, label);
}
static void
page_holder_button_jump_to_clicked_cb (GtkWidget* button,
GtkWidget* notebook)
{
gint n;
MidoriBrowser* browser;
const gchar* uri;
GtkWidget* view;
n = gtk_notebook_get_current_page (GTK_NOTEBOOK (notebook));
if (n < 0)
n = page_holder_notebook_append_view (notebook);
browser = MIDORI_BROWSER (gtk_widget_get_toplevel (notebook));
uri = midori_browser_get_current_uri (browser);
view = gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), n);
midori_view_set_uri (MIDORI_VIEW (view), uri);
}
static void
page_holder_button_add_clicked_cb (GtkWidget* button,
GtkWidget* notebook)
{
gint n;
GtkWidget* view;
MidoriBrowser* browser;
const gchar* uri;
n = page_holder_notebook_append_view (notebook);
view = gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), n);
browser = MIDORI_BROWSER (gtk_widget_get_toplevel (notebook));
uri = midori_browser_get_current_uri (browser);
midori_view_set_uri (MIDORI_VIEW (view), uri);
}
static void
page_holder_deactivate_cb (MidoriExtension* extension,
GtkWidget* notebook)
{
MidoriApp* app = midori_extension_get_app (extension);
gtk_widget_destroy (notebook);
g_signal_handlers_disconnect_by_func (
extension, page_holder_deactivate_cb, notebook);
g_signal_handlers_disconnect_by_func (
app, page_holder_app_add_browser_cb, extension);
}
static void
page_holder_app_add_browser_cb (MidoriApp* app,
MidoriBrowser* browser,
MidoriExtension* extension)
{
GtkWidget* panel;
GtkWidget* notebook;
GtkWidget* toolbar;
GtkToolItem* toolitem;
panel = katze_object_get_object (browser, "panel");
notebook = gtk_notebook_new ();
gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_RIGHT);
gtk_notebook_set_scrollable (GTK_NOTEBOOK (notebook), TRUE);
gtk_widget_show (notebook);
toolbar = gtk_toolbar_new ();
gtk_toolbar_set_style (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_BOTH_HORIZ);
gtk_toolbar_set_icon_size (GTK_TOOLBAR (toolbar), GTK_ICON_SIZE_BUTTON);
gtk_widget_show (toolbar);
toolitem = gtk_tool_button_new_from_stock (GTK_STOCK_JUMP_TO);
gtk_tool_item_set_is_important (toolitem, TRUE);
g_signal_connect (toolitem, "clicked",
G_CALLBACK (page_holder_button_jump_to_clicked_cb), notebook);
gtk_widget_show (GTK_WIDGET (toolitem));
gtk_toolbar_insert (GTK_TOOLBAR (toolbar), toolitem, -1);
toolitem = gtk_separator_tool_item_new ();
gtk_separator_tool_item_set_draw (GTK_SEPARATOR_TOOL_ITEM (toolitem), FALSE);
gtk_tool_item_set_expand (toolitem, TRUE);
gtk_toolbar_insert (GTK_TOOLBAR (toolbar), toolitem, -1);
gtk_widget_show (GTK_WIDGET (toolitem));
toolitem = gtk_tool_button_new_from_stock (GTK_STOCK_ADD);
gtk_tool_item_set_is_important (toolitem, TRUE);
g_signal_connect (toolitem, "clicked",
G_CALLBACK (page_holder_button_add_clicked_cb), notebook);
gtk_widget_show (GTK_WIDGET (toolitem));
gtk_toolbar_insert (GTK_TOOLBAR (toolbar), toolitem, -1);
midori_panel_append_widget (MIDORI_PANEL (panel), notebook,
/* i18n: A panel showing a user specified web page */
STOCK_PAGE_HOLDER, _("Pageholder"), toolbar);
g_signal_connect (extension, "deactivate",
G_CALLBACK (page_holder_deactivate_cb), notebook);
g_object_unref (panel);
}
static void
page_holder_activate_cb (MidoriExtension* extension,
MidoriApp* app)
{
KatzeArray* browsers;
MidoriBrowser* browser;
guint i;
browsers = katze_object_get_object (app, "browsers");
i = 0;
while ((browser = katze_array_get_nth_item (browsers, i++)))
page_holder_app_add_browser_cb (app, browser, extension);
g_object_unref (browsers);
g_signal_connect (app, "add-browser",
G_CALLBACK (page_holder_app_add_browser_cb), extension);
}
MidoriExtension*
extension_init (void)
{
GtkIconFactory* factory;
GtkIconSource* icon_source;
GtkIconSet* icon_set;
static GtkStockItem items[] =
{
{ STOCK_PAGE_HOLDER, N_("_Pageholder"), 0, 0, NULL },
};
factory = gtk_icon_factory_new ();
gtk_stock_add (items, G_N_ELEMENTS (items));
icon_set = gtk_icon_set_new ();
icon_source = gtk_icon_source_new ();
gtk_icon_source_set_icon_name (icon_source, GTK_STOCK_ORIENTATION_PORTRAIT);
gtk_icon_set_add_source (icon_set, icon_source);
gtk_icon_source_free (icon_source);
gtk_icon_factory_add (factory, STOCK_PAGE_HOLDER, icon_set);
gtk_icon_set_unref (icon_set);
gtk_icon_factory_add_default (factory);
g_object_unref (factory);
MidoriExtension* extension = g_object_new (MIDORI_TYPE_EXTENSION,
"name", _("Pageholder"),
"description", "",
"version", "0.1",
"authors", "Christian Dywan <christian@twotoasts.de>",
NULL);
g_signal_connect (extension, "activate",
G_CALLBACK (page_holder_activate_cb), NULL);
return extension;
}

View file

@ -0,0 +1,114 @@
/*
Copyright (C) 2008 Christian Dywan <christian@twotoasts.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#include <midori/midori.h>
static void
statusbar_features_app_add_browser_cb (MidoriApp* app,
MidoriBrowser* browser,
MidoriExtension* extension);
static void
statusbar_features_deactivate_cb (MidoriExtension* extension,
GtkWidget* bbox)
{
MidoriApp* app = midori_extension_get_app (extension);
gtk_widget_destroy (bbox);
g_signal_handlers_disconnect_by_func (
extension, statusbar_features_deactivate_cb, bbox);
g_signal_handlers_disconnect_by_func (
app, statusbar_features_app_add_browser_cb, extension);
}
static void
statusbar_features_app_add_browser_cb (MidoriApp* app,
MidoriBrowser* browser,
MidoriExtension* extension)
{
GtkWidget* statusbar;
GtkWidget* bbox;
MidoriWebSettings* settings;
GtkWidget* button;
GtkWidget* image;
/* FIXME: Monitor each view and modify its settings individually
instead of merely replicating the global preferences. */
statusbar = katze_object_get_object (browser, "statusbar");
bbox = gtk_hbox_new (FALSE, 0);
settings = katze_object_get_object (browser, "settings");
button = katze_property_proxy (settings, "auto-load-images", "toggle");
image = gtk_image_new_from_stock (STOCK_IMAGE, GTK_ICON_SIZE_MENU);
gtk_widget_show (image);
gtk_container_add (GTK_CONTAINER (button), image);
#if GTK_CHECK_VERSION(2, 12, 0)
gtk_widget_set_tooltip_text (button, _("Load images automatically"));
#endif
gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 2);
gtk_widget_show (button);
button = katze_property_proxy (settings, "enable-scripts", "toggle");
image = gtk_image_new_from_stock (STOCK_SCRIPTS, GTK_ICON_SIZE_MENU);
gtk_widget_show (image);
gtk_container_add (GTK_CONTAINER (button), image);
#if GTK_CHECK_VERSION(2, 12, 0)
gtk_widget_set_tooltip_text (button, _("Enable scripts"));
#endif
gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 2);
gtk_widget_show (button);
button = katze_property_proxy (settings, "enable-plugins", "toggle");
image = gtk_image_new_from_stock (STOCK_PLUGINS, GTK_ICON_SIZE_MENU);
gtk_widget_show (image);
gtk_container_add (GTK_CONTAINER (button), image);
#if GTK_CHECK_VERSION(2, 12, 0)
gtk_widget_set_tooltip_text (button, _("Enable plugins"));
#endif
gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 2);
gtk_widget_show (button);
gtk_widget_show (bbox);
gtk_box_pack_start (GTK_BOX (statusbar), bbox, FALSE, FALSE, 3);
g_object_unref (settings);
g_signal_connect (extension, "deactivate",
G_CALLBACK (statusbar_features_deactivate_cb), bbox);
}
static void
statusbar_features_activate_cb (MidoriExtension* extension,
MidoriApp* app)
{
KatzeArray* browsers;
MidoriBrowser* browser;
guint i;
browsers = katze_object_get_object (app, "browsers");
i = 0;
while ((browser = katze_array_get_nth_item (browsers, i++)))
statusbar_features_app_add_browser_cb (app, browser, extension);
g_signal_connect (app, "add-browser",
G_CALLBACK (statusbar_features_app_add_browser_cb), extension);
}
MidoriExtension*
extension_init (void)
{
MidoriExtension* extension = g_object_new (MIDORI_TYPE_EXTENSION,
"name", "Statusbar Features",
"description", "",
"version", "0.1",
"authors", "Christian Dywan <christian@twotoasts.de>",
NULL);
g_signal_connect (extension, "activate",
G_CALLBACK (statusbar_features_activate_cb), NULL);
return extension;
}

View file

@ -0,0 +1,77 @@
/*
Copyright (C) 2008 Christian Dywan <christian@twotoasts.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#include "tab-panel-extension.h"
#include <midori/midori.h>
#define STOCK_TAB_PANEL "tab-panel"
static void
tab_panel_app_add_browser_cb (MidoriApp* app,
MidoriBrowser* browser)
{
GtkWidget* panel;
GtkWidget* child;
/* FIXME: Actually provide a tree view listing all views. */
panel = katze_object_get_object (browser, "panel");
child = midori_view_new (NULL);
gtk_widget_show (child);
midori_panel_append_widget (MIDORI_PANEL (panel), child,
STOCK_TAB_PANEL, _("Tab Panel"), NULL);
}
static void
tab_panel_activate_cb (MidoriExtension* extension,
MidoriApp* app)
{
g_signal_connect (app, "add-browser",
G_CALLBACK (tab_panel_app_add_browser_cb), NULL);
}
MidoriExtension*
extension_init (void)
{
MidoriExtension* extension;
GtkIconFactory* factory;
GtkIconSource* icon_source;
GtkIconSet* icon_set;
static GtkStockItem items[] =
{
{ STOCK_TAB_PANEL, N_("T_ab Panel"), 0, 0, NULL },
};
factory = gtk_icon_factory_new ();
gtk_stock_add (items, G_N_ELEMENTS (items));
icon_set = gtk_icon_set_new ();
icon_source = gtk_icon_source_new ();
gtk_icon_source_set_icon_name (icon_source, GTK_STOCK_INDEX);
gtk_icon_set_add_source (icon_set, icon_source);
gtk_icon_source_free (icon_source);
gtk_icon_factory_add (factory, STOCK_TAB_PANEL, icon_set);
gtk_icon_set_unref (icon_set);
gtk_icon_factory_add_default (factory);
g_object_unref (factory);
extension = g_object_new (TAB_PANEL_TYPE_EXTENSION,
"name", _("Tab Panel"),
"description", "",
"version", "0.1",
"authors", "Christian Dywan <christian@twotoasts.de>",
NULL);
g_signal_connect (extension, "activate",
G_CALLBACK (tab_panel_activate_cb), NULL);
return extension;
}

View file

@ -0,0 +1,38 @@
/*
Copyright (C) 2008 Christian Dywan <christian@twotoasts.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#include "tab-panel-extension.h"
#include <midori/midori.h>
struct _TabPanelExtension
{
MidoriExtension parent_instance;
};
struct _TabPanelExtensionClass
{
MidoriExtensionClass parent_class;
};
G_DEFINE_TYPE (TabPanelExtension, tab_panel_extension, MIDORI_TYPE_EXTENSION);
static void
tab_panel_extension_class_init (TabPanelExtensionClass* class)
{
/* Nothing to do. */
}
static void
tab_panel_extension_init (TabPanelExtension* extension)
{
/* Nothing to do. */
}

View file

@ -0,0 +1,43 @@
/*
Copyright (C) 2008 Christian Dywan <christian@twotoasts.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#ifndef __TAB_PANEL_EXTENSION_H__
#define __TAB_PANEL_EXTENSION_H__
#include <glib-object.h>
G_BEGIN_DECLS
#define TAB_PANEL_TYPE_EXTENSION \
(midori_extension_get_type ())
#define TAB_PANEL_EXTENSION(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), TAB_PANEL_TYPE_EXTENSION, TabPanelExtension))
#define TAB_PANEL_EXTENSION_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), TAB_PANEL_TYPE_EXTENSION, TabPanelExtensionClass))
#define TAB_PANEL_IS_EXTENSION(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), TAB_PANEL_TYPE_EXTENSION))
#define TAB_PANEL_IS_EXTENSION_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), TAB_PANEL_TYPE_EXTENSION))
#define TAB_PANEL_EXTENSION_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), TAB_PANEL_TYPE_EXTENSION, TabPanelExtensionClass))
typedef struct _TabPanelExtension TabPanelExtension;
typedef struct _TabPanelExtensionClass TabPanelExtensionClass;
GType
tab_panel_extension_get_type (void);
/* There is no API for TabPanelExtension. Please use the
available properties and signals. */
G_END_DECLS
#endif /* __TAB_PANEL_EXTENSION_H__ */

32
extensions/wscript_build Normal file
View file

@ -0,0 +1,32 @@
#! /usr/bin/env python
# WAF build script for midori
# This file is licensed under the terms of the expat license, see the file EXPAT.
extensions = os.listdir ('extensions')
for extension in extensions:
# Tab Panel isn't useful at this point
if extension == 'tab-panel':
continue
folder = 'extensions' + os.sep + extension
if os.path.isdir (folder):
files = os.listdir (folder)
target = extension
source = ''
for fila in files:
if fila[-2:] == '.c':
source += ' ' + extension + os.sep + fila
if not source:
Utils.pprint ('RED', folder + ': No source files found')
continue
else:
if extension[-2:] != '.c':
continue
target = extension[:-2]
source = extension
obj = bld.new_task_gen ('cc', 'shlib')
obj.target = target
obj.includes = '..'
obj.source = source
obj.uselib = 'UNIQUE LIBSOUP GIO GTK SQLITE WEBKIT LIBXML'
obj.install_path = '${LIBDIR}/midori'

BIN
icons/16x16/extension.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 780 B

BIN
icons/16x16/midori.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 937 B

BIN
icons/16x16/news-feed.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 832 B

BIN
icons/22x22/extension.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
icons/22x22/midori.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
icons/22x22/news-feed.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View file

@ -0,0 +1,199 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="48"
height="48"
id="svg2"
sodipodi:version="0.32"
inkscape:version="0.46"
version="1.0"
sodipodi:docname="puzzle.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape">
<defs
id="defs4">
<linearGradient
inkscape:collect="always"
id="linearGradient3301">
<stop
style="stop-color:#888a85;stop-opacity:1;"
offset="0"
id="stop3303" />
<stop
style="stop-color:#888a85;stop-opacity:0;"
offset="1"
id="stop3305" />
</linearGradient>
<linearGradient
id="linearGradient3259">
<stop
style="stop-color:#254109;stop-opacity:1;"
offset="0"
id="stop3261" />
<stop
style="stop-color:#c1f093;stop-opacity:0;"
offset="1"
id="stop3263" />
</linearGradient>
<linearGradient
id="linearGradient3229">
<stop
style="stop-color:#6fcb15;stop-opacity:1;"
offset="0"
id="stop3231" />
<stop
style="stop-color:#73d216;stop-opacity:0;"
offset="1"
id="stop3233" />
</linearGradient>
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 526.18109 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="744.09448 : 526.18109 : 1"
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
id="perspective10" />
<inkscape:perspective
id="perspective2447"
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
inkscape:vp_z="744.09448 : 526.18109 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 526.18109 : 1"
sodipodi:type="inkscape:persp3d" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3229"
id="linearGradient3235"
x1="371.78729"
y1="555.55804"
x2="320.8378"
y2="501.43228"
gradientUnits="userSpaceOnUse" />
<filter
inkscape:collect="always"
id="filter3287"
x="-0.013903426"
width="1.0278069"
y="-0.11628319"
height="1.2325664">
<feGaussianBlur
inkscape:collect="always"
stdDeviation="0.20189084"
id="feGaussianBlur3289" />
</filter>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3229"
id="linearGradient3299"
gradientUnits="userSpaceOnUse"
x1="371.78729"
y1="555.55804"
x2="320.8378"
y2="501.43228" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3301"
id="radialGradient3307"
cx="17.704134"
cy="44.27507"
fx="17.704134"
fy="44.27507"
r="17.425131"
gradientTransform="matrix(1.4191617,0,0,0.1195652,-7.4208958,38.981304)"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3229"
id="linearGradient3310"
gradientUnits="userSpaceOnUse"
x1="371.78729"
y1="555.55804"
x2="307.07446"
y2="483.37579"
gradientTransform="translate(0.1262691,0)" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="7.9195959"
inkscape:cx="-31.755352"
inkscape:cy="29.67997"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:snap-global="false"
inkscape:window-width="997"
inkscape:window-height="795"
inkscape:window-x="0"
inkscape:window-y="0">
<inkscape:grid
type="xygrid"
id="grid2455"
visible="true"
enabled="true" />
</sodipodi:namedview>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:creator>
<cc:Agent>
<dc:title>Nancy Runge</dc:title>
</cc:Agent>
</dc:creator>
<dc:rights>
<cc:Agent>
<dc:title>licenced under LGPL</dc:title>
</cc:Agent>
</dc:rights>
<dc:title>Extensions</dc:title>
<dc:publisher>
<cc:Agent>
<dc:title>http://www.twotoasts.de</dc:title>
</cc:Agent>
</dc:publisher>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Ebene 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-334.84263,-513.45087)">
<path
sodipodi:type="arc"
style="opacity:0.52803034;fill:url(#radialGradient3307);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;filter:url(#filter3287)"
id="path3257"
sodipodi:cx="20.834396"
sodipodi:cy="44.275063"
sodipodi:rx="17.425131"
sodipodi:ry="2.0834396"
d="M 38.259527,44.275063 A 17.425131,2.0834396 0 1 1 3.4092655,44.275063 A 17.425131,2.0834396 0 1 1 38.259527,44.275063 z"
transform="matrix(1.2065218,0,0,1.6363637,333.12839,482.68731)" />
<path
style="fill:#c1f093;fill-opacity:1;fill-rule:evenodd;stroke:#499402;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
d="M 337.59808,522.17297 L 337.72435,533.84844 C 339.47847,534.10639 341.10631,535.92142 342.86043,535.22887 C 354.484,532.75774 350.70132,551.41563 342.10964,542.50639 C 340.64788,541.6646 339.18611,542.12627 337.72435,542.15558 L 337.67073,553.72581 L 353.23389,553.73869 C 354.05552,552.4318 354.72796,551.87106 354.60115,550.08995 C 351.64196,539.72544 369.94217,539.26102 360.04106,550.78887 C 359.83384,551.92692 361.24191,552.43363 361.98031,553.57168 L 369.96412,553.44765 L 369.96412,540.88184 C 370.96339,539.9698 371.96266,540.18833 372.96193,540.17836 C 384.45308,546.41513 382.69169,524.21109 372.50653,532.25474 C 371.79768,532.78933 371.04359,533.05251 370.0988,532.17145 L 370.0988,521.99757 L 362.85737,521.99757 C 361.30432,524.66021 361.13738,525.26649 361.37766,526.1182 C 368.03927,535.17088 347.04741,536.92703 352.54122,528.11641 C 354.21415,526.75748 354.49233,523.14925 354.4376,521.99756 L 337.57862,522.11095"
id="path2453"
sodipodi:nodetypes="ccccccccccccccccccccc" />
<path
style="fill:url(#linearGradient3310);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.87325984000000001;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
d="M 339.0736,523.88908 L 339.37844,532.79484 C 340.92793,533.01753 342.49273,534.03344 344.04222,533.43557 C 356.8745,532.10371 351.782,552.26286 342.62716,544.9362 C 341.58846,543.57814 340.36483,543.48432 339.0736,543.50962 L 339.13777,552.19979 L 352.02889,552.1019 C 352.95857,551.13679 354.00081,551.05253 352.57409,548.46314 C 352.71994,537.89846 369.3947,537.1685 362.99814,549.56575 C 362.81509,550.54821 362.19137,550.54855 362.84363,551.53102 L 368.46752,551.51322 L 368.46752,540.12957 C 369.78113,538.48037 371.66756,538.44729 372.54418,538.45083 C 381.58291,544.2191 381.40416,527.19794 373.12406,533.66401 C 372.91206,535.1722 368.70591,534.44374 368.40791,532.60997 L 368.40791,523.55909 L 363.61838,523.64838 C 362.51436,525.85772 363.34904,526.38112 363.56129,527.11639 C 368.40591,536.59135 346.45266,539.32394 350.48782,528.03786 C 351.96559,526.86471 353.37203,524.01762 352.60941,523.55908 L 338.78855,523.65697"
id="path3227"
sodipodi:nodetypes="ccccccccccccccccccccc" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 8.1 KiB

230
icons/scalable/midori.svg Normal file
View file

@ -0,0 +1,230 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="48"
height="48"
id="svg3612"
sodipodi:version="0.32"
inkscape:version="0.46"
version="1.0"
sodipodi:docname="drawing-1.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape">
<defs
id="defs3614">
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 19.696583 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="34.692669 : 19.696583 : 1"
inkscape:persp3d-origin="17.346334 : 13.131055 : 1"
id="perspective42" />
<linearGradient
id="linearGradient3412">
<stop
style="stop-color:#ffffff;stop-opacity:0.59836066;"
offset="0"
id="stop3414" />
<stop
style="stop-color:#4e9a06;stop-opacity:0;"
offset="1"
id="stop3416" />
</linearGradient>
<linearGradient
id="linearGradient3458">
<stop
style="stop-color:#41a100;stop-opacity:1;"
offset="0"
id="stop3460" />
<stop
style="stop-color:#ffffff;stop-opacity:0;"
offset="1"
id="stop3462" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3412"
id="linearGradient2416"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.1626866,0.3285437,-0.3285437,1.1626866,325.6313,407.16081)"
x1="13"
y1="11"
x2="40"
y2="19" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3458"
id="linearGradient2427"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.1626866,0.3285437,-0.3285437,1.1626866,327.75135,406.92561)"
x1="33"
y1="33"
x2="4"
y2="5" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
gridtolerance="10000"
guidetolerance="10"
objecttolerance="10"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="11.2"
inkscape:cx="-2.4112669"
inkscape:cy="21.831798"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="true"
showguides="true"
inkscape:guide-bbox="true"
inkscape:window-width="1443"
inkscape:window-height="766"
inkscape:window-x="0"
inkscape:window-y="22"
inkscape:snap-global="false">
<inkscape:grid
type="xygrid"
id="grid3623"
visible="true"
enabled="true" />
<sodipodi:guide
orientation="0,1"
position="-24.285714,35.982143"
id="guide3782" />
<sodipodi:guide
orientation="0,1"
position="10.535714,-15.357143"
id="guide3784" />
<sodipodi:guide
orientation="1,0"
position="8.3928572,12.321429"
id="guide3786" />
</sodipodi:namedview>
<metadata
id="metadata3617">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-322.76854,-423.39033)">
<g
transform="matrix(1.1626866,0.3285437,-0.3285437,1.1626866,327.85931,406.67587)"
style="stroke:none"
id="g3562">
<path
sodipodi:nodetypes="ccsssscssccc"
id="path3564"
d="M 32.62692,6.6695339 C 28.943103,10.347154 11.111941,12.664469 9,33 C 9.3414198,38.11565 11.750163,44.619293 16.499797,43.597643 C 17.482576,43.386246 18.538501,43.794446 19.203605,44.407481 C 23.555343,48.418538 27.732345,46.782233 28.855024,43.962447 C 29.070261,43.421846 29.754997,43.365614 30.315916,43.589557 C 36.857006,46.201039 38.613158,38.645886 39,33 C 39.096949,30.551387 37.800853,11.942617 35.822153,10.473066 C 35.232485,10.035129 33.801652,12.187441 32.644545,14.379307 C 23.397466,31.895713 11.762403,24.057082 32.238499,7.1548098 L 32.4735,6.6276491 L 32.744417,6.6586341"
style="fill:#c5f199;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" />
<g
style="fill:#c5f199;fill-opacity:1;stroke:none;stroke-linecap:round;stroke-linejoin:bevel;stroke-opacity:1"
id="g3566">
<path
style="fill:#c5f199;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:bevel;stroke-opacity:1"
d="M 24,45 L 24,33"
id="path3568" />
<path
style="fill:#c5f199;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:bevel;stroke-opacity:1"
d="M 15,42 L 15,35"
id="path3570" />
<path
style="fill:#c5f199;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:bevel;stroke-opacity:1"
d="M 33,42 L 33,35"
id="path3572" />
</g>
</g>
<g
transform="matrix(1.1626866,0.3285437,-0.3285437,1.1626866,327.85931,406.67587)"
id="g3574"
style="fill:#73d216;fill-opacity:1;stroke:none">
<path
sodipodi:nodetypes="csccsssscc"
id="path3576"
d="M 35.234589,13.724224 C 31.496538,21.805793 21.999895,29.946967 19.494746,24.633171 C 18.259214,22.012423 20.444587,17.339475 24.970511,12.046117 C 19.052984,15.684909 9.0048605,24.657969 10.614085,33.891165 C 10.240096,37.730699 13.217584,44.854617 17.074704,42.528018 C 18.102914,41.907806 19.832336,42.804046 20.452936,43.859693 C 21.771483,46.102557 26.565305,45.447239 27.607052,44.011061 C 28.374886,42.952509 29.980607,42.339501 31.245483,42.634122 C 36.778838,43.922978 37.16615,36.508792 37.142809,33.588177 C 38.771623,22.841659 35.355682,17.704462 35.234589,13.724224 z"
style="fill:#73d216;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" />
<g
style="fill:#73d216;fill-opacity:1;stroke:none;stroke-linecap:round;stroke-linejoin:bevel;stroke-opacity:1"
id="g3578">
<path
style="fill:#73d216;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:bevel;stroke-opacity:1"
d="M 33,42 L 33,35"
id="path3580" />
<path
style="fill:#73d216;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:bevel;stroke-opacity:1"
d="M 24,45 L 24,33"
id="path3582" />
<path
style="fill:#73d216;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:bevel;stroke-opacity:1"
d="M 15,42 L 15,35"
id="path3584" />
</g>
</g>
<path
sodipodi:nodetypes="cccsscsc"
id="path3586"
d="M 329.51073,447.61372 C 332.22018,442.31643 337.23637,442.25529 346.02247,445.13278 C 351.85692,445.13277 359.69811,439.61104 364.13235,434.66153 C 365.12684,453.86745 356.57278,473.21027 348.95566,465.678 C 347.93716,464.67086 347.17038,465.7736 345.66657,466.61478 C 344.22635,467.4204 343.53424,467.54511 341.98051,467.14292 C 336.85873,467.46725 335.86518,459.21391 333.59195,460.87858 C 329.28077,464.03562 327.73041,455.09453 329.51073,447.61372 z"
style="fill:url(#linearGradient2427);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
sodipodi:nodetypes="cc"
id="path3590"
d="M 334.53834,462.27896 C 334.2078,459.40748 333.844,454.00043 336.35842,450.8616"
style="fill:none;fill-rule:evenodd;stroke:#c5f199;stroke-width:3.6246419;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
sodipodi:nodetypes="ccccc"
id="path3592"
d="M 347.26802,454.03922 C 344.36973,461.6067 346.25402,462.8854 347.66323,466.99966 L 347.66323,466.99966 L 347.66323,466.99966 L 347.48466,466.37466"
style="fill:none;fill-rule:evenodd;stroke:#c5f199;stroke-width:3.6246419;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<g
transform="matrix(1.1626866,0.3285437,-0.3285437,1.1626866,300.43486,392.47027)"
id="g3596">
<path
style="fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#204c00;stroke-width:0.82766795;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 58.836696,11.191679 C 54.60152,13.283618 34.371877,21.539565 34.111956,38.37916 C 34.23937,44.016827 37.022977,50.949008 42.995777,48.976423 C 43.419099,48.836853 43.503143,48.965524 43.757523,49.283134 C 47.911767,54.469973 53.736445,51.666736 54.462077,48.968721 C 54.565425,48.584458 54.107103,48.849125 54.462077,48.968721 C 61.90878,51.477628 63.638909,44.604122 64.115394,38.779293 C 65.224194,33.529058 61.312968,14.079248 60.37612,15.673393 C 44.414802,42.833251 39.236631,24.348064 58.836696,11.191679"
id="path3598"
sodipodi:nodetypes="ccsssscsc" />
<g
id="g3600"
style="fill:none;fill-opacity:1;stroke:#306600;stroke-width:0.82766795;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
transform="translate(25,5)">
<g
style="stroke:#204c00;stroke-width:0.82766795;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="g3602">
<path
sodipodi:nodetypes="cc"
style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#204c00;stroke-width:0.82766795;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 18.645566,43.903974 C 15.051587,37.187354 16.540541,35.406359 16.713974,33.280216"
id="path3606" />
<path
sodipodi:nodetypes="cc"
style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#204c00;stroke-width:0.82766795;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 29.35012,43.828988 C 26.087374,40.085035 25.418677,36.423326 26.118423,33.355781"
id="path3608" />
</g>
</g>
</g>
<path
sodipodi:nodetypes="ccccccc"
id="path3610"
d="M 351.92318,429.5918 C 352.10808,427.28792 329.31466,436.91697 329.60494,447.76046 C 333.57302,442.60412 337.42833,442.17904 343.75497,444.76136 C 348.36775,449.06988 334.57289,441.21352 351.92318,429.5918 L 351.92318,429.5918 L 351.92318,429.5918 L 351.92318,429.5918 z"
style="fill:url(#linearGradient2416);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 11 KiB

View file

@ -0,0 +1,280 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
id="svg2"
sodipodi:version="0.32"
inkscape:version="0.46"
width="48"
height="48"
xml:space="preserve"
sodipodi:docname="tango-rss.svg"
version="1.0"
inkscape:output_extension="org.inkscape.output.svg.inkscape"><metadata
id="metadata7"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
id="defs5"><linearGradient
id="linearGradient3300"><stop
style="stop-color:#ce5c00;stop-opacity:1;"
offset="0"
id="stop3302" /><stop
style="stop-color:#893d00;stop-opacity:1;"
offset="1"
id="stop3304" /></linearGradient><linearGradient
id="linearGradient3275"><stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop3277" /><stop
style="stop-color:#f57900;stop-opacity:0;"
offset="1"
id="stop3279" /></linearGradient><inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 526.18109 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="744.09448 : 526.18109 : 1"
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
id="perspective9" /><clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath17"><path
d="M 0,128 L 128,128 L 128,0 L 0,0 L 0,128 z"
id="path19" /></clipPath><linearGradient
x1="0"
y1="0"
x2="1"
y2="0"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(-104.01236,104.01237,104.01237,104.01237,116.00586,11.994141)"
spreadMethod="pad"
id="linearGradient37"><stop
style="stop-opacity:1;stop-color:#d95b29"
offset="0"
id="stop39" /><stop
style="stop-opacity:1;stop-color:#fb9e3a"
offset="0.5"
id="stop41" /><stop
style="stop-opacity:1;stop-color:#e3702d"
offset="1"
id="stop43" /></linearGradient><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3275"
id="linearGradient3281"
x1="28.140682"
y1="59.007069"
x2="123.56256"
y2="64.008011"
gradientUnits="userSpaceOnUse" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3275"
id="linearGradient3283"
gradientUnits="userSpaceOnUse"
x1="-22.962652"
y1="-26.856916"
x2="113.12444"
y2="103.36325" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3275"
id="linearGradient3285"
gradientUnits="userSpaceOnUse"
x1="4.4374332"
y1="64.008011"
x2="123.56256"
y2="64.008011" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3275"
id="linearGradient3287"
gradientUnits="userSpaceOnUse"
x1="4.4374332"
y1="64.008011"
x2="123.56256"
y2="64.008011" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3300"
id="linearGradient3306"
x1="-0.98719376"
y1="119.27105"
x2="39.936729"
y2="88.299164"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.9961613,0,0,1.0000405,6.8742977e-4,-4.4021459e-3)" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3300"
id="linearGradient3351"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.9961613,0,0,1.0000405,6.8742977e-4,-4.4021459e-3)"
x1="-0.98719376"
y1="119.27105"
x2="39.936729"
y2="88.299164" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3275"
id="linearGradient3353"
gradientUnits="userSpaceOnUse"
x1="-22.962652"
y1="-26.856916"
x2="113.12444"
y2="103.36325" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3275"
id="linearGradient3355"
gradientUnits="userSpaceOnUse"
x1="4.4374332"
y1="64.008011"
x2="123.56256"
y2="64.008011" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3275"
id="linearGradient3357"
gradientUnits="userSpaceOnUse"
x1="4.4374332"
y1="64.008011"
x2="123.56256"
y2="64.008011" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3275"
id="linearGradient3359"
gradientUnits="userSpaceOnUse"
x1="28.140682"
y1="59.007069"
x2="123.56256"
y2="64.008011" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3300"
id="linearGradient3209"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.9961613,0,0,1.0000405,6.8742977e-4,-4.4021459e-3)"
x1="-0.98719376"
y1="119.27105"
x2="39.936729"
y2="88.299164" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3275"
id="linearGradient3211"
gradientUnits="userSpaceOnUse"
x1="-22.962652"
y1="-26.856916"
x2="113.12444"
y2="103.36325" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3275"
id="linearGradient3213"
gradientUnits="userSpaceOnUse"
x1="4.4374332"
y1="64.008011"
x2="123.56256"
y2="64.008011" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3275"
id="linearGradient3215"
gradientUnits="userSpaceOnUse"
x1="4.4374332"
y1="64.008011"
x2="123.56256"
y2="64.008011" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3275"
id="linearGradient3217"
gradientUnits="userSpaceOnUse"
x1="28.140682"
y1="59.007069"
x2="123.56256"
y2="64.008011" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3300"
id="linearGradient3232"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.9961613,0,0,1.0000405,6.4944458e-2,-4.4021459e-3)"
x1="-0.98719376"
y1="119.27105"
x2="39.936729"
y2="88.299164" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3275"
id="linearGradient3234"
gradientUnits="userSpaceOnUse"
x1="-17.119463"
y1="-35.774288"
x2="113.12444"
y2="103.36325" /></defs><sodipodi:namedview
inkscape:window-height="720"
inkscape:window-width="888"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
guidetolerance="10.0"
gridtolerance="10.0"
objecttolerance="10.0"
borderopacity="1.0"
bordercolor="#666666"
pagecolor="#ffffff"
id="base"
showgrid="true"
inkscape:snap-global="false"
showguides="true"
inkscape:guide-bbox="true"
inkscape:zoom="8.8034794"
inkscape:cx="3.3324561"
inkscape:cy="40.010499"
inkscape:window-x="542"
inkscape:window-y="39"
inkscape:current-layer="g11"><inkscape:grid
type="xygrid"
id="grid2432"
visible="true"
enabled="true" /></sodipodi:namedview><g
id="g11"
inkscape:groupmode="layer"
inkscape:label="feed-icon-legacy"
transform="matrix(1.25,0,0,-1.25,0,160)"><path
style="fill:#fcaf3e;fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient3232);stroke-width:0.80048220999999986"
d="M 38.002169,119.5841 C 38.136627,124.13453 33.833799,128.04502 29.34011,127.60391 C 22.114004,127.57701 14.884487,127.65816 7.6605468,127.56249 C 3.374464,127.23569 0.043196567,123.0315 0.4796428,118.78629 C 0.50646108,111.58944 0.42554092,104.38919 0.52093827,97.194505 C 0.84590169,92.898821 5.0383763,89.557076 9.2743628,89.994993 C 16.456202,90.021864 23.641448,89.940771 30.821119,90.036395 C 35.107237,90.362998 38.438787,94.566998 38.002169,98.8123 C 38.002169,105.73624 38.002169,112.66018 38.002169,119.5841 z"
id="path21" /><g
id="g27"
transform="matrix(0.2954876,0,0,-0.2955267,0.3513908,127.60862)"
style="fill:#f57900;fill-opacity:1"><g
id="g33"
style="fill:#f57900;fill-opacity:1"><g
id="g35"
style="fill:#f57900;fill-opacity:1"><path
id="path45"
d="M 123.429,29.915001 C 123.85961,15.464801 110.11454,3.1099424 95.831258,4.571 C 72.994905,4.6555834 50.147792,4.4001008 27.318303,4.7018714 C 13.655392,5.7359945 3.1212452,19.154954 4.571,32.63029 C 4.6555615,55.310488 4.4001543,78.001434 4.701815,100.67478 C 5.732848,114.33766 19.14685,124.88003 32.62429,123.429 C 55.309345,123.34447 78.005156,123.59982 100.68335,123.29816 C 114.34614,122.26269 124.87863,108.84276 123.429,95.36771 C 123.429,73.55014 123.429,51.732571 123.429,29.915001 z"
style="fill:#f57900;fill-opacity:1;stroke:none" /></g></g></g><g
id="g3267"
transform="matrix(0.2954876,0,0,-0.2955267,0.3016452,127.60042)"
style="fill:url(#linearGradient3217);fill-opacity:1"><g
id="g3269"
style="fill:url(#linearGradient3215);fill-opacity:1"><g
id="g3271"
style="fill:url(#linearGradient3213);fill-opacity:1"><path
id="path3273"
d="M 120.35364,17.922673 C 115.55613,8.6998977 107.96179,4.6474204 95.831258,4.571 C 72.994905,4.6555834 50.147792,4.4001008 27.318303,4.7018714 C 13.655392,5.7359945 3.1212452,19.154954 4.571,32.63029 C 4.6555615,55.310488 4.4001543,80.768894 4.701815,103.44224 C 6.1143957,104.77002 9.3538134,119.64674 16.281216,115.55817 C 32.747299,105.83986 62.937668,76.829161 61.921742,67.38561 C 61.921742,45.56804 120.35364,39.740243 120.35364,17.922673 z"
style="fill:url(#linearGradient3234);fill-opacity:1;stroke:none"
sodipodi:nodetypes="cccccscc" /></g></g></g><g
id="g3295"
transform="translate(-0.7068273,-0.4497993)"
style="fill:#eeeeec;stroke:#eeeeec"><path
transform="matrix(0.8,0,0,-0.8,0,128)"
sodipodi:nodetypes="ccccc"
id="path3293"
d="M 8.7550201,7.1164658 C 27.144226,9.188466 39.179126,18.429426 40.883534,39.325301 L 35.180723,39.325301 C 33.384365,22.620491 23.902594,14.889021 8.8353414,13.381526 L 8.7550201,7.1164658 z"
style="fill:#eeeeec;fill-opacity:1;fill-rule:evenodd;stroke:#eeeeec;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" /><path
sodipodi:nodetypes="ccccc"
transform="matrix(0.8,0,0,-0.8,0,128)"
id="path3291"
d="M 9.0763052,24.2249 C 18.841763,24.662007 23.0271,30.700076 23.935743,39.405622 L 29.879518,39.485944 C 28.300152,25.30521 20.281142,19.207838 9.0763052,18.120482 L 9.0763052,24.2249 z"
style="fill:#eeeeec;fill-opacity:1;fill-rule:evenodd;stroke:#eeeeec;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" /><path
transform="matrix(0.8,0,0,-0.8,0.8178584,128)"
d="M 16.290628,35.107368 A 4.3635263,4.3537817 0 1 1 7.5635757,35.107368 A 4.3635263,4.3537817 0 1 1 16.290628,35.107368 z"
sodipodi:ry="4.3537817"
sodipodi:rx="4.3635263"
sodipodi:cy="35.107368"
sodipodi:cx="11.927102"
id="path2493"
style="opacity:1;fill:#eeeeec;fill-opacity:1;fill-rule:evenodd;stroke:#eeeeec;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
sodipodi:type="arc" /></g></g></svg>

After

Width:  |  Height:  |  Size: 12 KiB

39
icons/wscript_build Normal file
View file

@ -0,0 +1,39 @@
#! /usr/bin/env python
# WAF build script for midori
# This file is licensed under the terms of the expat license, see the file EXPAT.
import Utils
def add_image (bld, category, name):
srcdir = os.getcwd ()
blddir = bld.bdir
rsvg_convert = bld.env['RSVG_CONVERT']
if rsvg_convert:
Utils.check_dir (blddir + '/icons')
for size in [16, 22, 32, 48]:
format = str (size) + 'x' + str (size)
if os.access (srcdir + '/icons/' + format + '/' + name + '.png', os.F_OK):
bld.install_files ('${DATADIR}/icons/hicolor/' + format + '/' + category,
srcdir + '/icons/' + format + '/' + name + '.png')
elif not rsvg_convert:
pass
elif os.access (srcdir + '/icons/scalable/' + name + '.svg', os.F_OK):
Utils.check_dir (blddir + '/icons/' + format)
command = rsvg_convert + ' -w ' + str(size) + \
' -h ' + str(size) + \
' -o ' + blddir + '/icons/' + format + '/' + name + '.png' + \
' ' + srcdir + '/icons/scalable/' + name + '.svg'
if not Utils.exec_command (command):
bld.install_files ('${DATADIR}/icons/hicolor/' + format + '/' + category,
blddir + '/icons/' + format + '/' + name + '.png')
else:
Utils.pprint ('BLUE', "Optimized icons could not be created.")
break
add_image (bld, 'categories', 'extension')
add_image (bld, 'apps', 'midori')
add_image (bld, 'status', 'news-feed')

439
katze/katze-array.c Normal file
View file

@ -0,0 +1,439 @@
/*
Copyright (C) 2008-2009 Christian Dywan <christian@twotoasts.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#include "katze-array.h"
#include "katze-utils.h"
#include "marshal.h"
#include <glib/gi18n.h>
#include <string.h>
/**
* SECTION:katze-array
* @short_description: A type aware item container
* @see_also: #KatzeList
*
* #KatzeArray is a type aware container for items.
*/
struct _KatzeArray
{
KatzeItem parent_instance;
GType type;
GList* items;
};
struct _KatzeArrayClass
{
KatzeItemClass parent_class;
/* Signals */
void
(*add_item) (KatzeArray* array,
gpointer item);
void
(*remove_item) (KatzeArray* array,
gpointer item);
void
(*move_item) (KatzeArray* array,
gpointer item,
gint index);
void
(*clear) (KatzeArray* array);
};
G_DEFINE_TYPE (KatzeArray, katze_array, KATZE_TYPE_ITEM);
enum {
ADD_ITEM,
REMOVE_ITEM,
MOVE_ITEM,
CLEAR,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL];
static void
katze_array_finalize (GObject* object);
static void
_katze_array_add_item (KatzeArray* array,
gpointer item)
{
if (katze_array_is_a (array, G_TYPE_OBJECT))
{
GType type = G_OBJECT_TYPE (item);
g_return_if_fail (katze_array_is_a (array, type));
g_object_ref (item);
if (g_type_is_a (type, KATZE_TYPE_ITEM))
katze_item_set_parent (item, array);
}
array->items = g_list_append (array->items, item);
}
static void
_katze_array_remove_item (KatzeArray* array,
gpointer item)
{
array->items = g_list_remove (array->items, item);
if (katze_array_is_a (array, G_TYPE_OBJECT))
{
if (KATZE_IS_ITEM (item))
katze_item_set_parent (item, NULL);
g_object_unref (item);
}
}
static void
_katze_array_move_item (KatzeArray* array,
gpointer item,
gint position)
{
array->items = g_list_remove (array->items, item);
array->items = g_list_insert (array->items, item, position);
}
static void
_katze_array_clear (KatzeArray* array)
{
guint n;
guint i;
GObject* item;
n = g_list_length (array->items);
for (i = 0; i < n; i++)
{
if ((item = g_list_nth_data (array->items, i)))
katze_array_remove_item (array, item);
}
g_list_free (array->items);
array->items = NULL;
}
static void
katze_array_class_init (KatzeArrayClass* class)
{
GObjectClass* gobject_class;
gobject_class = G_OBJECT_CLASS (class);
gobject_class->finalize = katze_array_finalize;
signals[ADD_ITEM] = g_signal_new (
"add-item",
G_TYPE_FROM_CLASS (class),
(GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
G_STRUCT_OFFSET (KatzeArrayClass, add_item),
0,
NULL,
g_cclosure_marshal_VOID__POINTER,
G_TYPE_NONE, 1,
G_TYPE_POINTER);
signals[REMOVE_ITEM] = g_signal_new (
"remove-item",
G_TYPE_FROM_CLASS (class),
(GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
G_STRUCT_OFFSET (KatzeArrayClass, remove_item),
0,
NULL,
g_cclosure_marshal_VOID__POINTER,
G_TYPE_NONE, 1,
G_TYPE_POINTER);
/**
* KatzeArray::move-item:
* @array: the object on which the signal is emitted
* @item: the item being moved
* @position: the new position of the item
*
* An item is moved to a new position.
*
* Since: 0.1.6
**/
signals[MOVE_ITEM] = g_signal_new (
"move-item",
G_TYPE_FROM_CLASS (class),
(GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
G_STRUCT_OFFSET (KatzeArrayClass, move_item),
0,
NULL,
katze_cclosure_marshal_VOID__POINTER_INT,
G_TYPE_NONE, 2,
G_TYPE_POINTER,
G_TYPE_INT);
signals[CLEAR] = g_signal_new (
"clear",
G_TYPE_FROM_CLASS (class),
(GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
G_STRUCT_OFFSET (KatzeArrayClass, clear),
0,
NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
gobject_class = G_OBJECT_CLASS (class);
gobject_class->finalize = katze_array_finalize;
class->add_item = _katze_array_add_item;
class->remove_item = _katze_array_remove_item;
class->move_item = _katze_array_move_item;
class->clear = _katze_array_clear;
}
static void
katze_array_init (KatzeArray* array)
{
array->type = G_TYPE_NONE;
array->items = NULL;
}
static void
katze_array_finalize (GObject* object)
{
KatzeArray* array;
guint i;
array = KATZE_ARRAY (object);
if (katze_array_is_a (array, G_TYPE_OBJECT))
{
gpointer item;
i = 0;
while ((item = g_list_nth_data (array->items, i++)))
g_object_unref (item);
}
g_list_free (array->items);
G_OBJECT_CLASS (katze_array_parent_class)->finalize (object);
}
/**
* katze_array_new:
* @type: the expected item type
*
* Creates a new #KatzeArray for @type items.
*
* You may only add items of the given type or inherited
* from it to this array *if* @type is an #GObject type.
* The array will keep a reference on each object until
* it is removed from the array.
*
* Return value: a new #KatzeArray
**/
KatzeArray*
katze_array_new (GType type)
{
KatzeArray* array = g_object_new (KATZE_TYPE_ARRAY, NULL);
array->type = type;
return array;
}
/**
*
* katze_array_is_a:
* @array: a #KatzeArray
* @is_a_type: type to compare with
*
* Checks whether the array is compatible
* with items of the specified type.
*
* Retur value: %TRUE if @array is compatible with @is_a_type
**/
gboolean
katze_array_is_a (KatzeArray* array,
GType is_a_type)
{
g_return_val_if_fail (KATZE_IS_ARRAY (array), FALSE);
return g_type_is_a (array->type, is_a_type);
}
/**
* katze_array_add_item:
* @array: a #KatzeArray
* @item: an item
*
* Adds an item to the array.
*
* If @item is a #KatzeItem its parent is set accordingly.
**/
void
katze_array_add_item (KatzeArray* array,
gpointer item)
{
g_return_if_fail (KATZE_IS_ARRAY (array));
g_signal_emit (array, signals[ADD_ITEM], 0, item);
}
/**
* katze_array_remove_item:
* @array: a #KatzeArray
* @item: an item
*
* Removes an item from the array.
*
* If @item is a #KatzeItem its parent is unset accordingly.
**/
void
katze_array_remove_item (KatzeArray* array,
gpointer item)
{
g_return_if_fail (KATZE_IS_ARRAY (array));
g_signal_emit (array, signals[REMOVE_ITEM], 0, item);
}
/**
* katze_array_get_nth_item:
* @array: a #KatzeArray
* @n: an index in the array
*
* Retrieves the item in @array at the position @n.
*
* Return value: an item, or %NULL
**/
gpointer
katze_array_get_nth_item (KatzeArray* array,
guint n)
{
g_return_val_if_fail (KATZE_IS_ARRAY (array), NULL);
return g_list_nth_data (array->items, n);
}
/**
* katze_array_is_empty:
* @array: a #KatzeArray
*
* Determines whether @array is empty.
*
* Return value: an item, or %NULL
**/
gboolean
katze_array_is_empty (KatzeArray* array)
{
g_return_val_if_fail (KATZE_IS_ARRAY (array), TRUE);
return !g_list_nth_data (array->items, 0);
}
/**
* katze_array_get_item_index:
* @array: a #KatzeArray
* @item: an item in the array
*
* Retrieves the index of the item in @array.
*
* Return value: an item, or -1
**/
gint
katze_array_get_item_index (KatzeArray* array,
gpointer item)
{
g_return_val_if_fail (KATZE_IS_ARRAY (array), -1);
return g_list_index (array->items, item);
}
/**
* katze_array_find_token:
* @array: a #KatzeArray
* @token: a token 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.
*
* Note that @token is by definition unique to one item.
*
* Return value: an item, or %NULL
**/
gpointer
katze_array_find_token (KatzeArray* array,
const gchar* token)
{
guint i;
gpointer item;
if (!katze_array_is_a (array, G_TYPE_OBJECT))
return NULL;
i = 0;
while ((item = g_list_nth_data (array->items, i++)))
{
const gchar* found_token = katze_item_get_token ((KatzeItem*)item);
if (!g_strcmp0 (found_token, token))
return item;
}
return NULL;
}
/**
* katze_array_get_length:
* @array: a #KatzeArray
*
* Retrieves the number of items in @array.
*
* Return value: the length of the list
**/
guint
katze_array_get_length (KatzeArray* array)
{
g_return_val_if_fail (KATZE_IS_ARRAY (array), 0);
return g_list_length (array->items);
}
/**
* katze_array_move_item:
* @array: a #KatzeArray
* @item: the item being moved
* @position: the new position of the item
*
* Moves @item to the position @position.
*
* Since: 0.1.6
**/
void
katze_array_move_item (KatzeArray* array,
gpointer item,
gint position)
{
g_return_if_fail (KATZE_IS_ARRAY (array));
g_signal_emit (array, signals[MOVE_ITEM], 0, item, position);
}
/**
* katze_array_clear:
* @array: a #KatzeArray
*
* Deletes all items currently contained in @array.
**/
void
katze_array_clear (KatzeArray* array)
{
g_return_if_fail (KATZE_IS_ARRAY (array));
g_signal_emit (array, signals[CLEAR], 0);
}

81
katze/katze-array.h Normal file
View file

@ -0,0 +1,81 @@
/*
Copyright (C) 2008-2009 Christian Dywan <christian@twotoasts.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#ifndef __KATZE_ARRAY_H__
#define __KATZE_ARRAY_H__
#include <katze/katze-item.h>
G_BEGIN_DECLS
#define KATZE_TYPE_ARRAY \
(katze_array_get_type ())
#define KATZE_ARRAY(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), KATZE_TYPE_ARRAY, KatzeArray))
#define KATZE_ARRAY_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), KATZE_TYPE_ARRAY, KatzeArrayClass))
#define KATZE_IS_ARRAY(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), KATZE_TYPE_ARRAY))
#define KATZE_IS_ARRAY_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), KATZE_TYPE_ARRAY))
#define KATZE_ARRAY_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), KATZE_TYPE_ARRAY, KatzeArrayClass))
typedef struct _KatzeArray KatzeArray;
typedef struct _KatzeArrayClass KatzeArrayClass;
GType
katze_array_get_type (void);
KatzeArray*
katze_array_new (GType type);
gboolean
katze_array_is_a (KatzeArray* array,
GType is_a_type);
void
katze_array_add_item (KatzeArray* array,
gpointer item);
void
katze_array_remove_item (KatzeArray* array,
gpointer item);
gpointer
katze_array_get_nth_item (KatzeArray* array,
guint n);
gboolean
katze_array_is_empty (KatzeArray* array);
gint
katze_array_get_item_index (KatzeArray* array,
gpointer item);
gpointer
katze_array_find_token (KatzeArray* array,
const gchar* token);
guint
katze_array_get_length (KatzeArray* array);
void
katze_array_move_item (KatzeArray* array,
gpointer item,
gint position);
void
katze_array_clear (KatzeArray* array);
G_END_DECLS
#endif /* __KATZE_ARRAY_H__ */

574
katze/katze-arrayaction.c Normal file
View file

@ -0,0 +1,574 @@
/*
Copyright (C) 2008 Christian Dywan <christian@twotoasts.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#include "katze-arrayaction.h"
#include "katze-net.h"
#include "katze-utils.h"
#include <string.h>
#include <glib/gi18n.h>
#include <gtk/gtk.h>
struct _KatzeArrayAction
{
GtkAction parent_instance;
KatzeArray* array;
KatzeNet* net;
};
struct _KatzeArrayActionClass
{
GtkActionClass parent_class;
};
G_DEFINE_TYPE (KatzeArrayAction, katze_array_action, GTK_TYPE_ACTION);
enum
{
PROP_0,
PROP_ARRAY
};
enum
{
POPULATE_POPUP,
ACTIVATE_ITEM,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL];
static void
katze_array_action_finalize (GObject* object);
static void
katze_array_action_set_property (GObject* object,
guint prop_id,
const GValue* value,
GParamSpec* pspec);
static void
katze_array_action_get_property (GObject* object,
guint prop_id,
GValue* value,
GParamSpec* pspec);
static void
katze_array_action_activate (GtkAction* object);
static GtkWidget*
katze_array_action_create_tool_item (GtkAction* action);
static GtkWidget*
katze_array_action_create_menu_item (GtkAction* action);
static void
katze_array_action_connect_proxy (GtkAction* action,
GtkWidget* proxy);
static void
katze_array_action_disconnect_proxy (GtkAction* action,
GtkWidget* proxy);
static void
katze_array_action_class_init (KatzeArrayActionClass* class)
{
GObjectClass* gobject_class;
GtkActionClass* action_class;
signals[POPULATE_POPUP] = g_signal_new ("populate-popup",
G_TYPE_FROM_CLASS (class),
(GSignalFlags) (G_SIGNAL_RUN_LAST),
0,
0,
NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE, 1,
GTK_TYPE_MENU);
signals[ACTIVATE_ITEM] = g_signal_new ("activate-item",
G_TYPE_FROM_CLASS (class),
(GSignalFlags) (G_SIGNAL_RUN_LAST),
0,
0,
NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE, 1,
KATZE_TYPE_ITEM);
gobject_class = G_OBJECT_CLASS (class);
gobject_class->finalize = katze_array_action_finalize;
gobject_class->set_property = katze_array_action_set_property;
gobject_class->get_property = katze_array_action_get_property;
action_class = GTK_ACTION_CLASS (class);
action_class->activate = katze_array_action_activate;
action_class->create_menu_item = katze_array_action_create_menu_item;
action_class->create_tool_item = katze_array_action_create_tool_item;
action_class->connect_proxy = katze_array_action_connect_proxy;
action_class->disconnect_proxy = katze_array_action_disconnect_proxy;
g_object_class_install_property (gobject_class,
PROP_ARRAY,
g_param_spec_object (
"array",
"Array",
"The array the action represents",
KATZE_TYPE_ARRAY,
G_PARAM_READWRITE));
}
static void
katze_array_action_init (KatzeArrayAction* array_action)
{
array_action->array = NULL;
array_action->net = katze_net_new ();
}
static void
katze_array_action_finalize (GObject* object)
{
KatzeArrayAction* array_action = KATZE_ARRAY_ACTION (object);
katze_object_assign (array_action->array, NULL);
katze_object_assign (array_action->net, NULL);
G_OBJECT_CLASS (katze_array_action_parent_class)->finalize (object);
}
static void
katze_array_action_set_property (GObject* object,
guint prop_id,
const GValue* value,
GParamSpec* pspec)
{
KatzeArrayAction* array_action = KATZE_ARRAY_ACTION (object);
switch (prop_id)
{
case PROP_ARRAY:
katze_array_action_set_array (array_action, g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
katze_array_action_get_property (GObject* object,
guint prop_id,
GValue* value,
GParamSpec* pspec)
{
KatzeArrayAction* array_action = KATZE_ARRAY_ACTION (object);
switch (prop_id)
{
case PROP_ARRAY:
g_value_set_object (value, array_action->array);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
katze_array_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_array_action_parent_class)->activate)
GTK_ACTION_CLASS (katze_array_action_parent_class)->activate (action);
}
static void
katze_array_action_menu_item_activate_cb (GtkWidget* proxy,
KatzeArrayAction* array_action)
{
KatzeItem* item = g_object_get_data (G_OBJECT (proxy), "KatzeItem");
g_signal_emit (array_action, signals[ACTIVATE_ITEM], 0, item);
}
static void
katze_array_action_menu_item_select_cb (GtkWidget* proxy,
KatzeArrayAction* array_action);
static void
katze_array_action_generate_menu (KatzeArrayAction* array_action,
KatzeArray* array,
GtkWidget* menu,
GtkWidget* proxy)
{
guint i;
KatzeItem* item;
GtkWidget* menuitem;
const gchar* icon_name;
GdkPixbuf* icon;
GtkWidget* image;
GtkWidget* submenu;
i = 0;
while ((item = katze_array_get_nth_item (array, i++)))
{
/* FIXME: The menu item should reflect changes to the item */
if (!KATZE_IS_ARRAY (item) && !katze_item_get_uri (item))
{
menuitem = gtk_separator_menu_item_new ();
gtk_widget_show (menuitem);
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
continue;
}
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_IS_ARRAY (item))
icon = gtk_widget_render_icon (menuitem,
GTK_STOCK_DIRECTORY, GTK_ICON_SIZE_MENU, NULL);
else
icon = katze_net_load_icon (array_action->net,
katze_item_get_uri (item), NULL, proxy, NULL);
image = gtk_image_new_from_pixbuf (icon);
g_object_unref (icon);
}
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), image);
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
g_object_set_data (G_OBJECT (menuitem), "KatzeItem", item);
if (KATZE_IS_ARRAY (item))
{
submenu = gtk_menu_new ();
gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), submenu);
g_signal_connect (menuitem, "select",
G_CALLBACK (katze_array_action_menu_item_select_cb), array_action);
}
else
g_signal_connect (menuitem, "activate",
G_CALLBACK (katze_array_action_menu_item_activate_cb), array_action);
gtk_widget_show (menuitem);
}
if (!i)
{
menuitem = gtk_image_menu_item_new_with_label (_("Empty"));
gtk_widget_set_sensitive (menuitem, FALSE);
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
gtk_widget_show (menuitem);
}
}
static void
katze_array_action_menu_item_select_cb (GtkWidget* proxy,
KatzeArrayAction* array_action)
{
GtkWidget* menu;
KatzeArray* array;
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, menu, proxy);
}
static void
katze_array_action_proxy_clicked_cb (GtkWidget* proxy,
KatzeArrayAction* array_action)
{
GtkWidget* menu;
KatzeArray* array;
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_POPUP], 0,
gtk_menu_item_get_submenu (GTK_MENU_ITEM (proxy)));
return;
}
menu = gtk_menu_new ();
array = (KatzeArray*)g_object_get_data (G_OBJECT (proxy), "KatzeArray");
if (!array)
array = array_action->array;
katze_array_action_generate_menu (array_action, array, menu, proxy);
/* populate-popup should only affect the main proxy */
if (array == array_action->array)
g_signal_emit (array_action, signals[POPULATE_POPUP], 0, menu);
katze_widget_popup (GTK_WIDGET (proxy), GTK_MENU (menu),
NULL, KATZE_MENU_POSITION_LEFT);
}
static GtkWidget*
katze_array_action_create_menu_item (GtkAction* action)
{
GtkWidget* menuitem;
menuitem = gtk_menu_item_new ();
return menuitem;
}
static GtkWidget*
katze_array_action_create_tool_item (GtkAction* action)
{
GtkWidget* toolitem;
toolitem = GTK_WIDGET (gtk_tool_button_new (NULL, NULL));
return toolitem;
}
static void
katze_array_action_label_notify_cb (GtkToolButton* item,
GParamSpec* pspec,
GtkLabel* label)
{
const gchar* property;
const gchar* text;
if (!G_IS_PARAM_SPEC_STRING (pspec))
return;
property = g_param_spec_get_name (pspec);
if (!strcmp (property, "label"))
{
text = gtk_tool_button_get_label (item);
gtk_label_set_text (label, text);
}
}
static void
katze_array_action_item_notify_cb (KatzeItem* item,
GParamSpec* pspec,
GtkToolItem* toolitem)
{
KatzeArrayAction* array_action;
const gchar* property;
const gchar* title;
const gchar* desc;
GdkPixbuf* icon;
GtkWidget* image;
if (!G_IS_PARAM_SPEC_STRING (pspec))
return;
array_action = (KatzeArrayAction*)g_object_get_data (
G_OBJECT (toolitem), "KatzeArrayAction");
property = g_param_spec_get_name (pspec);
if (!strcmp (property, "name"))
{
title = katze_item_get_name (item);
if (title)
gtk_tool_button_set_label (GTK_TOOL_BUTTON (toolitem), title);
else
gtk_tool_button_set_label (GTK_TOOL_BUTTON (toolitem),
katze_item_get_uri (item));
}
else if (!strcmp (property, "text"))
{
desc = katze_item_get_text (item);
if (desc && *desc)
gtk_tool_item_set_tooltip_text (toolitem, desc);
else
gtk_tool_item_set_tooltip_text (toolitem,
katze_item_get_uri (item));
}
else if (!KATZE_IS_ARRAY (item) && !strcmp (property, "uri"))
{
icon = katze_net_load_icon (array_action->net, katze_item_get_uri (item),
NULL, GTK_WIDGET (toolitem), NULL);
image = gtk_image_new_from_pixbuf (icon);
g_object_unref (icon);
gtk_widget_show (image);
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);
gtk_tool_button_set_icon_widget (GTK_TOOL_BUTTON (toolitem), image);
}
}
/**
* katze_array_action_create_tool_item_for:
* @array_action: a #KatzeArrayAction
* @item: a #KatzeItem
*
* Creates a tool item for a particular @item, that also
* reflects changes to its properties. In the case of
* an array, the item will create a popup menu with
* the contained items.
*
* Note that the label is reasonably ellipsized for you,
* much like katze_image_menu_item_new_ellipsized().
*
* Return value: a new tool item
**/
GtkToolItem*
katze_array_action_create_tool_item_for (KatzeArrayAction* array_action,
KatzeItem* item)
{
const gchar* title;
const gchar* uri;
const gchar* desc;
GtkToolItem* toolitem;
GdkPixbuf* icon;
GtkWidget* image;
GtkWidget* label;
title = katze_item_get_name (item);
uri = katze_item_get_uri (item);
desc = katze_item_get_text (item);
if (!KATZE_IS_ARRAY (item) && !uri)
return gtk_separator_tool_item_new ();
toolitem = gtk_tool_button_new (NULL, NULL);
if (KATZE_IS_ARRAY (item))
icon = gtk_widget_render_icon (GTK_WIDGET (toolitem),
GTK_STOCK_DIRECTORY, GTK_ICON_SIZE_MENU, NULL);
else
icon = katze_net_load_icon (array_action->net, uri,
NULL, GTK_WIDGET (toolitem), NULL);
image = gtk_image_new_from_pixbuf (icon);
g_object_unref (icon);
gtk_widget_show (image);
gtk_tool_button_set_icon_widget (GTK_TOOL_BUTTON (toolitem), image);
label = gtk_label_new (NULL);
/* FIXME: Should text direction be respected here? */
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.0);
gtk_label_set_max_width_chars (GTK_LABEL (label), 25);
gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_MIDDLE);
gtk_widget_show (label);
gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (toolitem), label);
/* GtkToolItem won't update our custom label, so we
apply a little bit of 'magic' to fix that. */
g_signal_connect (toolitem, "notify",
G_CALLBACK (katze_array_action_label_notify_cb), label);
if (title)
gtk_tool_button_set_label (GTK_TOOL_BUTTON (toolitem), title);
else
gtk_tool_button_set_label (GTK_TOOL_BUTTON (toolitem), uri);
gtk_tool_item_set_is_important (toolitem, TRUE);
if (desc && *desc)
gtk_tool_item_set_tooltip_text (toolitem, desc);
else
gtk_tool_item_set_tooltip_text (toolitem, uri);
if (KATZE_IS_ARRAY (item))
{
g_object_set_data (G_OBJECT (toolitem), "KatzeArray", item);
g_signal_connect (toolitem, "clicked",
G_CALLBACK (katze_array_action_proxy_clicked_cb), array_action);
}
g_object_set_data (G_OBJECT (toolitem), "KatzeArrayAction", array_action);
g_signal_connect (item, "notify",
G_CALLBACK (katze_array_action_item_notify_cb), toolitem);
return toolitem;
}
static void
katze_array_action_connect_proxy (GtkAction* action,
GtkWidget* proxy)
{
GTK_ACTION_CLASS (katze_array_action_parent_class)->connect_proxy (
action, proxy);
if (GTK_IS_TOOL_ITEM (proxy))
{
g_signal_connect (proxy, "clicked",
G_CALLBACK (katze_array_action_proxy_clicked_cb), 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);
}
gtk_widget_set_sensitive (proxy, KATZE_ARRAY_ACTION (action)->array != NULL);
}
static void
katze_array_action_disconnect_proxy (GtkAction* action,
GtkWidget* proxy)
{
g_signal_handlers_disconnect_by_func (proxy,
G_CALLBACK (katze_array_action_proxy_clicked_cb), action);
GTK_ACTION_CLASS (katze_array_action_parent_class)->disconnect_proxy
(action, proxy);
}
KatzeArray*
katze_array_action_get_array (KatzeArrayAction* array_action)
{
g_return_val_if_fail (KATZE_IS_ARRAY_ACTION (array_action), NULL);
return array_action->array;
}
void
katze_array_action_set_array (KatzeArrayAction* array_action,
KatzeArray* array)
{
GSList* proxies;
g_return_if_fail (KATZE_IS_ARRAY_ACTION (array_action));
g_return_if_fail (!array || katze_array_is_a (array, KATZE_TYPE_ITEM));
/* FIXME: Disconnect old array */
if (array)
g_object_ref (array);
katze_object_assign (array_action->array, array);
/* FIXME: Add and remove items dynamically */
/*g_object_connect (array,
"signal-after::add-item",
katze_array_action_engines_add_item_cb, array_action,
"signal-after::remove-item",
katze_array_action_engines_remove_item_cb, array_action,
NULL);*/
g_object_notify (G_OBJECT (array_action), "array");
proxies = gtk_action_get_proxies (GTK_ACTION (array_action));
if (!proxies)
return;
do
{
gtk_widget_set_sensitive (proxies->data, array != NULL);
}
while ((proxies = g_slist_next (proxies)));
}

53
katze/katze-arrayaction.h Normal file
View file

@ -0,0 +1,53 @@
/*
Copyright (C) 2008 Christian Dywan <christian@twotoasts.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#ifndef __KATZE_ARRAY_ACTION_H__
#define __KATZE_ARRAY_ACTION_H__
#include "katze-array.h"
#include <gtk/gtk.h>
G_BEGIN_DECLS
#define KATZE_TYPE_ARRAY_ACTION \
(katze_array_action_get_type ())
#define KATZE_ARRAY_ACTION(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), KATZE_TYPE_ARRAY_ACTION, KatzeArrayAction))
#define KATZE_ARRAY_ACTION_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), KATZE_TYPE_ARRAY_ACTION, KatzeArrayActionClass))
#define KATZE_IS_ARRAY_ACTION(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), KATZE_TYPE_ARRAY_ACTION))
#define KATZE_IS_ARRAY_ACTION_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), KATZE_TYPE_ARRAY_ACTION))
#define KATZE_ARRAY_ACTION_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), KATZE_TYPE_ARRAY_ACTION, KatzeArrayActionClass))
typedef struct _KatzeArrayAction KatzeArrayAction;
typedef struct _KatzeArrayActionClass KatzeArrayActionClass;
GType
katze_array_action_get_type (void);
KatzeArray*
katze_array_action_get_array (KatzeArrayAction* array_action);
void
katze_array_action_set_array (KatzeArrayAction* array_action,
KatzeArray* array);
GtkToolItem*
katze_array_action_create_tool_item_for (KatzeArrayAction* array_action,
KatzeItem* item);
G_END_DECLS
#endif /* __KATZE_ARRAY_ACTION_H__ */

212
katze/katze-http-auth.c Normal file
View file

@ -0,0 +1,212 @@
/*
Copyright (C) 2008-2009 Christian Dywan <christian@twotoasts.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#if HAVE_CONFIG_H
#include <config.h>
#endif
#include "katze-http-auth.h"
#include <libsoup/soup.h>
#include <gtk/gtk.h>
#include <glib/gi18n.h>
struct _KatzeHttpAuth
{
GObject parent_instance;
};
struct _KatzeHttpAuthClass
{
GObjectClass parent_class;
};
static void
katze_http_auth_session_feature_iface_init (SoupSessionFeatureInterface *iface,
gpointer data);
G_DEFINE_TYPE_WITH_CODE (KatzeHttpAuth, katze_http_auth, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (SOUP_TYPE_SESSION_FEATURE,
katze_http_auth_session_feature_iface_init));
static void
authentication_dialog_response_cb (GtkWidget* dialog,
gint response,
SoupAuth* auth)
{
GtkWidget* username;
GtkWidget* password;
SoupSession* session;
SoupMessage* msg;
if (response == GTK_RESPONSE_OK)
{
username = g_object_get_data (G_OBJECT (dialog), "username");
password = g_object_get_data (G_OBJECT (dialog), "password");
soup_auth_authenticate (auth,
gtk_entry_get_text (GTK_ENTRY (username)),
gtk_entry_get_text (GTK_ENTRY (password)));
}
session = g_object_get_data (G_OBJECT (dialog), "session");
msg = g_object_get_data (G_OBJECT (dialog), "msg");
gtk_widget_destroy (dialog);
if (g_object_get_data (G_OBJECT (msg), "paused"))
soup_session_unpause_message (session, msg);
g_object_unref (auth);
}
static void
katze_http_auth_session_authenticate_cb (SoupSession* session,
SoupMessage* msg,
SoupAuth* auth,
gboolean retrying)
{
GtkWidget* dialog;
GtkSizeGroup* sizegroup;
GtkWidget* hbox;
GtkWidget* image;
GtkWidget* label;
GtkWidget* align;
GtkWidget* entry;
/* We want to ask for authentication exactly once, so we
enforce this with a tag. There might be a better way. */
if (!retrying && g_object_get_data (G_OBJECT (msg), "katze-session-tag"))
return;
if (soup_message_is_keepalive (msg))
{
/* We use another tag to indicate whether a message is paused.
There doesn't seem to be API in libSoup to find that out. */
soup_session_pause_message (session, msg);
g_object_set_data (G_OBJECT (msg), "paused", (void*)1);
}
g_object_set_data (G_OBJECT (msg), "katze-session-tag", (void*)1);
dialog = gtk_dialog_new_with_buttons (_("Authentication Required"),
NULL,
GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OK, GTK_RESPONSE_OK,
NULL);
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 (GTK_DIALOG (dialog)->vbox), 5);
gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->vbox), 5);
hbox = gtk_hbox_new (FALSE, 6);
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 (_("A username and a password are required\n"
"to open this location:"));
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), hbox);
label = gtk_label_new (soup_auth_get_host (auth));
gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), label);
/* If the realm is merely the host, omit the realm label */
if (g_strcmp0 (soup_auth_get_host (auth), soup_auth_get_realm (auth)))
{
label = gtk_label_new (soup_auth_get_realm (auth));
gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), label);
}
sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
hbox = gtk_hbox_new (FALSE, 6);
label = gtk_label_new (_("Username"));
align = gtk_alignment_new (0, 0.5, 0, 0);
gtk_container_add (GTK_CONTAINER (align), label);
gtk_size_group_add_widget (sizegroup, align);
gtk_box_pack_start (GTK_BOX (hbox), align, TRUE, TRUE, 0);
entry = gtk_entry_new ();
gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
g_object_set_data (G_OBJECT (dialog), "username", entry);
gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), hbox);
hbox = gtk_hbox_new (FALSE, 6);
label = gtk_label_new (_("Password"));
align = gtk_alignment_new (0, 0.5, 0, 0);
gtk_container_add (GTK_CONTAINER (align), label);
gtk_size_group_add_widget (sizegroup, align);
gtk_box_pack_start (GTK_BOX (hbox), align, TRUE, TRUE, 0);
entry = gtk_entry_new_with_max_length (32);
gtk_entry_set_visibility (GTK_ENTRY (entry), FALSE);
gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
g_object_set_data (G_OBJECT (dialog), "password", entry);
gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), hbox);
gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
gtk_widget_show_all (GTK_DIALOG (dialog)->vbox);
g_object_set_data (G_OBJECT (dialog), "session", session);
g_object_set_data (G_OBJECT (dialog), "msg", msg);
g_signal_connect (dialog, "response",
G_CALLBACK (authentication_dialog_response_cb), g_object_ref (auth));
gtk_widget_show (dialog);
}
static void
katze_http_auth_session_request_queued_cb (SoupSession* session,
SoupMessage* msg,
gpointer data)
{
/* WebKit has its own authentication dialog in recent versions.
We want only one, and we choose our own to have localization. */
GType type = g_type_from_name ("WebKitSoupAuthDialog");
if (type)
soup_session_remove_feature_by_type (session, type);
g_signal_connect (session, "authenticate",
G_CALLBACK (katze_http_auth_session_authenticate_cb), NULL);
g_signal_handlers_disconnect_by_func (session,
katze_http_auth_session_request_queued_cb, NULL);
}
static void
katze_http_auth_attach (SoupSessionFeature* feature,
SoupSession* session)
{
g_signal_connect (session, "request-queued",
G_CALLBACK (katze_http_auth_session_request_queued_cb), NULL);
}
static void
katze_http_auth_detach (SoupSessionFeature* feature,
SoupSession* session)
{
g_signal_handlers_disconnect_by_func (session,
katze_http_auth_session_authenticate_cb, NULL);
g_signal_handlers_disconnect_by_func (session,
katze_http_auth_session_request_queued_cb, NULL);
}
static void
katze_http_auth_session_feature_iface_init (SoupSessionFeatureInterface *iface,
gpointer data)
{
iface->attach = katze_http_auth_attach;
iface->detach = katze_http_auth_detach;
}
static void
katze_http_auth_class_init (KatzeHttpAuthClass* class)
{
/* Nothing to do. */
}
static void
katze_http_auth_init (KatzeHttpAuth* http_auth)
{
/* Nothing to do. */
}

42
katze/katze-http-auth.h Normal file
View file

@ -0,0 +1,42 @@
/*
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_HTTP_AUTH_H__
#define __KATZE_HTTP_AUTH_H__
#include "katze-utils.h"
#include <glib-object.h>
G_BEGIN_DECLS
#define KATZE_TYPE_HTTP_AUTH \
(katze_http_auth_get_type ())
#define KATZE_HTTP_AUTH(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), KATZE_TYPE_HTTP_AUTH, KatzeHttpAuth))
#define KATZE_HTTP_AUTH_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), KATZE_TYPE_HTTP_AUTH, KatzeHttpAuthClass))
#define KATZE_IS_HTTP_AUTH(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), KATZE_TYPE_HTTP_AUTH))
#define KATZE_IS_HTTP_AUTH_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), KATZE_TYPE_HTTP_AUTH))
#define KATZE_HTTP_AUTH_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), KATZE_TYPE_HTTP_AUTH, KatzeHttpAuthClass))
typedef struct _KatzeHttpAuth KatzeHttpAuth;
typedef struct _KatzeHttpAuthClass KatzeHttpAuthClass;
GType
katze_http_auth_get_type (void);
G_END_DECLS
#endif /* __KATZE_HTTP_AUTH_H__ */

300
katze/katze-http-cookies.c Normal file
View file

@ -0,0 +1,300 @@
/*
Copyright (C) 2008-2009 Christian Dywan <christian@twotoasts.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#if HAVE_CONFIG_H
#include <config.h>
#endif
#include "katze-http-cookies.h"
#include <stdlib.h>
#include <glib/gi18n.h>
#include <libsoup/soup.h>
#include <gtk/gtk.h>
struct _KatzeHttpCookies
{
GObject parent_instance;
};
struct _KatzeHttpCookiesClass
{
GObjectClass parent_class;
};
static void
katze_http_cookies_session_feature_iface_init (SoupSessionFeatureInterface *iface,
gpointer data);
G_DEFINE_TYPE_WITH_CODE (KatzeHttpCookies, katze_http_cookies, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (SOUP_TYPE_SESSION_FEATURE,
katze_http_cookies_session_feature_iface_init));
/* Cookie jar saving to Mozilla format
Copyright (C) 2008 Xan Lopez <xan@gnome.org>
Copyright (C) 2008 Dan Winship <danw@gnome.org>
Mostly copied from libSoup 2.24, coding style adjusted */
static SoupCookie*
parse_cookie (gchar* line,
time_t now)
{
gchar** result;
SoupCookie *cookie = NULL;
gboolean http_only;
time_t max_age;
gchar* host/*, *is_domain*/, *path, *secure, *expires, *name, *value;
if (g_str_has_prefix (line, "#HttpOnly_"))
{
http_only = TRUE;
line += strlen ("#HttpOnly_");
}
else if (*line == '#' || g_ascii_isspace (*line))
return cookie;
else
http_only = FALSE;
result = g_strsplit (line, "\t", -1);
if (g_strv_length (result) != 7)
goto out;
/* Check this first */
expires = result[4];
max_age = strtoul (expires, NULL, 10) - now;
if (max_age <= 0)
goto out;
host = result[0];
/* is_domain = result[1]; */
path = result[2];
secure = result[3];
name = result[5];
value = result[6];
cookie = soup_cookie_new (name, value, host, path, max_age);
if (strcmp (secure, "FALSE"))
soup_cookie_set_secure (cookie, TRUE);
if (http_only)
soup_cookie_set_http_only (cookie, TRUE);
out:
g_strfreev (result);
return cookie;
}
/* Cookie jar saving to Mozilla format
Copyright (C) 2008 Xan Lopez <xan@gnome.org>
Copyright (C) 2008 Dan Winship <danw@gnome.org>
Mostly copied from libSoup 2.24, coding style adjusted */
static void
parse_line (SoupCookieJar* jar,
gchar* line,
time_t now)
{
SoupCookie* cookie;
if ((cookie = parse_cookie (line, now)))
soup_cookie_jar_add_cookie (jar, cookie);
}
/* Cookie jar saving to Mozilla format
Copyright (C) 2008 Xan Lopez <xan@gnome.org>
Copyright (C) 2008 Dan Winship <danw@gnome.org>
Mostly copied from libSoup 2.24, coding style adjusted */
static void
cookie_jar_load (SoupCookieJar* jar,
const gchar* filename)
{
char* contents = NULL;
gchar* line;
gchar* p;
gsize length = 0;
time_t now = time (NULL);
if (!g_file_get_contents (filename, &contents, &length, NULL))
return;
line = contents;
for (p = contents; *p; p++)
{
/* \r\n comes out as an extra empty line and gets ignored */
if (*p == '\r' || *p == '\n')
{
*p = '\0';
parse_line (jar, line, now);
line = p + 1;
}
}
parse_line (jar, line, now);
g_free (contents);
}
/* Cookie jar saving to Mozilla format
Copyright (C) 2008 Xan Lopez <xan@gnome.org>
Copyright (C) 2008 Dan Winship <danw@gnome.org>
Copied from libSoup 2.24, coding style preserved */
static void
write_cookie (FILE *out, SoupCookie *cookie)
{
fseek (out, 0, SEEK_END);
fprintf (out, "%s%s\t%s\t%s\t%s\t%lu\t%s\t%s\n",
cookie->http_only ? "#HttpOnly_" : "",
cookie->domain,
*cookie->domain == '.' ? "TRUE" : "FALSE",
cookie->path,
cookie->secure ? "TRUE" : "FALSE",
(gulong)soup_date_to_time_t (cookie->expires),
cookie->name,
cookie->value);
}
/* Cookie jar saving to Mozilla format
Copyright (C) 2008 Xan Lopez <xan@gnome.org>
Copyright (C) 2008 Dan Winship <danw@gnome.org>
Copied from libSoup 2.24, coding style preserved */
static void
delete_cookie (const char *filename, SoupCookie *cookie)
{
char *contents = NULL, *line, *p;
gsize length = 0;
FILE *f;
SoupCookie *c;
time_t now = time (NULL);
if (!g_file_get_contents (filename, &contents, &length, NULL))
return;
f = fopen (filename, "w");
if (!f) {
g_free (contents);
return;
}
line = contents;
for (p = contents; *p; p++) {
/* \r\n comes out as an extra empty line and gets ignored */
if (*p == '\r' || *p == '\n') {
*p = '\0';
c = parse_cookie (line, now);
if (!c)
continue;
if (!soup_cookie_equal (cookie, c))
write_cookie (f, c);
line = p + 1;
soup_cookie_free (c);
}
}
c = parse_cookie (line, now);
if (c) {
if (!soup_cookie_equal (cookie, c))
write_cookie (f, c);
soup_cookie_free (c);
}
g_free (contents);
fclose (f);
}
/* Cookie jar saving to Mozilla format
Copyright (C) 2008 Xan Lopez <xan@gnome.org>
Copyright (C) 2008 Dan Winship <danw@gnome.org>
Mostly copied from libSoup 2.24, coding style adjusted */
static void
cookie_jar_changed_cb (SoupCookieJar* jar,
SoupCookie* old_cookie,
SoupCookie* new_cookie,
gchar* filename)
{
GObject* settings;
guint accept_cookies;
if (old_cookie)
delete_cookie (filename, old_cookie);
if (new_cookie)
{
FILE *out;
settings = g_object_get_data (G_OBJECT (jar), "midori-settings");
accept_cookies = katze_object_get_enum (settings, "accept-cookies");
if (accept_cookies == 2 /* MIDORI_ACCEPT_COOKIES_NONE */)
{
soup_cookie_jar_delete_cookie (jar, new_cookie);
}
else if (accept_cookies == 1 /* MIDORI_ACCEPT_COOKIES_SESSION */
&& new_cookie->expires)
{
soup_cookie_jar_delete_cookie (jar, new_cookie);
}
else if (new_cookie->expires)
{
gint age = katze_object_get_int (settings, "maximum-cookie-age");
soup_cookie_set_max_age (new_cookie,
age * SOUP_COOKIE_MAX_AGE_ONE_DAY);
if (!(out = fopen (filename, "a")))
return;
write_cookie (out, new_cookie);
if (fclose (out) != 0)
return;
}
}
}
static void
katze_http_cookies_attach (SoupSessionFeature* feature,
SoupSession* session)
{
SoupSessionFeature* cookie_jar;
gchar* filename;
cookie_jar = soup_session_get_feature (session, SOUP_TYPE_COOKIE_JAR);
g_return_if_fail (cookie_jar != NULL);
filename = g_object_get_data (G_OBJECT (feature), "filename");
g_return_if_fail (filename != NULL);
cookie_jar_load (SOUP_COOKIE_JAR (cookie_jar), filename);
g_signal_connect_data (cookie_jar, "changed",
G_CALLBACK (cookie_jar_changed_cb), g_strdup (filename),
(GClosureNotify)g_free, 0);
}
static void
katze_http_cookies_detach (SoupSessionFeature* feature,
SoupSession* session)
{
/* Nothing to do. */
}
static void
katze_http_cookies_session_feature_iface_init (SoupSessionFeatureInterface *iface,
gpointer data)
{
iface->attach = katze_http_cookies_attach;
iface->detach = katze_http_cookies_detach;
}
static void
katze_http_cookies_class_init (KatzeHttpCookiesClass* class)
{
/* Nothing to do. */
}
static void
katze_http_cookies_init (KatzeHttpCookies* http_cookies)
{
/* Nothing to do. */
}

View file

@ -0,0 +1,42 @@
/*
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_HTTP_COOKIES_H__
#define __KATZE_HTTP_COOKIES_H__
#include "katze-utils.h"
#include <glib-object.h>
G_BEGIN_DECLS
#define KATZE_TYPE_HTTP_COOKIES \
(katze_http_cookies_get_type ())
#define KATZE_HTTP_COOKIES(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), KATZE_TYPE_HTTP_COOKIES, KatzeHttpCookies))
#define KATZE_HTTP_COOKIES_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), KATZE_TYPE_HTTP_COOKIES, KatzeHttpCookiesClass))
#define KATZE_IS_HTTP_COOKIES(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), KATZE_TYPE_HTTP_COOKIES))
#define KATZE_IS_HTTP_COOKIES_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), KATZE_TYPE_HTTP_COOKIES))
#define KATZE_HTTP_COOKIES_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), KATZE_TYPE_HTTP_COOKIES, KatzeHttpCookiesClass))
typedef struct _KatzeHttpCookies KatzeHttpCookies;
typedef struct _KatzeHttpCookiesClass KatzeHttpCookiesClass;
GType
katze_http_cookies_get_type (void);
G_END_DECLS
#endif /* __KATZE_HTTP_COOKIES_H__ */

530
katze/katze-item.c Normal file
View file

@ -0,0 +1,530 @@
/*
Copyright (C) 2008 Christian Dywan <christian@twotoasts.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#include "katze-item.h"
#include "katze-utils.h"
#include <glib/gi18n.h>
/**
* SECTION:katze-item
* @short_description: A useful item
* @see_also: #KatzeArray
*
* #KatzeItem is a particularly useful item that provides
* several commonly needed properties.
*/
G_DEFINE_TYPE (KatzeItem, katze_item, G_TYPE_OBJECT)
enum
{
PROP_0,
PROP_NAME,
PROP_TEXT,
PROP_URI,
PROP_ICON,
PROP_TOKEN,
PROP_ADDED,
PROP_PARENT
};
static void
katze_item_finalize (GObject* object);
static void
katze_item_set_property (GObject* object,
guint prop_id,
const GValue* value,
GParamSpec* pspec);
static void
katze_item_get_property (GObject* object,
guint prop_id,
GValue* value,
GParamSpec* pspec);
static void
katze_item_class_init (KatzeItemClass* class)
{
GObjectClass* gobject_class;
GParamFlags flags;
gobject_class = G_OBJECT_CLASS (class);
gobject_class->finalize = katze_item_finalize;
gobject_class->set_property = katze_item_set_property;
gobject_class->get_property = katze_item_get_property;
flags = G_PARAM_READWRITE | G_PARAM_CONSTRUCT;
g_object_class_install_property (gobject_class,
PROP_NAME,
g_param_spec_string (
"name",
"Name",
"The name of the item",
NULL,
flags));
g_object_class_install_property (gobject_class,
PROP_TEXT,
g_param_spec_string (
"text",
"Text",
"The descriptive text of the item",
NULL,
flags));
g_object_class_install_property (gobject_class,
PROP_URI,
g_param_spec_string (
"uri",
"URI",
"The URI of the item",
NULL,
flags));
g_object_class_install_property (gobject_class,
PROP_ICON,
g_param_spec_string (
"icon",
"Icon",
"The icon of the item",
NULL,
flags));
g_object_class_install_property (gobject_class,
PROP_TOKEN,
g_param_spec_string (
"token",
"Token",
"The token of the item",
NULL,
flags));
g_object_class_install_property (gobject_class,
PROP_ADDED,
g_param_spec_int64 (
"added",
"Added",
"When the item was added",
G_MININT64,
G_MAXINT64,
0,
flags));
/**
* KatzeItem:parent:
*
* The parent of the item.
*
* Since: 0.1.2
*/
g_object_class_install_property (gobject_class,
PROP_PARENT,
g_param_spec_object (
"parent",
"Parent",
"The parent of the item",
G_TYPE_OBJECT,
flags));
class->copy = NULL;
}
static void
katze_item_init (KatzeItem* item)
{
/* Nothing to do here */
}
static void
katze_item_finalize (GObject* object)
{
KatzeItem* item = KATZE_ITEM (object);
g_free (item->name);
g_free (item->text);
g_free (item->uri);
g_free (item->icon);
g_free (item->token);
G_OBJECT_CLASS (katze_item_parent_class)->finalize (object);
}
static void
katze_item_set_property (GObject* object,
guint prop_id,
const GValue* value,
GParamSpec* pspec)
{
KatzeItem* item = KATZE_ITEM (object);
switch (prop_id)
{
case PROP_NAME:
katze_assign (item->name, g_value_dup_string (value));
break;
case PROP_TEXT:
katze_assign (item->text, g_value_dup_string (value));
break;
case PROP_URI:
katze_assign (item->uri, g_value_dup_string (value));
break;
case PROP_ICON:
katze_assign (item->icon, g_value_dup_string (value));
break;
case PROP_TOKEN:
katze_assign (item->token, g_value_dup_string (value));
break;
case PROP_ADDED:
item->added = g_value_get_int64 (value);
break;
case PROP_PARENT:
katze_item_set_parent (item, g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
katze_item_get_property (GObject* object,
guint prop_id,
GValue* value,
GParamSpec* pspec)
{
KatzeItem* item = KATZE_ITEM (object);
switch (prop_id)
{
case PROP_NAME:
g_value_set_string (value, item->name);
break;
case PROP_TEXT:
g_value_set_string (value, item->text);
break;
case PROP_URI:
g_value_set_string (value, item->uri);
break;
case PROP_ICON:
g_value_set_string (value, item->icon);
break;
case PROP_TOKEN:
g_value_set_string (value, item->token);
break;
case PROP_ADDED:
g_value_set_int64 (value, item->added);
break;
case PROP_PARENT:
g_value_set_object (value, item->parent);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
/**
* katze_item_new:
*
* Creates a new #KatzeItem.
*
* Return value: a new #KatzeItem
**/
KatzeItem*
katze_item_new (void)
{
KatzeItem* item = g_object_new (KATZE_TYPE_ITEM, NULL);
return item;
}
/**
* katze_item_get_name:
* @item: a #KatzeItem
*
* Retrieves the name of @item.
*
* Return value: the name of the item
**/
const gchar*
katze_item_get_name (KatzeItem* item)
{
g_return_val_if_fail (KATZE_IS_ITEM (item), NULL);
return item->name;
}
/**
* katze_item_set_name:
* @item: a #KatzeItem
* @name: a string
*
* Sets the name of @item.
**/
void
katze_item_set_name (KatzeItem* item,
const gchar* name)
{
g_return_if_fail (KATZE_IS_ITEM (item));
katze_assign (item->name, g_strdup (name));
g_object_notify (G_OBJECT (item), "name");
}
/**
* katze_item_get_text:
* @item: a #KatzeItem
*
* Retrieves the descriptive text of @item.
*
* Return value: the text of the item
**/
const gchar*
katze_item_get_text (KatzeItem* item)
{
g_return_val_if_fail (KATZE_IS_ITEM (item), NULL);
return item->text;
}
/**
* katze_item_set_text:
* @item: a #KatzeItem
* @description: a string
*
* Sets the descriptive text of @item.
**/
void
katze_item_set_text (KatzeItem* item,
const gchar* text)
{
g_return_if_fail (KATZE_IS_ITEM (item));
katze_assign (item->text, g_strdup (text));
g_object_notify (G_OBJECT (item), "text");
}
/**
* katze_item_get_uri:
* @item: a #KatzeItem
*
* Retrieves the URI of @item.
*
* Return value: the URI of the item
**/
const gchar*
katze_item_get_uri (KatzeItem* item)
{
g_return_val_if_fail (KATZE_IS_ITEM (item), NULL);
return item->uri;
}
/**
* katze_item_set_uri:
* @item: a #KatzeItem
* @uri: a string
*
* Sets the URI of @item.
**/
void
katze_item_set_uri (KatzeItem* item,
const gchar* uri)
{
g_return_if_fail (KATZE_IS_ITEM (item));
katze_assign (item->uri, g_strdup (uri));
g_object_notify (G_OBJECT (item), "uri");
}
/**
* katze_item_get_icon:
* @item: a #KatzeItem
*
* Retrieves the icon of @item.
*
* Return value: the icon of the item
**/
const gchar*
katze_item_get_icon (KatzeItem* item)
{
g_return_val_if_fail (KATZE_IS_ITEM (item), NULL);
return item->icon;
}
/**
* katze_item_set_icon:
* @item: a #KatzeItem
* @icon: a string
*
* Sets the icon of @item.
**/
void
katze_item_set_icon (KatzeItem* item,
const gchar* icon)
{
g_return_if_fail (KATZE_IS_ITEM (item));
katze_assign (item->icon, g_strdup (icon));
g_object_notify (G_OBJECT (item), "icon");
}
/**
* katze_item_get_token:
* @item: a #KatzeItem
*
* Retrieves the token of @item.
*
* Return value: the token of the item
**/
const gchar*
katze_item_get_token (KatzeItem* item)
{
g_return_val_if_fail (KATZE_IS_ITEM (item), NULL);
return item->token;
}
/**
* katze_item_set_token:
* @item: a #KatzeItem
* @token: a string
*
* Sets the token of @item.
**/
void
katze_item_set_token (KatzeItem* item,
const gchar* token)
{
g_return_if_fail (KATZE_IS_ITEM (item));
katze_assign (item->token, g_strdup (token));
g_object_notify (G_OBJECT (item), "token");
}
/**
* katze_item_get_added:
* @item: a #KatzeItem
*
* Determines when @item was added.
*
* Return value: a timestamp
**/
gint64
katze_item_get_added (KatzeItem* item)
{
g_return_val_if_fail (KATZE_IS_ITEM (item), 0);
return item->added;
}
/**
* katze_item_set_added:
* @item: a #KatzeItem
* @added: a timestamp
*
* Sets when @item was added.
**/
void
katze_item_set_added (KatzeItem* item,
gint64 added)
{
g_return_if_fail (KATZE_IS_ITEM (item));
item->added = added;
g_object_notify (G_OBJECT (item), "added");
}
/**
* katze_item_get_parent:
* @item: a #KatzeItem
*
* Determines the parent of @item.
*
* Since 0.1.2 you can monitor the "parent" property.
*
* Return value: the parent of the item
**/
gpointer
katze_item_get_parent (KatzeItem* item)
{
g_return_val_if_fail (KATZE_IS_ITEM (item), NULL);
return item->parent;
}
/**
* katze_item_set_parent:
* @item: a #KatzeItem
* @parent: the new parent
*
* Sets the parent of @item.
*
* This is intended for item container implementations. Notably
* the new parent will not be notified of the change.
*
* Since 0.1.2 you can monitor the "parent" property, so unsetting
* the parent is actually safe if the parent supports it.
**/
void
katze_item_set_parent (KatzeItem* item,
gpointer parent)
{
g_return_if_fail (KATZE_IS_ITEM (item));
g_return_if_fail (!parent || G_IS_OBJECT (parent));
if (parent)
g_object_ref (parent);
katze_object_assign (item->parent, parent);
g_object_notify (G_OBJECT (item), "parent");
}
/**
* katze_item_copy:
* @item: a #KatzeItem
*
* Creates an exact copy of @item.
*
* Note that subclass specific features will only
* be preserved if the class implements it.
*
* Return value: a new #KatzeItem
*
* Since: 0.1.3
**/
KatzeItem*
katze_item_copy (KatzeItem* item)
{
KatzeItem* copy;
KatzeItemClass* class;
g_return_val_if_fail (KATZE_IS_ITEM (item), NULL);
copy = g_object_new (G_OBJECT_TYPE (item),
"name", item->name,
"text", item->text,
"uri", item->uri,
"icon", item->icon,
"token", item->token,
"added", item->added,
"parent", item->parent,
NULL);
class = KATZE_ITEM_GET_CLASS (item);
return class->copy ? class->copy (copy) : copy;
}

117
katze/katze-item.h Normal file
View file

@ -0,0 +1,117 @@
/*
Copyright (C) 2008 Christian Dywan <christian@twotoasts.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#ifndef __KATZE_ITEM_H__
#define __KATZE_ITEM_H__
#include <glib-object.h>
G_BEGIN_DECLS
#define KATZE_TYPE_ITEM \
(katze_item_get_type ())
#define KATZE_ITEM(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), KATZE_TYPE_ITEM, KatzeItem))
#define KATZE_ITEM_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), KATZE_TYPE_ITEM, KatzeItemClass))
#define KATZE_IS_ITEM(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), KATZE_TYPE_ITEM))
#define KATZE_IS_ITEM_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), KATZE_TYPE_ITEM))
#define KATZE_ITEM_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), KATZE_TYPE_ITEM, KatzeItemClass))
typedef struct _KatzeItem KatzeItem;
typedef struct _KatzeItemClass KatzeItemClass;
struct _KatzeItem
{
GObject parent_instance;
gchar* name;
gchar* text;
gchar* uri;
gchar* icon;
gchar* token;
gint64 added;
KatzeItem* parent;
};
struct _KatzeItemClass
{
GObjectClass parent_class;
gpointer
(*copy) (KatzeItem* item);
};
GType
katze_item_get_type (void);
KatzeItem*
katze_item_new (void);
const gchar*
katze_item_get_name (KatzeItem* item);
void
katze_item_set_name (KatzeItem* item,
const gchar* name);
const gchar*
katze_item_get_text (KatzeItem* item);
void
katze_item_set_text (KatzeItem* item,
const gchar* text);
const gchar*
katze_item_get_uri (KatzeItem* item);
void
katze_item_set_uri (KatzeItem* item,
const gchar* uri);
const gchar*
katze_item_get_icon (KatzeItem* item);
void
katze_item_set_icon (KatzeItem* item,
const gchar* icon);
const gchar*
katze_item_get_token (KatzeItem* item);
void
katze_item_set_token (KatzeItem* item,
const gchar* token);
gint64
katze_item_get_added (KatzeItem* item);
void
katze_item_set_added (KatzeItem* item,
gint64 added);
gpointer
katze_item_get_parent (KatzeItem* item);
void
katze_item_set_parent (KatzeItem* item,
gpointer parent);
KatzeItem*
katze_item_copy (KatzeItem* item);
G_END_DECLS
#endif /* __MIDORI_WEB_ITEM_H__ */

598
katze/katze-net.c Normal file
View file

@ -0,0 +1,598 @@
/*
Copyright (C) 2008-2009 Christian Dywan <christian@twotoasts.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#if HAVE_CONFIG_H
#include <config.h>
#endif
#include "katze-net.h"
#include <libsoup/soup.h>
#include <webkit/webkit.h>
struct _KatzeNet
{
GObject parent_instance;
GHashTable* memory;
gchar* cache_path;
guint cache_size;
SoupSession* session;
};
struct _KatzeNetClass
{
GObjectClass parent_class;
};
G_DEFINE_TYPE (KatzeNet, katze_net, G_TYPE_OBJECT)
static void
katze_net_finalize (GObject* object);
static void
katze_net_class_init (KatzeNetClass* class)
{
GObjectClass* gobject_class;
gobject_class = G_OBJECT_CLASS (class);
gobject_class->finalize = katze_net_finalize;
}
static void
katze_net_object_maybe_unref (gpointer object)
{
if (object)
g_object_unref (object);
}
static void
katze_net_init (KatzeNet* net)
{
net->memory = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, katze_net_object_maybe_unref);
net->cache_path = g_build_filename (g_get_user_cache_dir (),
PACKAGE_NAME, NULL);
net->session = webkit_get_default_session ();
}
static void
katze_net_finalize (GObject* object)
{
KatzeNet* net = KATZE_NET (object);
g_hash_table_destroy (net->memory);
katze_assign (net->cache_path, NULL);
G_OBJECT_CLASS (katze_net_parent_class)->finalize (object);
}
/**
* katze_net_new:
*
* Instantiates a new #KatzeNet instance.
*
* Return value: a new #KatzeNet
**/
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;
}
/**
* katze_net_get_session:
*
* Retrieves the session of the net.
*
* Return value: a session, or %NULL
*
* Since: 0.1.3
**/
gpointer
katze_net_get_session (KatzeNet* net)
{
g_return_val_if_fail (KATZE_IS_NET (net), NULL);
return net->session;
}
typedef struct
{
KatzeNet* net;
KatzeNetStatusCb status_cb;
KatzeNetTransferCb transfer_cb;
gpointer user_data;
KatzeNetRequest* request;
} KatzeNetPriv;
static void
katze_net_priv_free (KatzeNetPriv* priv)
{
KatzeNetRequest* request;
request = priv->request;
g_free (request->uri);
g_free (request->mime_type);
g_free (request->data);
g_free (request);
g_free (priv);
}
static 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;
if (subfolder)
cache_path = g_build_filename (net->cache_path, subfolder, NULL);
else
cache_path = net->cache_path;
g_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)
g_free (cache_path);
return cached_path;
}
static void
katze_net_got_body_cb (SoupMessage* msg,
KatzeNetPriv* priv);
static void
katze_net_got_headers_cb (SoupMessage* msg,
KatzeNetPriv* priv)
{
KatzeNetRequest* request;
request = priv->request;
switch (msg->status_code)
{
case 200:
request->status = KATZE_NET_VERIFIED;
break;
case 301:
request->status = KATZE_NET_MOVED;
break;
default:
request->status = KATZE_NET_NOT_FOUND;
}
if (!priv->status_cb (request, priv->user_data))
{
g_signal_handlers_disconnect_by_func (msg, katze_net_got_headers_cb, priv);
g_signal_handlers_disconnect_by_func (msg, katze_net_got_body_cb, priv);
soup_session_cancel_message (priv->net->session, msg, 1);
}
}
static void
katze_net_got_body_cb (SoupMessage* msg,
KatzeNetPriv* priv)
{
KatzeNetRequest* request;
#if 0
gchar* filename;
FILE* fp;
#endif
request = priv->request;
if (msg->response_body->length > 0)
{
#if 0
/* FIXME: Caching */
filename = katze_net_get_cached_path (net, request->uri, NULL);
if ((fp = fopen (filename, "wb")))
{
fwrite (msg->response_body->data,
1, msg->response_body->length, fp);
fclose (fp);
}
g_free (filename);
#endif
request->data = g_memdup (msg->response_body->data,
msg->response_body->length);
request->length = msg->response_body->length;
}
priv->transfer_cb (request, priv->user_data);
}
static void
katze_net_finished_cb (SoupMessage* msg,
KatzeNetPriv* priv)
{
katze_net_priv_free (priv);
}
static gboolean
katze_net_local_cb (KatzeNetPriv* priv)
{
KatzeNetRequest* request;
gchar* filename;
gchar* contents;
gsize length;
request = priv->request;
filename = g_filename_from_uri (request->uri, NULL, NULL);
if (!filename || !g_file_test (filename, G_FILE_TEST_EXISTS))
{
request->status = KATZE_NET_NOT_FOUND;
if (priv->status_cb)
priv->status_cb (request, priv->user_data);
katze_net_priv_free (priv);
return FALSE;
}
request->status = KATZE_NET_VERIFIED;
if (priv->status_cb && !priv->status_cb (request, priv->user_data))
{
katze_net_priv_free (priv);
return FALSE;
}
if (!priv->transfer_cb)
{
katze_net_priv_free (priv);
return FALSE;
}
contents = NULL;
if (!g_file_get_contents (filename, &contents, &length, NULL))
{
request->status = KATZE_NET_FAILED;
priv->transfer_cb (request, priv->user_data);
katze_net_priv_free (priv);
return FALSE;
}
request->status = KATZE_NET_DONE;
request->data = contents;
request->length = length;
priv->transfer_cb (request, priv->user_data);
katze_net_priv_free (priv);
return FALSE;
}
static gboolean
katze_net_default_cb (KatzeNetPriv* priv)
{
KatzeNetRequest* request;
request = priv->request;
request->status = KATZE_NET_NOT_FOUND;
if (priv->status_cb)
priv->status_cb (request, priv->user_data);
katze_net_priv_free (priv);
return FALSE;
}
/**
* katze_net_load_uri:
* @net: a #KatzeNet
* @uri: an URI string
* @status_cb: function to call for status information
* @transfer_cb: function to call upon transfer
* @user_data: data to pass to the callback
*
* Requests a transfer of @uri.
*
* @status_cb will be called when the status of @uri
* is verified. The specified callback may be called
* multiple times unless cancelled.
*
* @transfer_cb will be called when the data @uri is
* pointing to was transferred. Note that even a failed
* transfer may transfer data.
*
* @status_cb will always to be called at least once.
**/
void
katze_net_load_uri (KatzeNet* net,
const gchar* uri,
KatzeNetStatusCb status_cb,
KatzeNetTransferCb transfer_cb,
gpointer user_data)
{
KatzeNetRequest* request;
KatzeNetPriv* priv;
SoupMessage* msg;
g_return_if_fail (KATZE_IS_NET (net));
g_return_if_fail (uri != NULL);
if (!status_cb && !transfer_cb)
return;
request = g_new0 (KatzeNetRequest, 1);
request->uri = g_strdup (uri);
request->mime_type = NULL;
request->data = NULL;
priv = g_new0 (KatzeNetPriv, 1);
priv->net = net;
priv->status_cb = status_cb;
priv->transfer_cb = transfer_cb;
priv->user_data = user_data;
priv->request = request;
if (g_str_has_prefix (uri, "http://") || g_str_has_prefix (uri, "https://"))
{
msg = soup_message_new ("GET", uri);
if (status_cb)
g_signal_connect (msg, "got-headers",
G_CALLBACK (katze_net_got_headers_cb), priv);
if (transfer_cb)
g_signal_connect (msg, "got-body",
G_CALLBACK (katze_net_got_body_cb), priv);
g_signal_connect (msg, "finished",
G_CALLBACK (katze_net_finished_cb), priv);
soup_session_queue_message (net->session, msg, NULL, NULL);
return;
}
if (g_str_has_prefix (uri, "file://"))
{
g_idle_add ((GSourceFunc)katze_net_local_cb, priv);
return;
}
g_idle_add ((GSourceFunc)katze_net_default_cb, priv);
}
typedef struct
{
KatzeNet* net;
gchar* icon_file;
KatzeNetIconCb icon_cb;
GtkWidget* widget;
gpointer user_data;
} KatzeNetIconPriv;
static void
katze_net_icon_priv_free (KatzeNetIconPriv* priv)
{
g_free (priv->icon_file);
if (priv->widget)
g_object_unref (priv->widget);
g_free (priv);
}
static gboolean
katze_net_icon_status_cb (KatzeNetRequest* request,
KatzeNetIconPriv* priv)
{
switch (request->status)
{
case KATZE_NET_VERIFIED:
if (request->mime_type &&
!g_str_has_prefix (request->mime_type, "image/"))
{
katze_net_icon_priv_free (priv);
return FALSE;
}
break;
case KATZE_NET_MOVED:
break;
default:
katze_net_icon_priv_free (priv);
return FALSE;
}
return TRUE;
}
static void
katze_net_icon_transfer_cb (KatzeNetRequest* request,
KatzeNetIconPriv* priv)
{
GdkPixbuf* pixbuf;
FILE* fp;
GdkPixbuf* pixbuf_scaled;
gint icon_width, icon_height;
size_t ret;
if (request->status == KATZE_NET_MOVED)
return;
pixbuf = NULL;
if (request->data)
{
if ((fp = fopen (priv->icon_file, "wb")))
{
ret = fwrite (request->data, 1, request->length, fp);
fclose (fp);
if ((ret - request->length) != 0)
{
g_warning ("Error writing to file %s "
"in katze_net_icon_transfer_cb()", priv->icon_file);
}
pixbuf = gdk_pixbuf_new_from_file (priv->icon_file, NULL);
}
else
pixbuf = katze_pixbuf_new_from_buffer ((guchar*)request->data,
request->length, request->mime_type, NULL);
if (pixbuf)
g_object_ref (pixbuf);
g_hash_table_insert (priv->net->memory,
g_strdup (priv->icon_file), pixbuf);
}
if (!priv->icon_cb)
{
katze_net_icon_priv_free (priv);
return;
}
if (!pixbuf)
{
if (priv->widget)
pixbuf = gtk_widget_render_icon (priv->widget,
GTK_STOCK_FILE, GTK_ICON_SIZE_MENU, NULL);
else
{
priv->icon_cb (NULL, priv->user_data);
katze_net_icon_priv_free (priv);
return;
}
}
gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &icon_width, &icon_height);
pixbuf_scaled = gdk_pixbuf_scale_simple (pixbuf, icon_width, icon_height,
GDK_INTERP_BILINEAR);
g_object_unref (pixbuf);
priv->icon_cb (pixbuf_scaled, priv->user_data);
katze_net_icon_priv_free (priv);
}
/**
* katze_net_load_icon:
* @net: a #KatzeNet
* @uri: an URI string, or %NULL
* @icon_cb: function to call upon completion
* @widget: a related #GtkWidget, or %NULL
* @user_data: data to pass to the callback
*
* Requests a transfer of an icon for @uri. This is
* implemented by looking for a favicon.ico, an
* image according to the file type or even a
* generated icon. The provided icon is intended
* for user interfaces and not guaranteed to be
* the same over multiple requests, plus it may
* be scaled to fit the menu icon size.
*
* Pass a valid #GtkWidget to @widget if you want
* a themed default icon in case of a missing icon,
* otherwise %NULL will be returned in that case.
*
* The caller is expected to use the returned icon
* and update it if @icon_cb is called.
*
* Depending on whether the icon was previously
* cached or @uri is a local resource, the returned
* icon may already be the final one.
*
* Note that both the returned #GdkPixbuf and the
* icon passed to @icon_cb are newly allocated and
* the caller owns the reference.
*
* Since 0.1.2 @widget can be %NULL.
*
* Return value: a #GdkPixbuf, or %NULL
**/
GdkPixbuf*
katze_net_load_icon (KatzeNet* net,
const gchar* uri,
KatzeNetIconCb icon_cb,
GtkWidget* widget,
gpointer user_data)
{
guint i;
KatzeNetIconPriv* priv;
gchar* icon_uri;
gchar* icon_file;
GdkPixbuf* pixbuf;
gint icon_width, icon_height;
GdkPixbuf* pixbuf_scaled;
g_return_val_if_fail (KATZE_IS_NET (net), NULL);
g_return_val_if_fail (!widget || GTK_IS_WIDGET (widget), NULL);
pixbuf = NULL;
if (uri && (g_str_has_prefix (uri, "http://") ||
g_str_has_prefix (uri, "https://")))
{
i = 8;
while (uri[i] != '\0' && uri[i] != '/')
i++;
if (uri[i] == '/')
{
icon_uri = g_strdup (uri);
icon_uri[i] = '\0';
icon_uri = g_strdup_printf ("%s/favicon.ico", icon_uri);
}
else
icon_uri = g_strdup_printf ("%s/favicon.ico", uri);
icon_file = katze_net_get_cached_path (net, icon_uri, "icons");
if (g_hash_table_lookup_extended (net->memory,
icon_file, NULL, (gpointer)&pixbuf))
{
g_free (icon_file);
if (pixbuf)
g_object_ref (pixbuf);
}
else if ((pixbuf = gdk_pixbuf_new_from_file (icon_file, NULL)))
g_free (icon_file);
/* If the called doesn't provide an icon callback,
we assume there is no interest in loading an un-cached icon. */
else if (icon_cb)
{
priv = g_new0 (KatzeNetIconPriv, 1);
priv->net = net;
priv->icon_file = icon_file;
priv->icon_cb = icon_cb;
priv->widget = widget ? g_object_ref (widget) : NULL;
priv->user_data = user_data;
katze_net_load_uri (net, icon_uri,
(KatzeNetStatusCb)katze_net_icon_status_cb,
(KatzeNetTransferCb)katze_net_icon_transfer_cb, priv);
}
g_free (icon_uri);
}
if (!pixbuf)
{
if (widget)
pixbuf = gtk_widget_render_icon (widget,
GTK_STOCK_FILE, GTK_ICON_SIZE_MENU, NULL);
else
return NULL;
}
gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &icon_width, &icon_height);
pixbuf_scaled = gdk_pixbuf_scale_simple (pixbuf, icon_width, icon_height,
GDK_INTERP_BILINEAR);
g_object_unref (pixbuf);
return pixbuf_scaled;
}

89
katze/katze-net.h Normal file
View file

@ -0,0 +1,89 @@
/*
Copyright (C) 2008 Christian Dywan <christian@twotoasts.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#ifndef __KATZE_NET_H__
#define __KATZE_NET_H__
#include "katze-utils.h"
#include <gtk/gtk.h>
G_BEGIN_DECLS
#define KATZE_TYPE_NET \
(katze_net_get_type ())
#define KATZE_NET(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), KATZE_TYPE_NET, KatzeNet))
#define KATZE_NET_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), KATZE_TYPE_NET, KatzeNetClass))
#define KATZE_IS_NET(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), KATZE_TYPE_NET))
#define KATZE_IS_NET_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), KATZE_TYPE_NET))
#define KATZE_NET_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), KATZE_TYPE_NET, KatzeNetClass))
typedef struct _KatzeNet KatzeNet;
typedef struct _KatzeNetClass KatzeNetClass;
GType
katze_net_get_type (void);
KatzeNet*
katze_net_new (void);
gpointer
katze_net_get_session (KatzeNet* net);
typedef enum
{
KATZE_NET_VERIFIED,
KATZE_NET_MOVED,
KATZE_NET_NOT_FOUND,
KATZE_NET_FAILED,
KATZE_NET_DONE
} KatzeNetStatus;
typedef struct
{
gchar* uri;
KatzeNetStatus status;
gchar* mime_type;
gchar* data;
gint64 length;
} KatzeNetRequest;
typedef gboolean (*KatzeNetStatusCb) (KatzeNetRequest* request,
gpointer user_data);
typedef void (*KatzeNetTransferCb) (KatzeNetRequest* request,
gpointer user_data);
void
katze_net_load_uri (KatzeNet* net,
const gchar* uri,
KatzeNetStatusCb status_cb,
KatzeNetTransferCb transfer_cb,
gpointer user_data);
typedef void (*KatzeNetIconCb) (GdkPixbuf* icon,
gpointer user_data);
GdkPixbuf*
katze_net_load_icon (KatzeNet* net,
const gchar* uri,
KatzeNetIconCb icon_cb,
GtkWidget* widget,
gpointer user_data);
G_END_DECLS
#endif /* __KATZE_NET_H__ */

View file

@ -0,0 +1,134 @@
/*
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);
}

View file

@ -0,0 +1,43 @@
/*
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_END_DECLS
#endif /* __KATZE_SEPARATOR_ACTION_H__ */

919
katze/katze-throbber.c Normal file
View file

@ -0,0 +1,919 @@
/*
Copyright (C) 2007-2008 Christian Dywan <christian@twotoasts.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#include "katze-throbber.h"
#include "katze-utils.h"
#include <glib/gi18n.h>
#include <math.h>
struct _KatzeThrobber
{
GtkMisc parent_instance;
GtkIconSize icon_size;
gchar* icon_name;
GdkPixbuf* pixbuf;
gchar* stock_id;
gboolean animated;
gchar* static_icon_name;
GdkPixbuf* static_pixbuf;
gchar* static_stock_id;
gint index;
gint timer_id;
gint width;
gint height;
};
G_DEFINE_TYPE (KatzeThrobber, katze_throbber, GTK_TYPE_MISC);
enum
{
PROP_0,
PROP_ICON_SIZE,
PROP_ICON_NAME,
PROP_PIXBUF,
PROP_ANIMATED,
PROP_STATIC_ICON_NAME,
PROP_STATIC_PIXBUF,
PROP_STATIC_STOCK_ID
};
static void
katze_throbber_dispose (GObject* object);
static void
katze_throbber_set_property (GObject* object,
guint prop_id,
const GValue* value,
GParamSpec* pspec);
static void
katze_throbber_get_property (GObject* object,
guint prop_id,
GValue* value,
GParamSpec* pspec);
static void
katze_throbber_destroy (GtkObject* object);
static void
katze_throbber_realize (GtkWidget* widget);
static void
katze_throbber_unrealize (GtkWidget* widget);
static void
katze_throbber_map (GtkWidget* widget);
static void
katze_throbber_unmap (GtkWidget* widget);
static void
katze_throbber_style_set (GtkWidget* widget,
GtkStyle* style);
static void
katze_throbber_screen_changed (GtkWidget* widget,
GdkScreen* screen_prev);
static void
katze_throbber_size_request (GtkWidget* widget,
GtkRequisition* requisition);
static gboolean
katze_throbber_expose_event (GtkWidget* widget,
GdkEventExpose* event);
static void
icon_theme_changed (KatzeThrobber* throbber);
static gboolean
katze_throbber_timeout (KatzeThrobber* throbber);
static void
katze_throbber_timeout_destroy (KatzeThrobber* throbber);
static void
katze_throbber_class_init (KatzeThrobberClass* class)
{
GObjectClass* gobject_class = G_OBJECT_CLASS (class);
gobject_class->dispose = katze_throbber_dispose;
gobject_class->set_property = katze_throbber_set_property;
gobject_class->get_property = katze_throbber_get_property;
GtkObjectClass* object_class = GTK_OBJECT_CLASS (class);
object_class->destroy = katze_throbber_destroy;
GtkWidgetClass* widget_class = GTK_WIDGET_CLASS (class);
widget_class->realize = katze_throbber_realize;
widget_class->unrealize = katze_throbber_unrealize;
widget_class->map = katze_throbber_map;
widget_class->unmap = katze_throbber_unmap;
widget_class->style_set = katze_throbber_style_set;
widget_class->screen_changed = katze_throbber_screen_changed;
widget_class->size_request = katze_throbber_size_request;
widget_class->expose_event = katze_throbber_expose_event;
GParamFlags flags = G_PARAM_READWRITE | G_PARAM_CONSTRUCT;
g_object_class_install_property (gobject_class,
PROP_ICON_SIZE,
g_param_spec_int (
"icon-size",
"Icon size",
"Symbolic size to use for the animation",
0, G_MAXINT, GTK_ICON_SIZE_MENU,
flags));
g_object_class_install_property (gobject_class,
PROP_ICON_NAME,
g_param_spec_string (
"icon-name",
"Icon Name",
"The name of an icon containing animation frames",
"process-working",
flags));
g_object_class_install_property (gobject_class,
PROP_PIXBUF,
g_param_spec_object (
"pixbuf",
"Pixbuf",
"A GdkPixbuf containing animation frames",
GDK_TYPE_PIXBUF,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_ANIMATED,
g_param_spec_boolean (
"animated",
"Animated",
"Whether the throbber should be animated",
FALSE,
flags));
g_object_class_install_property (gobject_class,
PROP_STATIC_ICON_NAME,
g_param_spec_string (
"static-icon-name",
"Static Icon Name",
"The name of an icon to be used as the static image",
NULL,
flags));
g_object_class_install_property (gobject_class,
PROP_PIXBUF,
g_param_spec_object (
"static-pixbuf",
"Static Pixbuf",
"A GdkPixbuf to be used as the static image",
GDK_TYPE_PIXBUF,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_STATIC_STOCK_ID,
g_param_spec_string (
"static-stock-id",
"Static Stock ID",
"The stock ID of an icon to be used as the static image",
NULL,
flags));
}
static void
katze_throbber_init (KatzeThrobber *throbber)
{
GTK_WIDGET_SET_FLAGS (throbber, GTK_NO_WINDOW);
throbber->timer_id = -1;
}
static void
katze_throbber_dispose (GObject* object)
{
KatzeThrobber* throbber = KATZE_THROBBER (object);
if (G_UNLIKELY (throbber->timer_id >= 0))
g_source_remove (throbber->timer_id);
(*G_OBJECT_CLASS (katze_throbber_parent_class)->dispose) (object);
}
static void
katze_throbber_destroy (GtkObject* object)
{
KatzeThrobber* throbber = KATZE_THROBBER (object);
katze_assign (throbber->icon_name, NULL);
katze_object_assign (throbber->pixbuf, NULL);
katze_assign (throbber->static_icon_name, NULL);
katze_object_assign (throbber->static_pixbuf, NULL);
katze_assign (throbber->static_stock_id, NULL);
GTK_OBJECT_CLASS (katze_throbber_parent_class)->destroy (object);
}
static void
katze_throbber_set_property (GObject* object,
guint prop_id,
const GValue* value,
GParamSpec* pspec)
{
KatzeThrobber* throbber = KATZE_THROBBER (object);
switch (prop_id)
{
case PROP_ICON_SIZE:
katze_throbber_set_icon_size (throbber, g_value_get_int (value));
break;
case PROP_ICON_NAME:
katze_throbber_set_icon_name (throbber, g_value_get_string (value));
break;
case PROP_PIXBUF:
katze_throbber_set_pixbuf (throbber, g_value_get_object (value));
break;
case PROP_ANIMATED:
katze_throbber_set_animated (throbber, g_value_get_boolean (value));
break;
case PROP_STATIC_ICON_NAME:
katze_throbber_set_static_icon_name (throbber, g_value_get_string (value));
break;
case PROP_STATIC_PIXBUF:
katze_throbber_set_static_pixbuf (throbber, g_value_get_object (value));
break;
case PROP_STATIC_STOCK_ID:
katze_throbber_set_static_stock_id (throbber, g_value_get_string (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
katze_throbber_get_property (GObject* object,
guint prop_id,
GValue* value,
GParamSpec* pspec)
{
KatzeThrobber* throbber = KATZE_THROBBER (object);
switch (prop_id)
{
case PROP_ICON_SIZE:
g_value_set_int (value, katze_throbber_get_icon_size (throbber));
break;
case PROP_ICON_NAME:
g_value_set_string (value, katze_throbber_get_icon_name (throbber));
break;
case PROP_PIXBUF:
g_value_set_object (value, katze_throbber_get_pixbuf (throbber));
break;
case PROP_ANIMATED:
g_value_set_boolean (value, katze_throbber_get_animated (throbber));
break;
case PROP_STATIC_ICON_NAME:
g_value_set_string (value, katze_throbber_get_static_icon_name (throbber));
break;
case PROP_STATIC_PIXBUF:
g_value_set_object (value, katze_throbber_get_static_pixbuf (throbber));
break;
case PROP_STATIC_STOCK_ID:
g_value_set_string (value, katze_throbber_get_static_stock_id (throbber));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
/**
* katze_throbber_new:
*
* Creates a new throbber widget.
*
* Return value: a new #KatzeThrobber
**/
GtkWidget*
katze_throbber_new (void)
{
KatzeThrobber* throbber = g_object_new (KATZE_TYPE_THROBBER,
NULL);
return GTK_WIDGET (throbber);
}
/**
* katze_throbber_set_icon_size:
* @throbber: a #KatzeThrobber
* @icon_size: the new icon size
*
* Sets the desired size of the throbber image. The animation and static image
* will be displayed in this size. If a pixbuf is used for the animation every
* single frame is assumed to have this size.
**/
void
katze_throbber_set_icon_size (KatzeThrobber* throbber,
GtkIconSize icon_size)
{
GtkSettings* gtk_settings;
g_return_if_fail (KATZE_IS_THROBBER (throbber));
gtk_settings = gtk_widget_get_settings (GTK_WIDGET (throbber));
g_return_if_fail (gtk_icon_size_lookup_for_settings (gtk_settings,
icon_size,
&throbber->width,
&throbber->height));
throbber->icon_size = icon_size;
g_object_notify (G_OBJECT (throbber), "icon-size");
gtk_widget_queue_draw (GTK_WIDGET (throbber));
}
/**
* katze_throbber_set_icon_name:
* @throbber: a #KatzeThrobber
* @icon_name: an icon name or %NULL
*
* Sets the name of an icon that should provide the animation frames.
*
* The pixbuf is automatically invalidated.
**/
void
katze_throbber_set_icon_name (KatzeThrobber* throbber,
const gchar* icon_name)
{
g_return_if_fail (KATZE_IS_THROBBER (throbber));
katze_assign (throbber->icon_name, g_strdup (icon_name));
if (icon_name)
icon_theme_changed (throbber);
g_object_notify (G_OBJECT (throbber), "icon-name");
}
/**
* katze_throbber_set_pixbuf:
* @throbber: a #KatzeThrobber
* @pixbuf: a #GdkPixbuf or %NULL
*
* Sets the pixbuf that should provide the animation frames. Every frame
* is assumed to have the icon size of the throbber, which can be specified
* with katze_throbber_set_icon_size ().
*
* The icon name is automatically invalidated.
**/
void
katze_throbber_set_pixbuf (KatzeThrobber* throbber,
GdkPixbuf* pixbuf)
{
g_return_if_fail (KATZE_IS_THROBBER (throbber));
g_return_if_fail (!pixbuf || GDK_IS_PIXBUF (pixbuf));
katze_object_assign (throbber->pixbuf, pixbuf);
g_object_freeze_notify (G_OBJECT (throbber));
if (pixbuf)
{
g_object_ref (pixbuf);
katze_assign (throbber->icon_name, NULL);
g_object_notify (G_OBJECT (throbber), "icon-name");
}
gtk_widget_queue_draw (GTK_WIDGET (throbber));
g_object_notify (G_OBJECT (throbber), "pixbuf");
g_object_thaw_notify (G_OBJECT (throbber));
}
/**
* katze_throbber_set_animated:
* @throbber: a #KatzeThrobber
* @animated: %TRUE to animate the throbber
*
* Sets the animation state of the throbber.
**/
void
katze_throbber_set_animated (KatzeThrobber* throbber,
gboolean animated)
{
g_return_if_fail (KATZE_IS_THROBBER (throbber));
if (G_UNLIKELY (throbber->animated == animated))
return;
throbber->animated = animated;
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));
g_object_notify (G_OBJECT (throbber), "animated");
}
/**
* katze_throbber_set_static_icon_name:
* @throbber: a #KatzeThrobber
* @icon_name: an icon name or %NULL
*
* Sets the name of an icon that should provide the static image.
*
* The static pixbuf and stock ID are automatically invalidated.
**/
void
katze_throbber_set_static_icon_name (KatzeThrobber* throbber,
const gchar* icon_name)
{
g_return_if_fail (KATZE_IS_THROBBER (throbber));
katze_assign (throbber->static_icon_name, g_strdup (icon_name));
g_object_freeze_notify (G_OBJECT (throbber));
if (icon_name)
{
katze_assign (throbber->static_stock_id, NULL);
icon_theme_changed (throbber);
g_object_notify (G_OBJECT (throbber), "static-pixbuf");
g_object_notify (G_OBJECT (throbber), "static-stock-id");
}
g_object_notify (G_OBJECT (throbber), "static-icon-name");
g_object_thaw_notify (G_OBJECT (throbber));
}
/**
* katze_throbber_set_static_pixbuf:
* @throbber: a #KatzeThrobber
* @pixbuf: a #GdkPixbuf or %NULL
*
* Sets the pixbuf that should provide the static image. The pixbuf is
* assumed to have the icon size of the throbber, which can be specified
* with katze_throbber_set_icon_size ().
*
* The static icon name and stock ID are automatically invalidated.
**/
void
katze_throbber_set_static_pixbuf (KatzeThrobber* throbber,
GdkPixbuf* pixbuf)
{
g_return_if_fail (KATZE_IS_THROBBER (throbber));
g_return_if_fail (pixbuf == NULL || GDK_IS_PIXBUF (pixbuf));
katze_object_assign (throbber->static_pixbuf, pixbuf);
g_object_freeze_notify (G_OBJECT (throbber));
if (pixbuf)
{
g_object_ref (pixbuf);
katze_assign (throbber->static_icon_name, NULL);
katze_assign (throbber->static_stock_id, NULL);
gtk_widget_queue_draw (GTK_WIDGET (throbber));
g_object_notify (G_OBJECT (throbber), "static-icon-name");
g_object_notify (G_OBJECT (throbber), "static-stock-id");
}
g_object_notify (G_OBJECT (throbber), "static-pixbuf");
g_object_thaw_notify (G_OBJECT (throbber));
}
/**
* katze_throbber_set_static_stock_id:
* @throbber: a #KatzeThrobber
* @stock_id: a stock ID or %NULL
*
* Sets the stock ID of an icon that should provide the static image.
*
* The static icon name and pixbuf are automatically invalidated.
**/
void
katze_throbber_set_static_stock_id (KatzeThrobber* throbber,
const gchar* stock_id)
{
g_return_if_fail (KATZE_IS_THROBBER (throbber));
g_object_freeze_notify (G_OBJECT (throbber));
if (stock_id)
{
GtkStockItem stock_item;
g_return_if_fail (gtk_stock_lookup (stock_id, &stock_item));
g_object_notify (G_OBJECT (throbber), "static-icon-name");
g_object_notify (G_OBJECT (throbber), "static-pixbuf");
}
katze_assign (throbber->static_stock_id, g_strdup (stock_id));
if (stock_id)
icon_theme_changed (throbber);
g_object_notify (G_OBJECT (throbber), "static-stock-id");
g_object_thaw_notify (G_OBJECT (throbber));
}
/**
* katze_throbber_get_icon_size:
* @throbber: a #KatzeThrobber
*
* Retrieves the size of the throbber.
*
* Return value: the size of the throbber
**/
GtkIconSize
katze_throbber_get_icon_size (KatzeThrobber* throbber)
{
g_return_val_if_fail (KATZE_IS_THROBBER (throbber), GTK_ICON_SIZE_INVALID);
return throbber->icon_size;
}
/**
* katze_throbber_get_icon_name:
* @throbber: a #KatzeThrobber
*
* Retrieves the name of the icon providing the animation frames.
*
* Return value: the name of the icon providing the animation frames, or %NULL
**/
const gchar*
katze_throbber_get_icon_name (KatzeThrobber* throbber)
{
g_return_val_if_fail (KATZE_IS_THROBBER (throbber), NULL);
return throbber->icon_name;
}
/**
* katze_throbber_get_pixbuf:
* @throbber: a #KatzeThrobber
*
* Retrieves the #GdkPixbuf providing the animation frames if an icon name
* or pixbuf is available. The caller of this function does not own a
* reference to the returned pixbuf.
*
* Return value: the pixbuf providing the animation frames, or %NULL
**/
GdkPixbuf*
katze_throbber_get_pixbuf (KatzeThrobber* throbber)
{
g_return_val_if_fail (KATZE_IS_THROBBER (throbber), NULL);
return throbber->pixbuf;
}
/**
* katze_throbber_get_animated:
* @throbber: a #KatzeThrobber
*
* Retrieves the status of the animation, whcih can be animated or static.
*
* Return value: %TRUE if the throbber is animated
**/
gboolean
katze_throbber_get_animated (KatzeThrobber* throbber)
{
g_return_val_if_fail (KATZE_IS_THROBBER (throbber), FALSE);
return throbber->animated;
}
/**
* katze_throbber_get_static_icon_name:
* @throbber: a #KatzeThrobber
*
* Retrieves the name of the icon providing the static image, if an icon name
* for the static image was specified.
*
* Return value: the name of the icon providing the static image, or %NULL
**/
const gchar*
katze_throbber_get_static_icon_name (KatzeThrobber* throbber)
{
g_return_val_if_fail (KATZE_IS_THROBBER (throbber), NULL);
return throbber->static_icon_name;
}
/**
* katze_throbber_get_static pixbuf:
* @throbber: a #KatzeThrobber
*
* Retrieves the #GdkPixbuf providing the static image, if an icon name, a
* pixbuf or a stock ID for the static image was specified. The caller of this
* function does not own a reference to the returned pixbuf.
*
* Return value: the pixbuf providing the static image, or %NULL
**/
GdkPixbuf*
katze_throbber_get_static_pixbuf (KatzeThrobber* throbber)
{
g_return_val_if_fail (KATZE_IS_THROBBER (throbber), NULL);
return throbber->static_pixbuf;
}
/**
* katze_throbber_get_static_stock_id:
* @throbber: a #KatzeThrobber
*
* Retrieves the stock ID of the icon providing the static image, if a
* stock ID for the static image was specified.
*
* Return value: the stock ID of the icon providing the static image, or %NULL
**/
const gchar*
katze_throbber_get_static_stock_id (KatzeThrobber* throbber)
{
g_return_val_if_fail (KATZE_IS_THROBBER (throbber), NULL);
return throbber->static_stock_id;
}
static void
katze_throbber_realize (GtkWidget* widget)
{
(*GTK_WIDGET_CLASS (katze_throbber_parent_class)->realize) (widget);
icon_theme_changed (KATZE_THROBBER (widget));
}
static void
katze_throbber_unrealize (GtkWidget* widget)
{
if (GTK_WIDGET_CLASS (katze_throbber_parent_class)->unrealize)
GTK_WIDGET_CLASS (katze_throbber_parent_class)->unrealize (widget);
}
static void
pixbuf_assign_icon (GdkPixbuf** pixbuf,
const gchar* icon_name,
KatzeThrobber* throbber)
{
GdkScreen* screen;
GtkIconTheme* icon_theme;
if (*pixbuf)
g_object_unref (*pixbuf);
screen = gtk_widget_get_screen (GTK_WIDGET (throbber));
icon_theme = gtk_icon_theme_get_for_screen (screen);
*pixbuf = gtk_icon_theme_load_icon (icon_theme,
icon_name,
MAX (throbber->width, throbber->height),
(GtkIconLookupFlags) 0,
NULL);
}
static void
icon_theme_changed (KatzeThrobber* throbber)
{
if (throbber->icon_name)
pixbuf_assign_icon (&throbber->pixbuf,
throbber->icon_name, throbber);
if (throbber->static_icon_name)
pixbuf_assign_icon (&throbber->static_pixbuf,
throbber->static_icon_name, throbber);
else if (throbber->static_stock_id)
katze_object_assign (throbber->static_pixbuf,
gtk_widget_render_icon (GTK_WIDGET (throbber),
throbber->static_stock_id,
throbber->icon_size,
NULL));
g_object_freeze_notify (G_OBJECT (throbber));
g_object_notify (G_OBJECT (throbber), "pixbuf");
g_object_notify (G_OBJECT (throbber), "static-pixbuf");
g_object_thaw_notify (G_OBJECT (throbber));
gtk_widget_queue_draw (GTK_WIDGET (throbber));
}
static void
katze_throbber_map (GtkWidget* widget)
{
(*GTK_WIDGET_CLASS (katze_throbber_parent_class)->map) (widget);
}
static void
katze_throbber_unmap (GtkWidget* widget)
{
if (GTK_WIDGET_CLASS (katze_throbber_parent_class)->unmap)
GTK_WIDGET_CLASS (katze_throbber_parent_class)->unmap (widget);
}
static gboolean
katze_throbber_timeout (KatzeThrobber* throbber)
{
throbber->index++;
gtk_widget_queue_draw (GTK_WIDGET (throbber));
return throbber->animated;
}
static void
katze_throbber_timeout_destroy (KatzeThrobber* throbber)
{
throbber->index = 0;
throbber->timer_id = -1;
}
static void
katze_throbber_style_set (GtkWidget* widget,
GtkStyle* prev_style)
{
if (GTK_WIDGET_CLASS (katze_throbber_parent_class)->style_set)
GTK_WIDGET_CLASS (katze_throbber_parent_class)->style_set (widget,
prev_style);
icon_theme_changed (KATZE_THROBBER (widget));
}
static void
katze_throbber_screen_changed (GtkWidget* widget,
GdkScreen* prev_screen)
{
if (GTK_WIDGET_CLASS (katze_throbber_parent_class)->screen_changed)
GTK_WIDGET_CLASS (katze_throbber_parent_class)->screen_changed (
widget,
prev_screen);
icon_theme_changed (KATZE_THROBBER (widget));
}
static void
katze_throbber_size_request (GtkWidget* widget,
GtkRequisition* requisition)
{
KatzeThrobber* throbber = KATZE_THROBBER (widget);
requisition->width = throbber->width;
requisition->height = throbber->height;
GTK_WIDGET_CLASS (katze_throbber_parent_class)->size_request (widget,
requisition);
}
static void
katze_throbber_aligned_coords (GtkWidget* widget,
gint* ax,
gint* ay)
{
gfloat xalign, yalign;
gint xpad, ypad;
gtk_misc_get_alignment (GTK_MISC (widget), &xalign, &yalign);
if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
xalign = 1.0f - xalign;
gtk_misc_get_padding (GTK_MISC (widget), &xpad, &ypad);
*ax = floor (widget->allocation.x + xpad
+ ((widget->allocation.width - widget->requisition.width) * xalign));
*ay = floor (widget->allocation.y + ypad
+ ((widget->allocation.height - widget->requisition.height) * yalign));
}
static gboolean
katze_throbber_expose_event (GtkWidget* widget,
GdkEventExpose* event)
{
gint ax, ay;
KatzeThrobber* throbber = KATZE_THROBBER (widget);
if (G_UNLIKELY (!throbber->width || !throbber->height))
return TRUE;
if (G_UNLIKELY (!throbber->pixbuf && !throbber->static_pixbuf))
if (throbber->animated && !throbber->pixbuf && !throbber->icon_name)
return TRUE;
if (!throbber->animated && (throbber->static_pixbuf
|| throbber->static_icon_name || throbber->static_stock_id))
{
if (G_UNLIKELY (!throbber->static_pixbuf && throbber->static_icon_name))
{
icon_theme_changed (KATZE_THROBBER (widget));
if (!throbber->static_pixbuf)
{
g_warning (_("Named icon '%s' couldn't be loaded"),
throbber->static_icon_name);
katze_assign (throbber->static_icon_name, NULL);
g_object_notify (G_OBJECT (throbber), "static-icon-name");
return TRUE;
}
}
else if (G_UNLIKELY (!throbber->static_pixbuf && throbber->static_stock_id))
{
icon_theme_changed (KATZE_THROBBER (widget));
if (!throbber->static_pixbuf)
{
g_warning (_("Stock icon '%s' couldn't be loaded"),
throbber->static_stock_id);
katze_assign (throbber->static_stock_id, NULL);
g_object_notify (G_OBJECT (throbber), "static-stock-id");
return TRUE;
}
}
katze_throbber_aligned_coords (widget, &ax, &ay);
gdk_draw_pixbuf (event->window, NULL, throbber->static_pixbuf,
0, 0, ax, ay,
throbber->width, throbber->height,
GDK_RGB_DITHER_NONE, 0, 0);
}
else
{
if (G_UNLIKELY (throbber->icon_name && !throbber->pixbuf))
{
icon_theme_changed (KATZE_THROBBER (widget));
if (!throbber->pixbuf)
{
/* Fallback to a stock icon */
katze_assign (throbber->icon_name, g_strdup (GTK_STOCK_EXECUTE));
g_object_notify (G_OBJECT (throbber), "icon-name");
return TRUE;
}
}
gint cols = gdk_pixbuf_get_width (throbber->pixbuf) / throbber->width;
gint rows = gdk_pixbuf_get_height (throbber->pixbuf) / throbber->height;
if (G_UNLIKELY (cols == 1 && cols == rows))
{
katze_throbber_aligned_coords (widget, &ax, &ay);
if (throbber->animated)
gdk_draw_pixbuf (event->window, NULL, throbber->pixbuf,
0, 0, ax, ay,
throbber->width, throbber->height,
GDK_RGB_DITHER_NONE, 0, 0);
return TRUE;
}
if (G_LIKELY (cols > 0 && rows > 0))
{
gint idx;
guint x, y;
katze_throbber_aligned_coords (widget, &ax, &ay);
idx = throbber->index % (cols * rows);
if (G_LIKELY (throbber->timer_id >= 0))
idx = MAX (idx, 1);
x = (idx % cols) * throbber->width;
y = (idx / cols) * throbber->height;
gdk_draw_pixbuf (event->window, NULL, throbber->pixbuf,
x, y, ax, ay,
throbber->width, throbber->height,
GDK_RGB_DITHER_NONE, 0, 0);
}
else
{
g_warning (_("Animation frames are broken"));
katze_assign (throbber->icon_name, NULL);
katze_object_assign (throbber->pixbuf, NULL);
g_object_freeze_notify (G_OBJECT (throbber));
g_object_notify (G_OBJECT (throbber), "icon-name");
g_object_notify (G_OBJECT (throbber), "pixbuf");
g_object_thaw_notify (G_OBJECT (throbber));
}
}
return TRUE;
}

104
katze/katze-throbber.h Normal file
View file

@ -0,0 +1,104 @@
/*
Copyright (C) 2007 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_THROBBER_H__
#define __KATZE_THROBBER_H__
#include <gtk/gtk.h>
G_BEGIN_DECLS
#define KATZE_TYPE_THROBBER \
(katze_throbber_get_type ())
#define KATZE_THROBBER(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), KATZE_TYPE_THROBBER, KatzeThrobber))
#define KATZE_THROBBER_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), KATZE_TYPE_THROBBER, KatzeThrobberClass))
#define KATZE_IS_THROBBER(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), KATZE_TYPE_THROBBER))
#define KATZE_IS_THROBBER_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), KATZE_TYPE_THROBBER))
#define KATZE_THROBBER_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), KATZE_TYPE_THROBBER, KatzeThrobberClass))
typedef struct _KatzeThrobber KatzeThrobber;
typedef struct _KatzeThrobberPrivate KatzeThrobberPrivate;
typedef struct _KatzeThrobberClass KatzeThrobberClass;
struct _KatzeThrobberClass
{
GtkMiscClass parent_class;
/* Padding for future expansion */
void (*_katze_reserved1) (void);
void (*_katze_reserved2) (void);
void (*_katze_reserved3) (void);
void (*_katze_reserved4) (void);
};
GType
katze_throbber_get_type (void);
GtkWidget*
katze_throbber_new (void);
void
katze_throbber_set_icon_size (KatzeThrobber* throbber,
GtkIconSize icon_size);
void
katze_throbber_set_icon_name (KatzeThrobber* throbber,
const gchar* icon_size);
void
katze_throbber_set_pixbuf (KatzeThrobber* throbber,
GdkPixbuf* pixbuf);
void
katze_throbber_set_animated (KatzeThrobber* throbber,
gboolean animated);
void
katze_throbber_set_static_icon_name (KatzeThrobber* throbber,
const gchar* icon_name);
void
katze_throbber_set_static_pixbuf (KatzeThrobber* throbber,
GdkPixbuf* pixbuf);
void
katze_throbber_set_static_stock_id (KatzeThrobber* throbber,
const gchar* stock_id);
GtkIconSize
katze_throbber_get_icon_size (KatzeThrobber* throbber);
const gchar*
katze_throbber_get_icon_name (KatzeThrobber* throbber);
GdkPixbuf*
katze_throbber_get_pixbuf (KatzeThrobber* throbber);
gboolean
katze_throbber_get_animated (KatzeThrobber* throbber);
const gchar*
katze_throbber_get_static_icon_name (KatzeThrobber *throbber);
GdkPixbuf*
katze_throbber_get_static_pixbuf (KatzeThrobber* throbber);
const gchar*
katze_throbber_get_static_stock_id (KatzeThrobber* throbber);
G_END_DECLS
#endif /* __KATZE_THROBBER_H__ */

768
katze/katze-utils.c Normal file
View file

@ -0,0 +1,768 @@
/*
Copyright (C) 2007-2008 Christian Dywan <christian@twotoasts.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#include "katze-utils.h"
#include <glib/gi18n.h>
#include <string.h>
static void
proxy_toggle_button_toggled_cb (GtkToggleButton* button,
GObject* object)
{
gboolean toggled = gtk_toggle_button_get_active (button);
const gchar* property = g_object_get_data (G_OBJECT (button), "property");
g_object_set (object, property, toggled, NULL);
}
static void
proxy_file_file_set_cb (GtkFileChooser* button,
GObject* object)
{
const gchar* file = gtk_file_chooser_get_filename (button);
const gchar* property = g_object_get_data (G_OBJECT (button), "property");
g_object_set (object, property, file, NULL);
}
static void
proxy_folder_file_set_cb (GtkFileChooser* button,
GObject* object)
{
const gchar* file = gtk_file_chooser_get_current_folder (button);
const gchar* property = g_object_get_data (G_OBJECT (button), "property");
g_object_set (object, property, file, NULL);
}
static void
proxy_uri_file_set_cb (GtkFileChooser* button,
GObject* object)
{
const gchar* file = gtk_file_chooser_get_uri (button);
const gchar* property = g_object_get_data (G_OBJECT (button), "property");
g_object_set (object, property, file, NULL);
}
static void
proxy_combo_box_text_changed_cb (GtkComboBox* button,
GObject* object)
{
gchar* text = gtk_combo_box_get_active_text (button);
const gchar* property = g_object_get_data (G_OBJECT (button), "property");
g_object_set (object, property, text, NULL);
}
static void
proxy_entry_activate_cb (GtkEntry* entry,
GObject* object)
{
const gchar* text = gtk_entry_get_text (entry);
const gchar* property = g_object_get_data (G_OBJECT (entry), "property");
g_object_set (object, property, text, NULL);
}
static gboolean
proxy_entry_focus_out_event_cb (GtkEntry* entry,
GdkEventFocus* event,
GObject* object)
{
const gchar* text = gtk_entry_get_text (entry);
const gchar* property = g_object_get_data (G_OBJECT (entry), "property");
g_object_set (object, property, text, NULL);
return FALSE;
}
static void
proxy_spin_button_changed_cb (GtkSpinButton* button,
GObject* object)
{
GObjectClass* class = G_OBJECT_GET_CLASS (object);
const gchar* property = g_object_get_data (G_OBJECT (button), "property");
GParamSpec* pspec = g_object_class_find_property (class, property);
if (G_PARAM_SPEC_TYPE (pspec) == G_TYPE_PARAM_INT)
{
gint value = gtk_spin_button_get_value_as_int (button);
g_object_set (object, property, value, NULL);
}
else
{
gdouble value = gtk_spin_button_get_value (button);
g_object_set (object, property, value, NULL);
}
}
static void
proxy_combo_box_changed_cb (GtkComboBox* button,
GObject* object)
{
gint value = gtk_combo_box_get_active (button);
const gchar* property = g_object_get_data (G_OBJECT (button), "property");
g_object_set (object, property, value, NULL);
}
static void
proxy_object_notify_boolean_cb (GObject* object,
GParamSpec* pspec,
GtkWidget* proxy)
{
const gchar* property = g_object_get_data (G_OBJECT (proxy), "property");
gboolean value = katze_object_get_boolean (object, property);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (proxy), value);
}
static void
proxy_object_notify_string_cb (GObject* object,
GParamSpec* pspec,
GtkWidget* proxy)
{
const gchar* property = g_object_get_data (G_OBJECT (proxy), "property");
gchar* value = katze_object_get_string (object, property);
gtk_entry_set_text (GTK_ENTRY (proxy), value);
g_free (value);
}
/**
* katze_property_proxy:
* @object: a #GObject
* @property: the name of a property
* @hint: a special hint
*
* Create a widget of an appropriate type to represent the specified
* object's property. If the property is writable changes of the value
* through the widget will be reflected in the value of the property.
*
* Supported values for @hint are as follows:
* "blurb": the blurb of the property will be used to provide a kind
* of label, instead of the name.
* "file": the widget created will be particularly suitable for
* choosing an existing filename.
* "folder": the widget created will be particularly suitable for
* choosing an existing folder.
* "uri": the widget created will be particularly suitable for
* choosing an existing filename, encoded as an URI.
* "font": the widget created will be particularly suitable for
* choosing a font from installed fonts.
* Since 0.1.6 the following hints are also supported:
* "toggle": the widget created will be an empty toggle button. This
* is only supported with boolean properties.
*
* Any other values for @hint are silently ignored.
*
* Since 0.1.2 strings without hints and booleans are truly synchronous
* including property changes causing the proxy to be updated.
*
* Return value: a new widget
**/
GtkWidget*
katze_property_proxy (gpointer object,
const gchar* property,
const gchar* hint)
{
GObjectClass* class;
GParamSpec* pspec;
GType type;
const gchar* nick;
const gchar* _hint;
GtkWidget* widget;
gchar* string;
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);
}
type = G_PARAM_SPEC_TYPE (pspec);
nick = g_param_spec_get_nick (pspec);
_hint = g_intern_string (hint);
if (_hint == g_intern_string ("blurb"))
nick = g_param_spec_get_blurb (pspec);
string = NULL;
if (type == G_TYPE_PARAM_BOOLEAN)
{
gchar* notify_property;
gboolean toggled = katze_object_get_boolean (object, property);
if (_hint == g_intern_string ("toggle"))
widget = gtk_toggle_button_new ();
else
widget = gtk_check_button_new_with_label (gettext (nick));
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), toggled);
g_signal_connect (widget, "toggled",
G_CALLBACK (proxy_toggle_button_toggled_cb), object);
notify_property = g_strdup_printf ("notify::%s", property);
g_signal_connect (object, notify_property,
G_CALLBACK (proxy_object_notify_boolean_cb), widget);
g_free (notify_property);
}
else if (type == G_TYPE_PARAM_STRING && _hint == g_intern_string ("file"))
{
string = katze_object_get_string (object, property);
widget = gtk_file_chooser_button_new (_("Choose file"),
GTK_FILE_CHOOSER_ACTION_OPEN);
if (!string)
string = g_strdup (G_PARAM_SPEC_STRING (pspec)->default_value);
gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (widget),
string ? string : "");
#if GTK_CHECK_VERSION (2, 12, 0)
g_signal_connect (widget, "file-set",
G_CALLBACK (proxy_file_file_set_cb), object);
#else
if (pspec->flags & G_PARAM_WRITABLE)
g_signal_connect (widget, "selection-changed",
G_CALLBACK (proxy_file_file_set_cb), object);
#endif
}
else if (type == G_TYPE_PARAM_STRING && _hint == g_intern_string ("folder"))
{
string = katze_object_get_string (object, property);
widget = gtk_file_chooser_button_new (_("Choose folder"),
GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
if (!string)
string = g_strdup (G_PARAM_SPEC_STRING (pspec)->default_value);
gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (widget),
string ? string : "");
#if GTK_CHECK_VERSION (2, 12, 0)
g_signal_connect (widget, "file-set",
G_CALLBACK (proxy_folder_file_set_cb), object);
#else
if (pspec->flags & G_PARAM_WRITABLE)
g_signal_connect (widget, "selection-changed",
G_CALLBACK (proxy_folder_file_set_cb), object);
#endif
}
else if (type == G_TYPE_PARAM_STRING && _hint == g_intern_string ("uri"))
{
string = katze_object_get_string (object, property);
widget = gtk_file_chooser_button_new (_("Choose file"),
GTK_FILE_CHOOSER_ACTION_OPEN);
if (!string)
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 == g_intern_string ("font"))
{
int n_families, i;
PangoContext* context;
PangoFontFamily** families;
string = katze_object_get_string (object, property);
widget = gtk_combo_box_new_text ();
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);
for (i = 0; i < n_families; i++)
{
const gchar* font = pango_font_family_get_name (families[i]);
gtk_combo_box_append_text (GTK_COMBO_BOX (widget), font);
if (string && !strcmp (font, string))
gtk_combo_box_set_active (GTK_COMBO_BOX (widget), i);
}
gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (
gtk_combo_box_get_model (GTK_COMBO_BOX (widget))),
0, GTK_SORT_ASCENDING);
g_signal_connect (widget, "changed",
G_CALLBACK (proxy_combo_box_text_changed_cb), object);
g_free (families);
}
else if (type == G_TYPE_PARAM_STRING)
{
gchar* notify_property;
widget = gtk_entry_new ();
g_object_get (object, property, &string, NULL);
if (!string)
string = g_strdup (G_PARAM_SPEC_STRING (pspec)->default_value);
gtk_entry_set_text (GTK_ENTRY (widget), string ? string : "");
g_signal_connect (widget, "activate",
G_CALLBACK (proxy_entry_activate_cb), object);
g_signal_connect (widget, "focus-out-event",
G_CALLBACK (proxy_entry_focus_out_event_cb), object);
notify_property = g_strdup_printf ("notify::%s", property);
g_signal_connect (object, notify_property,
G_CALLBACK (proxy_object_notify_string_cb), widget);
g_free (notify_property);
}
else if (type == G_TYPE_PARAM_FLOAT)
{
gfloat value = katze_object_get_float (object, property);
widget = gtk_spin_button_new_with_range (
G_PARAM_SPEC_FLOAT (pspec)->minimum,
G_PARAM_SPEC_FLOAT (pspec)->maximum, 1);
/* Keep it narrow, 5 + 2 digits are usually fine */
gtk_entry_set_width_chars (GTK_ENTRY (widget), 5 + 2);
gtk_spin_button_set_digits (GTK_SPIN_BUTTON (widget), 2);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), value);
g_signal_connect (widget, "value-changed",
G_CALLBACK (proxy_spin_button_changed_cb), object);
}
else if (type == G_TYPE_PARAM_INT)
{
gint value = katze_object_get_int (object, property);
widget = gtk_spin_button_new_with_range (
G_PARAM_SPEC_INT (pspec)->minimum,
G_PARAM_SPEC_INT (pspec)->maximum, 1);
/* 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);
g_signal_connect (widget, "value-changed",
G_CALLBACK (proxy_spin_button_changed_cb), object);
}
else if (type == G_TYPE_PARAM_ENUM)
{
guint i;
GEnumClass* enum_class = G_ENUM_CLASS (
g_type_class_ref (pspec->value_type));
gint value = katze_object_get_enum (object, property);
widget = gtk_combo_box_new_text ();
for (i = 0; i < enum_class->n_values; i++)
{
const gchar* label = gettext (enum_class->values[i].value_nick);
gtk_combo_box_append_text (GTK_COMBO_BOX (widget), label);
}
gtk_combo_box_set_active (GTK_COMBO_BOX (widget), value);
g_signal_connect (widget, "changed",
G_CALLBACK (proxy_combo_box_changed_cb), object);
g_type_class_unref (enum_class);
}
else
widget = gtk_label_new (gettext (nick));
g_free (string);
gtk_widget_set_tooltip_text (widget, g_param_spec_get_blurb (pspec));
gtk_widget_set_sensitive (widget, pspec->flags & G_PARAM_WRITABLE);
g_object_set_data_full (G_OBJECT (widget), "property",
g_strdup (property), g_free);
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
**/
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);
}
nick = g_param_spec_get_nick (pspec);
widget = gtk_label_new (nick);
return widget;
}
typedef struct
{
GtkWidget* widget;
KatzeMenuPos position;
} KatzePopupInfo;
static void
katze_widget_popup_position_menu (GtkMenu* menu,
gint* x,
gint* y,
gboolean* push_in,
gpointer user_data)
{
gint wx, wy;
gint menu_width;
GtkRequisition menu_req;
GtkRequisition widget_req;
KatzePopupInfo* info = user_data;
GtkWidget* widget = info->widget;
gint widget_height;
/* Retrieve size and position of both widget and menu */
if (GTK_WIDGET_NO_WINDOW (widget))
{
gdk_window_get_position (widget->window, &wx, &wy);
wx += widget->allocation.x;
wy += widget->allocation.y;
}
else
gdk_window_get_origin (widget->window, &wx, &wy);
gtk_widget_size_request (GTK_WIDGET (menu), &menu_req);
gtk_widget_size_request (widget, &widget_req);
menu_width = menu_req.width;
widget_height = widget_req.height; /* Better than allocation.height */
/* Calculate menu position */
if (info->position == KATZE_MENU_POSITION_CURSOR)
; /* Do nothing? */
else if (info->position == KATZE_MENU_POSITION_RIGHT)
{
*x = wx + widget->allocation.width - menu_width;
*y = wy + widget_height;
} else if (info->position == KATZE_MENU_POSITION_LEFT)
{
*x = wx;
*y = wy + widget_height;
}
*push_in = TRUE;
}
/**
* katze_widget_popup:
* @widget: a widget
* @menu: the menu to popup
* @event: a button event, or %NULL
* @pos: the preferred positioning
*
* Pops up the given menu relative to @widget. Use this
* instead of writing custom positioning functions.
*
* Return value: a new label widget
**/
void
katze_widget_popup (GtkWidget* widget,
GtkMenu* menu,
GdkEventButton* event,
KatzeMenuPos pos)
{
int button, event_time;
if (event)
{
button = event->button;
event_time = event->time;
}
else
{
button = 0;
event_time = gtk_get_current_event_time ();
}
if (!gtk_menu_get_attach_widget (menu))
gtk_menu_attach_to_widget (menu, widget, NULL);
if (widget)
{
KatzePopupInfo info = { widget, pos };
gtk_menu_popup (menu, NULL, NULL,
katze_widget_popup_position_menu, &info,
button, event_time);
}
else
gtk_menu_popup (menu, NULL, NULL, NULL, NULL, button, event_time);
}
/**
* katze_image_menu_item_new_ellipsized:
* @label: a label or %NULL
*
* Creates an image menu item where the label is
* reasonably ellipsized for you.
*
* Return value: a new label widget
**/
GtkWidget*
katze_image_menu_item_new_ellipsized (const gchar* label)
{
GtkWidget* menuitem;
GtkWidget* label_widget;
menuitem = gtk_image_menu_item_new ();
label_widget = gtk_label_new (label);
/* FIXME: Should text direction be respected here? */
gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.0);
gtk_label_set_max_width_chars (GTK_LABEL (label_widget), 50);
gtk_label_set_ellipsize (GTK_LABEL (label_widget), PANGO_ELLIPSIZE_MIDDLE);
gtk_widget_show (label_widget);
gtk_container_add (GTK_CONTAINER (menuitem), label_widget);
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
* @model: a pointer to store the model, or %NULL
* @iter: a pointer to store the iter, or %NULL
*
* Determines whether there is a selection in @treeview
* and sets the @iter to the current selection.
*
* If there is a selection and @model is not %NULL, it is
* set to the model, mainly for convenience.
*
* Either @model or @iter or both can be %NULL in which case
* no value will be assigned in any case.
*
* Return value: %TRUE if there is a selection
*
* Since: 0.1.3
**/
gboolean
katze_tree_view_get_selected_iter (GtkTreeView* treeview,
GtkTreeModel** model,
GtkTreeIter* iter)
{
GtkTreeSelection* selection;
g_return_val_if_fail (GTK_IS_TREE_VIEW (treeview), FALSE);
if ((selection = gtk_tree_view_get_selection (treeview)))
if (gtk_tree_selection_get_selected (selection, model, iter))
return TRUE;
return FALSE;
}
/**
* 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)
{
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;
}
/**
* katze_object_get_boolean:
* @object: a #GObject
* @property: the name of the property to get
*
* Retrieve the boolean value of the specified property.
*
* Return value: a boolean
**/
gboolean
katze_object_get_boolean (gpointer object,
const gchar* property)
{
gboolean value = FALSE;
g_return_val_if_fail (G_IS_OBJECT (object), FALSE);
/* FIXME: Check value type */
g_object_get (object, property, &value, NULL);
return value;
}
/**
* katze_object_get_int:
* @object: a #GObject
* @property: the name of the property to get
*
* Retrieve the integer value of the specified property.
*
* Return value: an integer
**/
gint
katze_object_get_int (gpointer object,
const gchar* property)
{
gint value = -1;
g_return_val_if_fail (G_IS_OBJECT (object), -1);
/* FIXME: Check value type */
g_object_get (object, property, &value, NULL);
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
* @property: the name of the property to get
*
* Retrieve the enum value of the specified property.
*
* Return value: an enumeration
**/
gint
katze_object_get_enum (gpointer object,
const gchar* property)
{
gint value = -1;
g_return_val_if_fail (G_IS_OBJECT (object), -1);
/* FIXME: Check value type */
g_object_get (object, property, &value, NULL);
return value;
}
/**
* katze_object_get_string:
* @object: a #GObject
* @property: the name of the property to get
*
* Retrieve the string value of the specified property.
*
* Return value: a newly allocated string
**/
gchar*
katze_object_get_string (gpointer object,
const gchar* property)
{
gchar* value = NULL;
g_return_val_if_fail (G_IS_OBJECT (object), NULL);
/* FIXME: Check value type */
g_object_get (object, property, &value, NULL);
return value;
}
/**
* katze_object_get_object:
* @object: a #GObject
* @property: the name of the property to get
*
* Retrieve the object value of the specified property.
*
* Return value: an object
**/
gpointer
katze_object_get_object (gpointer object,
const gchar* property)
{
GObject* value = NULL;
g_return_val_if_fail (G_IS_OBJECT (object), NULL);
/* FIXME: Check value type */
g_object_get (object, property, &value, NULL);
return value;
}

122
katze/katze-utils.h Normal file
View file

@ -0,0 +1,122 @@
/*
Copyright (C) 2007-2008 Christian Dywan <christian@twotoasts.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#ifndef __KATZE_UTILS_H__
#define __KATZE_UTILS_H__
#include <gtk/gtk.h>
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
* @rvalue: the new value
*
* Frees @lvalue if needed and assigns it the value of @rvalue.
**/
#define katze_assign(lvalue, rvalue) \
if (1) \
{ \
g_free (lvalue); \
lvalue = rvalue; \
}
/**
* katze_object_assign:
* @lvalue: a gobject
* @rvalue: the new value
*
* Unrefs @lvalue if needed and assigns it the value of @rvalue.
**/
#define katze_object_assign(lvalue, rvalue) \
if (1) \
{ \
if (lvalue) \
g_object_unref (lvalue); \
lvalue = rvalue; \
}
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,
KATZE_MENU_POSITION_RIGHT
} KatzeMenuPos;
void
katze_widget_popup (GtkWidget* widget,
GtkMenu* menu,
GdkEventButton* event,
KatzeMenuPos pos);
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,
GtkTreeIter* iter);
gboolean
katze_object_has_property (gpointer object,
const gchar* property);
gint
katze_object_get_boolean (gpointer object,
const gchar* property);
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);
gchar*
katze_object_get_string (gpointer object,
const gchar* property);
gpointer
katze_object_get_object (gpointer object,
const gchar* property);
G_END_DECLS
#endif /* __KATZE_UTILS_H__ */

25
katze/katze.h Normal file
View file

@ -0,0 +1,25 @@
/*
Copyright (C) 2007-2009 Christian Dywan <christian@twotoasts.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#ifndef __KATZE_H__
#define __KATZE_H__
#include "katze-http-auth.h"
#include "katze-http-cookies.h"
#include "katze-throbber.h"
#include "katze-utils.h"
#include "katze-item.h"
#include "katze-array.h"
#include "katze-arrayaction.h"
#include "katze-separatoraction.h"
#include "katze-net.h"
#endif /* __KATZE_H__ */

1
katze/marshal.list Normal file
View file

@ -0,0 +1 @@
VOID:POINTER,INT

14
katze/wscript_build Normal file
View file

@ -0,0 +1,14 @@
#! /usr/bin/env python
# WAF build script for midori
# This file is licensed under the terms of the expat license, see the file EXPAT.
import platform
obj = bld.new_task_gen ('cc', 'staticlib')
obj.name = 'katze'
obj.target = 'katze'
obj.includes = '. ../.'
obj.find_sources_in_dirs ('.')
obj.add_marshal_file ('marshal.list', 'katze_cclosure_marshal')
obj.uselib = 'M GMODULE LIBSOUP GTK LIBXML WEBKIT'
obj.install_path = None

67
midori/compat.c Normal file
View file

@ -0,0 +1,67 @@
/*
Copyright (C) 2008-2009 Christian Dywan <christian@twotoasts.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#include "compat.h"
#include <string.h>
#if !GTK_CHECK_VERSION (2, 14, 0)
gboolean
gtk_show_uri (GdkScreen* screen,
const gchar* uri,
guint32 timestamp,
GError** error)
{
g_return_val_if_fail (uri != NULL, FALSE);
return g_app_info_launch_default_for_uri (uri, NULL, NULL);
}
#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

56
midori/compat.h Normal file
View file

@ -0,0 +1,56 @@
/*
Copyright (C) 2008-2009 Christian Dywan <christian@twotoasts.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#ifndef __COMPAT_H__
#define __COMPAT_H__
#if HAVE_CONFIG_H
#include <config.h>
#endif
#include <webkit/webkit.h>
G_BEGIN_DECLS
#if !GLIB_CHECK_VERSION (2, 14, 0)
#define G_PARAM_STATIC_STRINGS \
(G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)
#endif
#if !GTK_CHECK_VERSION (2, 14, 0)
gboolean
gtk_show_uri (GdkScreen* screen,
const gchar* uri,
guint32 timestamp,
GError** error);
#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);
#endif
G_END_DECLS
#endif /* __COMPAT_H__ */

1608
midori/gtkiconentry.c Normal file

File diff suppressed because it is too large Load diff

135
midori/gtkiconentry.h Normal file
View file

@ -0,0 +1,135 @@
/*
* Copyright (C) 2004-2006 Christian Hammond.
* Copyright (C) 2008 Cody Russell <bratsche@gnome.org>
*
* 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 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GTK_ICON_ENTRY_H__
#define __GTK_ICON_ENTRY_H__
#if HAVE_CONFIG_H
#include <config.h>
#endif
#include <gio/gio.h>
#include <gtk/gtk.h>
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
void
gtk_icon_entry_set_icon_from_pixbuf (GtkEntry* entry,
GtkEntryIconPosition position,
GdkPixbuf* pixbuf);
#define gtk_icon_entry_set_icon_highlight gtk_entry_set_icon_activatable
#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;
struct _GtkIconEntry
{
GtkEntry parent_object;
};
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);
#endif
G_END_DECLS
#endif /* __GTK_ICON_ENTRY_H__ */

1768
midori/main.c Normal file

File diff suppressed because it is too large Load diff

6
midori/marshal.list Normal file
View file

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

785
midori/midori-app.c Normal file
View file

@ -0,0 +1,785 @@
/*
Copyright (C) 2008 Christian Dywan <christian@twotoasts.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#if HAVE_CONFIG_H
#include <config.h>
#endif
#include "midori-app.h"
#include "sokoke.h"
#include <string.h>
#include <gtk/gtk.h>
#include <glib/gi18n.h>
#if HAVE_UNIQUE
#include <unique/unique.h>
#endif
struct _MidoriApp
{
GObject parent_instance;
MidoriBrowser* browser;
GtkAccelGroup* accel_group;
gchar* name;
MidoriWebSettings* settings;
KatzeArray* bookmarks;
KatzeArray* trash;
KatzeArray* search_engines;
KatzeArray* history;
KatzeArray* extensions;
KatzeArray* browsers;
gpointer instance;
};
struct _MidoriAppClass
{
GObjectClass parent_class;
/* Signals */
void
(*add_browser) (MidoriApp* app,
MidoriBrowser* browser);
void
(*quit) (MidoriApp* app);
};
G_DEFINE_TYPE (MidoriApp, midori_app, G_TYPE_OBJECT)
enum
{
PROP_0,
PROP_NAME,
PROP_SETTINGS,
PROP_BOOKMARKS,
PROP_TRASH,
PROP_SEARCH_ENGINES,
PROP_HISTORY,
PROP_EXTENSIONS,
PROP_BROWSERS,
PROP_BROWSER,
PROP_BROWSER_COUNT
};
enum {
ADD_BROWSER,
QUIT,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL];
static void
midori_app_finalize (GObject* object);
static void
midori_app_set_property (GObject* object,
guint prop_id,
const GValue* value,
GParamSpec* pspec);
static void
midori_app_get_property (GObject* object,
guint prop_id,
GValue* value,
GParamSpec* pspec);
static gboolean
midori_browser_focus_in_event_cb (MidoriBrowser* browser,
GdkEventFocus* event,
MidoriApp* app)
{
app->browser = browser;
g_object_notify (G_OBJECT (app), "browser");
return FALSE;
}
static void
midori_browser_new_window_cb (MidoriBrowser* browser,
const gchar* uri,
MidoriApp* app)
{
MidoriBrowser* new_browser = midori_app_create_browser (app);
midori_app_add_browser (app, new_browser);
midori_browser_add_uri (new_browser, uri);
gtk_widget_show (GTK_WIDGET (new_browser));
}
static gboolean
midori_browser_delete_event_cb (MidoriBrowser* browser,
GdkEvent* event,
MidoriApp* app)
{
return FALSE;
}
static gboolean
midori_browser_destroy_cb (MidoriBrowser* browser,
MidoriApp* app)
{
katze_array_remove_item (app->browsers, browser);
if (!katze_array_is_empty (app->browsers))
return FALSE;
midori_app_quit (app);
return TRUE;
}
static void
midori_browser_quit_cb (MidoriBrowser* browser,
MidoriApp* app)
{
midori_app_quit (app);
}
static void
_midori_app_add_browser (MidoriApp* app,
MidoriBrowser* browser)
{
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,
"signal::delete-event", midori_browser_delete_event_cb, app,
"signal::destroy", midori_browser_destroy_cb, app,
"signal::quit", midori_browser_quit_cb, app,
NULL);
katze_array_add_item (app->browsers, browser);
#if HAVE_UNIQUE
if (app->instance)
unique_app_watch_window (app->instance, GTK_WINDOW (browser));
#endif
}
static void
_midori_app_quit (MidoriApp* app)
{
gtk_main_quit ();
}
static void
midori_app_class_init (MidoriAppClass* class)
{
GObjectClass* gobject_class;
signals[ADD_BROWSER] = g_signal_new (
"add-browser",
G_TYPE_FROM_CLASS (class),
(GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
G_STRUCT_OFFSET (MidoriAppClass, add_browser),
0,
NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE, 1,
MIDORI_TYPE_BROWSER);
signals[QUIT] = g_signal_new (
"quit",
G_TYPE_FROM_CLASS (class),
(GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
G_STRUCT_OFFSET (MidoriAppClass, quit),
0,
NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
gobject_class = G_OBJECT_CLASS (class);
gobject_class->finalize = midori_app_finalize;
gobject_class->set_property = midori_app_set_property;
gobject_class->get_property = midori_app_get_property;
class->add_browser = _midori_app_add_browser;
class->quit = _midori_app_quit;
/**
* MidoriApp:name:
*
* The name of the instance.
*
* Since: 0.1.6
*/
g_object_class_install_property (gobject_class,
PROP_NAME,
g_param_spec_string (
"name",
"Name",
"The name of the instance",
"midori",
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class,
PROP_SETTINGS,
g_param_spec_object (
"settings",
"Settings",
"The associated settings",
MIDORI_TYPE_WEB_SETTINGS,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class,
PROP_BOOKMARKS,
g_param_spec_object (
"bookmarks",
"Bookmarks",
"The bookmarks folder, containing all bookmarks",
KATZE_TYPE_ARRAY,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class,
PROP_TRASH,
g_param_spec_object (
"trash",
"Trash",
"The trash, collecting recently closed tabs and windows",
KATZE_TYPE_ARRAY,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class,
PROP_SEARCH_ENGINES,
g_param_spec_object (
"search-engines",
"Search Engines",
"The list of search engines",
KATZE_TYPE_ARRAY,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class,
PROP_HISTORY,
g_param_spec_object (
"history",
"History",
"The list of history items",
KATZE_TYPE_ARRAY,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class,
PROP_EXTENSIONS,
g_param_spec_object (
"extensions",
"Extensions",
"The list of extensions",
KATZE_TYPE_ARRAY,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
* MidoriApp:browsers:
*
* The list of browsers.
*
* Since: 0.1.3
*/
g_object_class_install_property (gobject_class,
PROP_BROWSERS,
g_param_spec_object (
"browsers",
"Browsers",
"The list of browsers",
KATZE_TYPE_ARRAY,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
/**
* MidoriApp:browser:
*
* The current browser, that is the one that was last used.
*
* Since: 0.1.3
*/
g_object_class_install_property (gobject_class,
PROP_BROWSER,
g_param_spec_object (
"browser",
"Browser",
"The current browser",
MIDORI_TYPE_BROWSER,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
/**
* MidoriApp:browser-count:
*
* The number of browsers.
*
* Deprecated: 0.1.3 Use MidoriApp:browsers instead.
*/
g_object_class_install_property (gobject_class,
PROP_BROWSER_COUNT,
g_param_spec_uint (
"browser-count",
"Browser Count",
"The current number of browsers",
0, G_MAXUINT, 0,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
}
#if HAVE_UNIQUE
static UniqueResponse
midori_browser_message_received_cb (UniqueApp* instance,
UniqueCommand command,
UniqueMessageData* message,
guint timestamp,
MidoriApp* app)
{
UniqueResponse response;
MidoriBrowser* browser;
gchar** uris;
MidoriNewPage open_external_pages_in;
gboolean first;
switch (command)
{
case UNIQUE_ACTIVATE:
gtk_window_set_screen (GTK_WINDOW (app->browser),
unique_message_data_get_screen (message));
gtk_window_present (GTK_WINDOW (app->browser));
response = UNIQUE_RESPONSE_OK;
break;
case UNIQUE_NEW:
browser = midori_app_create_browser (app);
midori_app_add_browser (app, browser);
/* FIXME: Should open the homepage according to settings */
midori_browser_add_uri (browser, "");
midori_browser_activate_action (browser, "Location");
gtk_window_set_screen (GTK_WINDOW (app->browser),
unique_message_data_get_screen (message));
gtk_widget_show (GTK_WIDGET (browser));
response = UNIQUE_RESPONSE_OK;
break;
case UNIQUE_OPEN:
gtk_window_set_screen (GTK_WINDOW (app->browser),
unique_message_data_get_screen (message));
gtk_window_present (GTK_WINDOW (app->browser));
uris = unique_message_data_get_uris (message);
if (!uris)
response = UNIQUE_RESPONSE_FAIL;
else
{
g_object_get (app->settings, "open-external-pages-in",
&open_external_pages_in, NULL);
if (open_external_pages_in == MIDORI_NEW_PAGE_WINDOW)
{
browser = midori_app_create_browser (app);
midori_app_add_browser (app, browser);
gtk_window_set_screen (GTK_WINDOW (app->browser),
unique_message_data_get_screen (message));
gtk_widget_show (GTK_WIDGET (browser));
}
else
browser = app->browser;
first = (open_external_pages_in == MIDORI_NEW_PAGE_CURRENT);
while (*uris)
{
gchar* fixed_uri = sokoke_magic_uri (*uris, NULL);
if (first)
{
midori_browser_set_current_uri (browser, fixed_uri);
first = FALSE;
}
else
midori_browser_set_current_page (browser,
midori_browser_add_uri (browser, fixed_uri));
g_free (fixed_uri);
uris++;
}
/* g_strfreev (uris); */
response = UNIQUE_RESPONSE_OK;
}
break;
default:
response = UNIQUE_RESPONSE_FAIL;
break;
}
return response;
}
#endif
static gpointer
midori_app_create_instance (MidoriApp* app,
const gchar* name)
{
#if HAVE_UNIQUE
gpointer instance;
GdkDisplay* display;
gchar* display_name;
gchar* instance_name;
guint i, n;
#endif
if (!name)
name = "midori";
#if HAVE_UNIQUE
if (!(display = gdk_display_get_default ()))
return NULL;
display_name = g_strdup (gdk_display_get_name (display));
n = strlen (display_name);
for (i = 0; i < n; i++)
if (display_name[i] == ':' || display_name[i] == '.')
display_name[i] = '_';
instance_name = g_strdup_printf ("de.twotoasts.%s_%s", name, display_name);
instance = unique_app_new (instance_name, NULL);
g_free (instance_name);
g_free (display_name);
g_signal_connect (instance, "message-received",
G_CALLBACK (midori_browser_message_received_cb), app);
return instance;
#else
return NULL;
#endif
}
static void
midori_app_init (MidoriApp* app)
{
app->accel_group = gtk_accel_group_new ();
app->settings = NULL;
app->bookmarks = NULL;
app->trash = NULL;
app->search_engines = NULL;
app->history = NULL;
app->extensions = NULL;
app->browsers = katze_array_new (MIDORI_TYPE_BROWSER);
app->instance = NULL;
}
static void
midori_app_finalize (GObject* object)
{
MidoriApp* app = MIDORI_APP (object);
g_object_unref (app->accel_group);
katze_assign (app->name, NULL);
katze_object_assign (app->settings, NULL);
katze_object_assign (app->bookmarks, NULL);
katze_object_assign (app->trash, NULL);
katze_object_assign (app->search_engines, NULL);
katze_object_assign (app->history, NULL);
katze_object_assign (app->extensions, NULL);
katze_object_assign (app->browsers, NULL);
katze_object_assign (app->instance, NULL);
G_OBJECT_CLASS (midori_app_parent_class)->finalize (object);
}
static void
midori_app_set_property (GObject* object,
guint prop_id,
const GValue* value,
GParamSpec* pspec)
{
MidoriApp* app = MIDORI_APP (object);
switch (prop_id)
{
case PROP_NAME:
katze_assign (app->name, g_value_dup_string (value));
break;
case PROP_SETTINGS:
katze_object_assign (app->settings, g_value_dup_object (value));
/* FIXME: Propagate settings to all browsers */
break;
case PROP_BOOKMARKS:
katze_object_assign (app->bookmarks, g_value_dup_object (value));
/* FIXME: Propagate bookmarks to all browsers */
break;
case PROP_TRASH:
katze_object_assign (app->trash, g_value_dup_object (value));
/* FIXME: Propagate trash to all browsers */
break;
case PROP_SEARCH_ENGINES:
katze_object_assign (app->search_engines, g_value_dup_object (value));
/* FIXME: Propagate search engines to all browsers */
break;
case PROP_HISTORY:
katze_object_assign (app->history, g_value_dup_object (value));
/* FIXME: Propagate history to all browsers */
break;
case PROP_EXTENSIONS:
katze_object_assign (app->extensions, g_value_dup_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
midori_app_get_property (GObject* object,
guint prop_id,
GValue* value,
GParamSpec* pspec)
{
MidoriApp* app = MIDORI_APP (object);
switch (prop_id)
{
case PROP_NAME:
g_value_set_string (value, app->name);
break;
case PROP_SETTINGS:
g_value_set_object (value, app->settings);
break;
case PROP_BOOKMARKS:
g_value_set_object (value, app->bookmarks);
break;
case PROP_TRASH:
g_value_set_object (value, app->trash);
break;
case PROP_SEARCH_ENGINES:
g_value_set_object (value, app->search_engines);
break;
case PROP_HISTORY:
g_value_set_object (value, app->history);
break;
case PROP_EXTENSIONS:
g_value_set_object (value, app->extensions);
break;
case PROP_BROWSERS:
g_value_set_object (value, app->browsers);
break;
case PROP_BROWSER:
g_value_set_object (value, app->browser);
break;
case PROP_BROWSER_COUNT:
g_value_set_uint (value, katze_array_get_length (app->browsers));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
/**
* midori_app_new:
*
* Instantiates a new #MidoriApp singleton.
*
* Subsequent calls will ref the initial instance.
*
* Return value: a new #MidoriApp
**/
MidoriApp*
midori_app_new (void)
{
MidoriApp* app = g_object_new (MIDORI_TYPE_APP,
NULL);
return app;
}
/**
* midori_app_instance_is_running:
* @app: a #MidoriApp
*
* Determines whether an instance of Midori is
* already running on the default display.
*
* Use the "name" property if you want to run more
* than one instance.
*
* If Midori was built without single instance support
* this function will always return %FALSE.
*
* Return value: %TRUE if an instance is already running
**/
gboolean
midori_app_instance_is_running (MidoriApp* app)
{
g_return_val_if_fail (MIDORI_IS_APP (app), FALSE);
#if HAVE_UNIQUE
if (!app->instance)
app->instance = midori_app_create_instance (app, app->name);
if (app->instance)
return unique_app_is_running (app->instance);
#endif
return FALSE;
}
/**
* midori_app_instance_send_activate:
* @app: a #MidoriApp
*
* Sends a message to an instance of Midori already
* running on the default display, asking to activate it.
*
* Practically the current browser will be focussed.
*
* Return value: %TRUE if the message was sent successfully
**/
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_app_instance_is_running (app), FALSE);
#if HAVE_UNIQUE
if (app->instance)
{
response = unique_app_send_message (app->instance, UNIQUE_ACTIVATE, NULL);
if (response == UNIQUE_RESPONSE_OK)
return TRUE;
}
#endif
return FALSE;
}
/**
* midori_app_instance_send_new_browser:
* @app: a #MidoriApp
*
* Sends a message to an instance of Midori already
* running on the default display, asking to open a new browser.
*
* Return value: %TRUE if the message was sent successfully
**/
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_app_instance_is_running (app), FALSE);
#if HAVE_UNIQUE
if (app->instance)
{
response = unique_app_send_message (app->instance, UNIQUE_NEW, NULL);
if (response == UNIQUE_RESPONSE_OK)
return TRUE;
}
#endif
return FALSE;
}
/**
* midori_app_instance_send_uris:
* @app: a #MidoriApp
* @uris: a string vector of URIs
*
* Sends a message to an instance of Midori already
* running on the default display, asking to open @uris.
*
* The strings in @uris will each be opened in a new tab.
*
* Return value: %TRUE if the message was sent successfully
**/
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_app_instance_is_running (app), FALSE);
g_return_val_if_fail (uris != NULL, FALSE);
#if HAVE_UNIQUE
if (app->instance)
{
message = unique_message_data_new ();
unique_message_data_set_uris (message, uris);
response = unique_app_send_message (app->instance, UNIQUE_OPEN, message);
unique_message_data_free (message);
if (response == UNIQUE_RESPONSE_OK)
return TRUE;
}
#endif
return FALSE;
}
/**
* midori_app_add_browser:
* @app: a #MidoriApp
* @browser: a #MidoriBrowser
*
* Adds a #MidoriBrowser to the #MidoriApp.
*
* The app will take care of the browser's new-window and quit signals, as well
* as watch window closing so that the last closed window quits the app.
* Also the app watches focus changes to indicate the 'current' browser.
*
* Return value: a new #MidoriApp
**/
void
midori_app_add_browser (MidoriApp* app,
MidoriBrowser* browser)
{
g_return_if_fail (MIDORI_IS_APP (app));
g_return_if_fail (MIDORI_IS_BROWSER (browser));
g_signal_emit (app, signals[ADD_BROWSER], 0, browser);
}
/**
* midori_app_create_browser:
* @app: a #MidoriApp
*
* Creates a #MidoriBrowser which inherits its settings,
* bookmarks, trash, search engines and history from @app.
*
* Return value: a new #MidoriBrowser
*
* Since: 1.0.2
**/
MidoriBrowser*
midori_app_create_browser (MidoriApp* app)
{
g_return_val_if_fail (MIDORI_IS_APP (app), NULL);
return g_object_new (MIDORI_TYPE_BROWSER,
"settings", app->settings,
"bookmarks", app->bookmarks,
"trash", app->trash,
"search-engines", app->search_engines,
"history", app->history,
NULL);
}
/**
* midori_app_quit:
* @app: a #MidoriApp
*
* Quits the #MidoriApp singleton.
*
* Since 0.1.2 the "quit" signal is always emitted before quitting.
**/
void
midori_app_quit (MidoriApp* app)
{
g_return_if_fail (MIDORI_IS_APP (app));
g_signal_emit (app, signals[QUIT], 0);
}

69
midori/midori-app.h Normal file
View file

@ -0,0 +1,69 @@
/*
Copyright (C) 2008 Christian Dywan <christian@twotoasts.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#ifndef __MIDORI_APP_H__
#define __MIDORI_APP_H__
#include <katze/katze.h>
#include "midori-browser.h"
#include "midori-websettings.h"
G_BEGIN_DECLS
#define MIDORI_TYPE_APP \
(midori_app_get_type ())
#define MIDORI_APP(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), MIDORI_TYPE_APP, MidoriApp))
#define MIDORI_APP_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), MIDORI_TYPE_APP, MidoriAppClass))
#define MIDORI_IS_APP(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), MIDORI_TYPE_APP))
#define MIDORI_IS_APP_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), MIDORI_TYPE_APP))
#define MIDORI_APP_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), MIDORI_TYPE_APP, MidoriAppClass))
typedef struct _MidoriApp MidoriApp;
typedef struct _MidoriAppClass MidoriAppClass;
GType
midori_app_get_type (void);
MidoriApp*
midori_app_new (void);
gboolean
midori_app_instance_is_running (MidoriApp* app);
gboolean
midori_app_instance_send_activate (MidoriApp* app);
gboolean
midori_app_instance_send_new_browser (MidoriApp* app);
gboolean
midori_app_instance_send_uris (MidoriApp* app,
gchar** uris);
void
midori_app_add_browser (MidoriApp* app,
MidoriBrowser* browser);
MidoriBrowser*
midori_app_create_browser (MidoriApp* app);
void
midori_app_quit (MidoriApp* app);
G_END_DECLS
#endif /* __MIDORI_APP_H__ */

374
midori/midori-array.c Normal file
View file

@ -0,0 +1,374 @@
/*
Copyright (C) 2007-2009 Christian Dywan <christian@twotoasts.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#include <katze/katze.h>
#if HAVE_CONFIG_H
#include <config.h>
#endif
#include <glib/gi18n.h>
#if HAVE_LIBXML
#include <libxml/parser.h>
#include <libxml/tree.h>
#endif
#if HAVE_LIBXML
static KatzeItem*
katze_item_from_xmlNodePtr (xmlNodePtr cur)
{
KatzeItem* item;
xmlChar* key;
item = katze_item_new ();
key = xmlGetProp (cur, (xmlChar*)"href");
katze_item_set_uri (item, (gchar*)key);
g_free (key);
cur = cur->xmlChildrenNode;
while (cur)
{
if (!xmlStrcmp (cur->name, (const xmlChar*)"title"))
{
key = xmlNodeGetContent (cur);
katze_item_set_name (item, g_strstrip ((gchar*)key));
g_free (key);
}
else if (!xmlStrcmp (cur->name, (const xmlChar*)"desc"))
{
key = xmlNodeGetContent (cur);
katze_item_set_text (item, g_strstrip ((gchar*)key));
g_free (key);
}
cur = cur->next;
}
return item;
}
/* Create an array from an xmlNodePtr */
static KatzeArray*
katze_array_from_xmlNodePtr (xmlNodePtr cur)
{
KatzeArray* array;
xmlChar* key;
KatzeItem* item;
array = katze_array_new (KATZE_TYPE_ARRAY);
key = xmlGetProp (cur, (xmlChar*)"folded");
if (key)
{
/* if (!g_ascii_strncasecmp ((gchar*)key, "yes", 3))
folder->folded = TRUE;
else if (!g_ascii_strncasecmp ((gchar*)key, "no", 2))
folder->folded = FALSE;
else
g_warning ("XBEL: Unknown value for folded."); */
xmlFree (key);
}
cur = cur->xmlChildrenNode;
while (cur)
{
if (!xmlStrcmp (cur->name, (const xmlChar*)"title"))
{
key = xmlNodeGetContent (cur);
katze_item_set_name (KATZE_ITEM (array), g_strstrip ((gchar*)key));
}
else if (!xmlStrcmp (cur->name, (const xmlChar*)"desc"))
{
key = xmlNodeGetContent (cur);
katze_item_set_text (KATZE_ITEM (array), g_strstrip ((gchar*)key));
}
else if (!xmlStrcmp (cur->name, (const xmlChar*)"folder"))
{
item = (KatzeItem*)katze_array_from_xmlNodePtr (cur);
katze_array_add_item (array, item);
}
else if (!xmlStrcmp (cur->name, (const xmlChar*)"bookmark"))
{
item = katze_item_from_xmlNodePtr (cur);
katze_array_add_item (array, item);
}
else if (!xmlStrcmp (cur->name, (const xmlChar*)"separator"))
{
item = katze_item_new ();
katze_array_add_item (array, item);
}
cur = cur->next;
}
return array;
}
/* Loads the contents from an xmlNodePtr into an array. */
static gboolean
katze_array_from_xmlDocPtr (KatzeArray* array,
xmlDocPtr doc)
{
xmlNodePtr cur;
xmlChar* version;
gchar* value;
KatzeItem* item;
cur = xmlDocGetRootElement (doc);
version = xmlGetProp (cur, (xmlChar*)"version");
if (xmlStrcmp (version, (xmlChar*)"1.0"))
g_warning ("XBEL version is not 1.0.");
xmlFree (version);
value = (gchar*)xmlGetProp (cur, (xmlChar*)"title");
katze_item_set_name (KATZE_ITEM (array), value);
g_free (value);
value = (gchar*)xmlGetProp (cur, (xmlChar*)"desc");
katze_item_set_text (KATZE_ITEM (array), value);
g_free (value);
if ((cur = xmlDocGetRootElement (doc)) == NULL)
{
/* Empty document */
return FALSE;
}
if (xmlStrcmp (cur->name, (const xmlChar*)"xbel"))
{
/* Wrong document kind */
return FALSE;
}
cur = cur->xmlChildrenNode;
while (cur)
{
item = NULL;
if (!xmlStrcmp (cur->name, (const xmlChar*)"folder"))
item = (KatzeItem*)katze_array_from_xmlNodePtr (cur);
else if (!xmlStrcmp (cur->name, (const xmlChar*)"bookmark"))
item = katze_item_from_xmlNodePtr (cur);
else if (!xmlStrcmp (cur->name, (const xmlChar*)"separator"))
item = katze_item_new ();
/*else if (!xmlStrcmp (cur->name, (const xmlChar*)"info"))
item = katze_xbel_parse_info (xbel, cur);*/
if (item)
katze_array_add_item (array, item);
cur = cur->next;
}
return TRUE;
}
/**
* midori_array_from_file:
* @array: a #KatzeArray
* @filename: a filename to load from
* @format: the desired format
* @error: a #GError or %NULL
*
* Loads the contents of a file in the specified format.
*
* Return value: %TRUE on success, %FALSE otherwise
*
* Since: 0.1.6
**/
gboolean
midori_array_from_file (KatzeArray* array,
const gchar* filename,
const gchar* format,
GError** error)
{
xmlDocPtr doc;
g_return_val_if_fail (katze_array_is_a (array, KATZE_TYPE_ITEM), FALSE);
g_return_val_if_fail (filename != NULL, FALSE);
g_return_val_if_fail (!g_strcmp0 (format, "xbel"), FALSE);
g_return_val_if_fail (!error || !*error, FALSE);
if (!g_file_test (filename, G_FILE_TEST_EXISTS))
{
/* File doesn't exist */
*error = g_error_new_literal (G_FILE_ERROR, G_FILE_ERROR_NOENT,
_("File not found."));
return FALSE;
}
if ((doc = xmlParseFile (filename)) == NULL)
{
/* No valid xml or broken encoding */
*error = g_error_new_literal (G_FILE_ERROR, G_FILE_ERROR_FAILED,
_("Malformed document."));
return FALSE;
}
if (!katze_array_from_xmlDocPtr (array, doc))
{
/* Parsing failed */
xmlFreeDoc (doc);
*error = g_error_new_literal (G_FILE_ERROR, G_FILE_ERROR_FAILED,
_("Malformed document."));
return FALSE;
}
xmlFreeDoc (doc);
return TRUE;
}
#endif
static gchar*
_simple_xml_element (const gchar* name,
const gchar* value)
{
gchar* value_escaped;
gchar* markup;
if (!value)
return g_strdup ("");
value_escaped = g_markup_escape_text (value, -1);
markup = g_strdup_printf ("<%s>%s</%s>\n", name, value_escaped, name);
g_free (value_escaped);
return markup;
}
static gchar*
katze_item_to_data (KatzeItem* item)
{
gchar* markup;
g_return_val_if_fail (KATZE_IS_ITEM (item), NULL);
markup = NULL;
if (KATZE_IS_ARRAY (item))
{
GString* _markup = g_string_new (NULL);
guint i = 0;
KatzeItem* _item;
while ((_item = katze_array_get_nth_item (KATZE_ARRAY (item), i++)))
{
gchar* item_markup = katze_item_to_data (_item);
g_string_append (_markup, item_markup);
g_free (item_markup);
}
/* gchar* folded = item->folded ? NULL : g_strdup_printf (" folded=\"no\""); */
gchar* title = _simple_xml_element ("title", katze_item_get_name (item));
gchar* desc = _simple_xml_element ("desc", katze_item_get_text (item));
markup = g_strdup_printf ("<folder%s>\n%s%s%s</folder>\n",
"" /* folded ? folded : "" */,
title, desc,
_markup->str);
g_string_free (_markup, TRUE);
/* g_free (folded); */
g_free (title);
g_free (desc);
}
else if (katze_item_get_uri (item))
{
gchar* href_escaped = g_markup_escape_text (katze_item_get_uri (item), -1);
gchar* href = g_strdup_printf (" href=\"%s\"", href_escaped);
g_free (href_escaped);
gchar* title = _simple_xml_element ("title", katze_item_get_name (item));
gchar* desc = _simple_xml_element ("desc", katze_item_get_text (item));
markup = g_strdup_printf ("<bookmark%s>\n%s%s%s</bookmark>\n",
href,
title, desc,
"");
g_free (href);
g_free (title);
g_free (desc);
}
else
markup = g_strdup ("<separator/>\n");
return markup;
}
static gchar*
katze_array_to_xbel (KatzeArray* array,
GError** error)
{
GString* inner_markup;
guint i;
KatzeItem* item;
gchar* item_xml;
gchar* title;
gchar* desc;
gchar* outer_markup;
inner_markup = g_string_new (NULL);
i = 0;
while ((item = katze_array_get_nth_item (array, i++)))
{
item_xml = katze_item_to_data (item);
g_string_append (inner_markup, item_xml);
g_free (item_xml);
}
title = _simple_xml_element ("title", katze_item_get_name (KATZE_ITEM (array)));
desc = _simple_xml_element ("desc", katze_item_get_text (KATZE_ITEM (array)));
outer_markup = g_strdup_printf (
"%s%s<xbel version=\"1.0\">\n%s%s%s</xbel>\n",
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n",
"<!DOCTYPE xbel PUBLIC \"+//IDN python.org//DTD "
"XML Bookmark Exchange Language 1.0//EN//XML\" "
"\"http://www.python.org/topics/xml/dtds/xbel-1.0.dtd\">\n",
title,
desc,
inner_markup->str);
g_string_free (inner_markup, TRUE);
g_free (title);
g_free (desc);
return outer_markup;
}
static gboolean
midori_array_to_file_xbel (KatzeArray* array,
const gchar* filename,
GError** error)
{
gchar* data;
FILE* fp;
if (!(data = katze_array_to_xbel (array, error)))
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);
g_free (data);
return TRUE;
}
/**
* midori_array_to_file:
* @array: a #KatzeArray
* @filename: a filename to load from
* @format: the desired format
* @error: a #GError or %NULL
*
* Saves the contents to a file in the specified format.
*
* Return value: %TRUE on success, %FALSE otherwise
*
* Since: 0.1.6
**/
gboolean
midori_array_to_file (KatzeArray* array,
const gchar* filename,
const gchar* format,
GError** error)
{
g_return_val_if_fail (katze_array_is_a (array, KATZE_TYPE_ITEM), FALSE);
g_return_val_if_fail (filename, FALSE);
g_return_val_if_fail (!error || !*error, FALSE);
if (!g_strcmp0 (format, "xbel"))
return midori_array_to_file_xbel (array, filename, error);
g_critical ("Cannot write KatzeArray to unknown format '%s'.", format);
return FALSE;
}

29
midori/midori-array.h Normal file
View file

@ -0,0 +1,29 @@
/*
Copyright (C) 2007-2009 Christian Dywan <christian@twotoasts.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#ifndef __MIDORI_ARRAY_H__
#define __MIDORI_ARRAY_H__ 1
#include <katze/katze.h>
gboolean
midori_array_from_file (KatzeArray* array,
const gchar* filename,
const gchar* format,
GError** error);
gboolean
midori_array_to_file (KatzeArray* array,
const gchar* filename,
const gchar* format,
GError** error);
#endif /* !__MIDORI_ARRAY_H__ */

5234
midori/midori-browser.c Normal file

File diff suppressed because it is too large Load diff

135
midori/midori-browser.h Normal file
View file

@ -0,0 +1,135 @@
/*
Copyright (C) 2008 Christian Dywan <christian@twotoasts.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#ifndef __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>
G_BEGIN_DECLS
#define MIDORI_TYPE_BROWSER \
(midori_browser_get_type ())
#define MIDORI_BROWSER(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), MIDORI_TYPE_BROWSER, MidoriBrowser))
#define MIDORI_BROWSER_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), MIDORI_TYPE_BROWSER, MidoriBrowserClass))
#define MIDORI_IS_BROWSER(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), MIDORI_TYPE_BROWSER))
#define MIDORI_IS_BROWSER_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), MIDORI_TYPE_BROWSER))
#define MIDORI_BROWSER_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), MIDORI_TYPE_BROWSER, MidoriBrowserClass))
typedef struct _MidoriBrowser MidoriBrowser;
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,
WebKitWebFrame* web_frame,
JSContextRef* context,
JSObjectRef* window_object);
void
(*statusbar_text_changed) (MidoriBrowser* browser,
const gchar* text);
void
(*element_motion) (MidoriBrowser* browser,
const gchar* link_uri);
void
(*new_window) (MidoriBrowser* browser,
const gchar* uri);
void
(*add_tab) (MidoriBrowser* browser,
GtkWidget* view);
void
(*remove_tab) (MidoriBrowser* browser,
GtkWidget* view);
void
(*activate_action) (MidoriBrowser* browser,
const gchar* name);
void
(*quit) (MidoriBrowser* browser);
};
GType
midori_browser_get_type (void);
MidoriBrowser*
midori_browser_new (void);
gint
midori_browser_add_tab (MidoriBrowser* browser,
GtkWidget* widget);
void
midori_browser_remove_tab (MidoriBrowser* browser,
GtkWidget* widget);
gint
midori_browser_add_item (MidoriBrowser* browser,
KatzeItem* item);
gint
midori_browser_add_uri (MidoriBrowser* browser,
const gchar* uri);
void
midori_browser_activate_action (MidoriBrowser* browser,
const gchar* name);
GtkActionGroup*
midori_browser_get_action_group (MidoriBrowser* browser);
void
midori_browser_set_current_uri (MidoriBrowser* browser,
const gchar* uri);
const gchar*
midori_browser_get_current_uri (MidoriBrowser* browser);
void
midori_browser_set_current_page (MidoriBrowser* browser,
gint n);
gint
midori_browser_get_current_page (MidoriBrowser* browser);
void
midori_browser_set_current_tab (MidoriBrowser* browser,
GtkWidget* widget);
GtkWidget*
midori_browser_get_current_tab (MidoriBrowser* browser);
KatzeArray*
midori_browser_get_proxy_array (MidoriBrowser* browser);
void
midori_browser_quit (MidoriBrowser* browser);
G_END_DECLS
#endif /* __MIDORI_BROWSER_H__ */

772
midori/midori-extension.c Normal file
View file

@ -0,0 +1,772 @@
/*
Copyright (C) 2008-2009 Christian Dywan <christian@twotoasts.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#include "midori-extension.h"
#if HAVE_CONFIG_H
#include <config.h>
#endif
#include <katze/katze.h>
#include "sokoke.h"
#include <glib/gi18n.h>
G_DEFINE_TYPE (MidoriExtension, midori_extension, G_TYPE_OBJECT);
struct _MidoriExtensionPrivate
{
gchar* name;
gchar* description;
gchar* version;
gchar* authors;
MidoriApp* app;
gboolean active;
gchar* config_dir;
GList* lsettings;
GHashTable* settings;
GKeyFile* key_file;
};
typedef struct
{
gchar* name;
GType type;
gboolean default_value;
gboolean value;
} MESettingBoolean;
typedef struct
{
gchar* name;
GType type;
gint default_value;
gint value;
} MESettingInteger;
typedef struct
{
gchar* name;
GType type;
gchar* default_value;
gchar* value;
} MESettingString;
void me_setting_free (gpointer setting)
{
MESettingString* string_setting = (MESettingString*)setting;
g_free (string_setting->name);
if (string_setting->type == G_TYPE_STRING)
{
g_free (string_setting->default_value);
g_free (string_setting->value);
}
}
#define midori_extension_can_install_setting(extension, name) \
if (extension->priv->active) \
{ \
g_critical ("%s: Settings have to be installed before " \
"the extension is activated.", G_STRFUNC); \
return; \
} \
if (g_hash_table_lookup (extension->priv->settings, name)) \
{ \
g_critical ("%s: A setting with the name '%s' is already installed.", \
G_STRFUNC, name); \
return; \
}
#define me_setting_install(stype, _name, gtype, _default_value, _value) \
setting = g_new (stype, 1); \
setting->name = _name; \
setting->type = gtype; \
setting->default_value = _default_value; \
setting->value = _value; \
g_hash_table_insert (extension->priv->settings, setting->name, setting); \
extension->priv->lsettings = g_list_prepend \
(extension->priv->lsettings, setting);
#define me_setting_type(setting, gtype, rreturn) \
if (!setting) { \
g_critical ("%s: There is no setting with the name '%s' installed.", G_STRFUNC, name); \
rreturn; } \
if (setting->type != gtype) { \
g_critical ("%s: The setting '%s' is not a string.", G_STRFUNC, name); \
rreturn; }
enum
{
PROP_0,
PROP_NAME,
PROP_DESCRIPTION,
PROP_VERSION,
PROP_AUTHORS
};
enum {
ACTIVATE,
DEACTIVATE,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL];
static void
midori_extension_finalize (GObject* object);
static void
midori_extension_set_property (GObject* object,
guint prop_id,
const GValue* value,
GParamSpec* pspec);
static void
midori_extension_get_property (GObject* object,
guint prop_id,
GValue* value,
GParamSpec* pspec);
static void
midori_extension_class_init (MidoriExtensionClass* class)
{
GObjectClass* gobject_class;
GParamFlags flags;
signals[ACTIVATE] = g_signal_new (
"activate",
G_TYPE_FROM_CLASS (class),
(GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
0,
0,
NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE, 1,
MIDORI_TYPE_APP);
signals[DEACTIVATE] = g_signal_new (
"deactivate",
G_TYPE_FROM_CLASS (class),
(GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
0,
0,
NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0,
G_TYPE_NONE);
gobject_class = G_OBJECT_CLASS (class);
gobject_class->finalize = midori_extension_finalize;
gobject_class->set_property = midori_extension_set_property;
gobject_class->get_property = midori_extension_get_property;
flags = G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS;
g_object_class_install_property (gobject_class,
PROP_NAME,
g_param_spec_string (
"name",
"Name",
"The name of the extension",
NULL,
flags));
g_object_class_install_property (gobject_class,
PROP_DESCRIPTION,
g_param_spec_string (
"description",
"Description",
"The description of the extension",
NULL,
flags));
g_object_class_install_property (gobject_class,
PROP_VERSION,
g_param_spec_string (
"version",
"Version",
"The version of the extension",
NULL,
flags));
g_object_class_install_property (gobject_class,
PROP_AUTHORS,
g_param_spec_string (
"authors",
"Authors",
"The authors of the extension",
NULL,
flags));
g_type_class_add_private (class, sizeof (MidoriExtensionPrivate));
}
static void
midori_extension_activate_cb (MidoriExtension* extension,
MidoriApp* app)
{
GList* lsettings;
g_return_if_fail (MIDORI_IS_APP (app));
lsettings = g_list_first (extension->priv->lsettings);
/* If a configuration directory was requested before activation we
assume we should load and save settings. This is a detail that
extension writers shouldn't worry about. */
extension->priv->key_file = lsettings && extension->priv->config_dir
? g_key_file_new () : NULL;
if (extension->priv->key_file)
{
gchar* config_file;
GError* error = NULL;
config_file = g_build_filename (extension->priv->config_dir, "config", NULL);
if (!g_key_file_load_from_file (extension->priv->key_file, config_file,
G_KEY_FILE_KEEP_COMMENTS, &error))
{
if (error->code != G_FILE_ERROR_NOENT)
printf (_("The configuration of the extension '%s' couldn't be loaded: %s\n"),
extension->priv->name, error->message);
g_error_free (error);
}
}
while (lsettings)
{
MESettingString* setting = (MESettingString*)lsettings->data;
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);
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);
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);
else
setting->value = g_strdup (setting->default_value);
}
else
g_assert_not_reached ();
lsettings = g_list_next (lsettings);
}
extension->priv->app = g_object_ref (app);
extension->priv->active = TRUE;
/* FIXME: Disconnect all signal handlers */
}
static void
midori_extension_init (MidoriExtension* extension)
{
extension->priv = G_TYPE_INSTANCE_GET_PRIVATE (extension,
MIDORI_TYPE_EXTENSION, MidoriExtensionPrivate);
extension->priv->app = NULL;
extension->priv->active = FALSE;
extension->priv->config_dir = NULL;
extension->priv->lsettings = NULL;
extension->priv->settings = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, me_setting_free);
extension->priv->key_file = NULL;
g_signal_connect (extension, "activate",
G_CALLBACK (midori_extension_activate_cb), NULL);
}
static void
midori_extension_finalize (GObject* object)
{
MidoriExtension* extension = MIDORI_EXTENSION (object);
katze_object_assign (extension->priv->app, 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->config_dir, NULL);
g_list_free (extension->priv->lsettings);
g_hash_table_destroy (extension->priv->settings);
if (extension->priv->key_file)
g_key_file_free (extension->priv->key_file);
}
static void
midori_extension_set_property (GObject* object,
guint prop_id,
const GValue* value,
GParamSpec* pspec)
{
MidoriExtension* extension = MIDORI_EXTENSION (object);
switch (prop_id)
{
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_VERSION:
katze_assign (extension->priv->version, g_value_dup_string (value));
break;
case PROP_AUTHORS:
katze_assign (extension->priv->authors, g_value_dup_string (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
midori_extension_get_property (GObject* object,
guint prop_id,
GValue* value,
GParamSpec* pspec)
{
MidoriExtension* extension = MIDORI_EXTENSION (object);
switch (prop_id)
{
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_VERSION:
g_value_set_string (value, extension->priv->version);
break;
case PROP_AUTHORS:
g_value_set_string (value, extension->priv->authors);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
/**
* midori_extension_is_prepared:
* @extension: a #MidoriExtension
*
* Determines if @extension is prepared for use, for instance
* by ensuring that all required values are set and that it
* is actually activatable.
*
* Return value: %TRUE if @extension is ready for use
**/
gboolean
midori_extension_is_prepared (MidoriExtension* extension)
{
g_return_val_if_fail (MIDORI_IS_EXTENSION (extension), FALSE);
if (extension->priv->name && extension->priv->description
&& extension->priv->version && extension->priv->authors
&& g_signal_has_handler_pending (extension, signals[ACTIVATE], 0, FALSE))
return TRUE;
return FALSE;
}
/**
* midori_extension_is_active:
* @extension: a #MidoriExtension
*
* Determines if @extension is active.
*
* Return value: %TRUE if @extension is active
*
* Since: 0.1.2
**/
gboolean
midori_extension_is_active (MidoriExtension* extension)
{
g_return_val_if_fail (MIDORI_IS_EXTENSION (extension), FALSE);
return extension->priv->active;
}
/**
* midori_extension_deactivate:
* @extension: a #MidoriExtension
*
* Attempts to deactivate @extension.
**/
void
midori_extension_deactivate (MidoriExtension* extension)
{
g_return_if_fail (midori_extension_is_active (extension));
g_signal_emit (extension, signals[DEACTIVATE], 0);
extension->priv->active = FALSE;
katze_object_assign (extension->priv->app, NULL);
}
/**
* midori_extension_get_app:
* @extension: a #MidoriExtension
*
* Retrieves the #MidoriApp the extension belongs to. The
* extension has to be active.
*
* Return value: the #MidoriApp instance
*
* Since 0.1.6
**/
MidoriApp*
midori_extension_get_app (MidoriExtension* extension)
{
g_return_val_if_fail (midori_extension_is_active (extension), NULL);
return extension->priv->app;
}
/**
* midori_extension_get_config_dir:
* @extension: a #MidoriExtension
*
* Retrieves the path to a directory reserved for configuration
* files specific to the extension. For that purpose the 'name'
* of the extension is actually part of the path.
*
* If settings are installed on the extension, they will be
* loaded from and saved to a file "config" in this path.
*
* Return value: a path, such as ~/.config/midori/extensions/name
**/
const gchar*
midori_extension_get_config_dir (MidoriExtension* extension)
{
g_return_val_if_fail (midori_extension_is_prepared (extension), NULL);
if (!extension->priv->config_dir)
extension->priv->config_dir = g_build_filename (
sokoke_set_config_dir (NULL), "extensions",
extension->priv->name, NULL);
return extension->priv->config_dir;
}
/**
* midori_extension_install_boolean:
* @extension: a #MidoriExtension
* @name: the name of the setting
* @default_value: the default value
*
* Installs a boolean that can be used to conveniently
* store user configuration.
*
* Note that all settings have to be installed before
* the extension is activated.
*
* Since: 0.1.3
**/
void
midori_extension_install_boolean (MidoriExtension* extension,
const gchar* name,
gboolean default_value)
{
MESettingBoolean* setting;
g_return_if_fail (midori_extension_is_prepared (extension));
midori_extension_can_install_setting (extension, name);
me_setting_install (MESettingBoolean, g_strdup (name), G_TYPE_BOOLEAN,
default_value, FALSE);
}
/**
* midori_extension_get_boolean:
* @extension: a #MidoriExtension
* @name: the name of the setting
*
* Retrieves the value of the specified setting.
*
* Since: 0.1.3
**/
gboolean
midori_extension_get_boolean (MidoriExtension* extension,
const gchar* name)
{
MESettingBoolean* setting;
g_return_val_if_fail (midori_extension_is_prepared (extension), FALSE);
g_return_val_if_fail (name != NULL, FALSE);
setting = g_hash_table_lookup (extension->priv->settings, name);
me_setting_type (setting, G_TYPE_BOOLEAN, return FALSE);
return setting->value;
}
/**
* midori_extension_set_boolean:
* @extension: a #MidoriExtension
* @name: the name of the setting
* @value: the new value
*
* Assigns a new value to the specified setting.
*
* Since: 0.1.3
**/
void
midori_extension_set_boolean (MidoriExtension* extension,
const gchar* name,
gboolean value)
{
MESettingBoolean* setting;
g_return_if_fail (midori_extension_is_active (extension));
g_return_if_fail (name != NULL);
setting = g_hash_table_lookup (extension->priv->settings, name);
me_setting_type (setting, G_TYPE_BOOLEAN, return);
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);
g_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_install_integer:
* @extension: a #MidoriExtension
* @name: the name of the setting
* @default_value: the default value
*
* Installs an integer that can be used to conveniently
* store user configuration.
*
* Note that all settings have to be installed before
* the extension is activated.
*
* Since: 0.1.3
**/
void
midori_extension_install_integer (MidoriExtension* extension,
const gchar* name,
gint default_value)
{
MESettingInteger* setting;
g_return_if_fail (midori_extension_is_prepared (extension));
midori_extension_can_install_setting (extension, name);
me_setting_install (MESettingInteger, g_strdup (name), G_TYPE_INT,
default_value, 0);
}
/**
* midori_extension_get_integer:
* @extension: a #MidoriExtension
* @name: the name of the setting
*
* Retrieves the value of the specified setting.
*
* Since: 0.1.3
**/
gint
midori_extension_get_integer (MidoriExtension* extension,
const gchar* name)
{
MESettingInteger* setting;
g_return_val_if_fail (midori_extension_is_prepared (extension), 0);
g_return_val_if_fail (name != NULL, 0);
setting = g_hash_table_lookup (extension->priv->settings, name);
me_setting_type (setting, G_TYPE_INT, return 0);
return setting->value;
}
/**
* midori_extension_set_integer:
* @extension: a #MidoriExtension
* @name: the name of the setting
* @value: the new value
*
* Assigns a new value to the specified setting.
*
* Since: 0.1.3
**/
void
midori_extension_set_integer (MidoriExtension* extension,
const gchar* name,
gint value)
{
MESettingInteger* setting;
g_return_if_fail (midori_extension_is_active (extension));
g_return_if_fail (name != NULL);
setting = g_hash_table_lookup (extension->priv->settings, name);
me_setting_type (setting, G_TYPE_INT, return);
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);
g_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_install_string:
* @extension: a #MidoriExtension
* @name: the name of the setting
* @default_value: the default value
*
* Installs a string that can be used to conveniently
* store user configuration.
*
* Note that all settings have to be installed before
* the extension is activated.
*
* Since: 0.1.3
**/
void
midori_extension_install_string (MidoriExtension* extension,
const gchar* name,
const gchar* default_value)
{
MESettingString* setting;
g_return_if_fail (midori_extension_is_prepared (extension));
midori_extension_can_install_setting (extension, name);
me_setting_install (MESettingString, g_strdup (name), G_TYPE_STRING,
g_strdup (default_value), NULL);
}
/**
* midori_extension_get_string:
* @extension: a #MidoriExtension
* @name: the name of the setting
*
* Retrieves the value of the specified setting.
*
* Since: 0.1.3
**/
const gchar*
midori_extension_get_string (MidoriExtension* extension,
const gchar* name)
{
MESettingString* setting;
g_return_val_if_fail (midori_extension_is_prepared (extension), NULL);
g_return_val_if_fail (name != NULL, NULL);
setting = g_hash_table_lookup (extension->priv->settings, name);
me_setting_type (setting, G_TYPE_STRING, return NULL);
return setting->value;
}
/**
* midori_extension_set_string:
* @extension: a #MidoriExtension
* @name: the name of the setting
* @value: the new value
*
* Assigns a new value to the specified setting.
*
* Since: 0.1.3
**/
void
midori_extension_set_string (MidoriExtension* extension,
const gchar* name,
const gchar* value)
{
MESettingString* setting;
g_return_if_fail (midori_extension_is_active (extension));
g_return_if_fail (name != NULL);
setting = g_hash_table_lookup (extension->priv->settings, name);
me_setting_type (setting, G_TYPE_STRING, return);
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);
g_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);
}
}
}

110
midori/midori-extension.h Normal file
View file

@ -0,0 +1,110 @@
/*
Copyright (C) 2008 Christian Dywan <christian@twotoasts.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#ifndef __MIDORI_EXTENSION_H__
#define __MIDORI_EXTENSION_H__
#include "midori-app.h"
G_BEGIN_DECLS
#define MIDORI_TYPE_EXTENSION \
(midori_extension_get_type ())
#define MIDORI_EXTENSION(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), MIDORI_TYPE_EXTENSION, MidoriExtension))
#define MIDORI_EXTENSION_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), MIDORI_TYPE_EXTENSION, MidoriExtensionClass))
#define MIDORI_IS_EXTENSION(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), MIDORI_TYPE_EXTENSION))
#define MIDORI_IS_EXTENSION_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), MIDORI_TYPE_EXTENSION))
#define MIDORI_EXTENSION_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), MIDORI_TYPE_EXTENSION, MidoriExtensionClass))
typedef struct _MidoriExtension MidoriExtension;
typedef struct _MidoriExtensionClass MidoriExtensionClass;
typedef struct _MidoriExtensionPrivate MidoriExtensionPrivate;
struct _MidoriExtension
{
GObject parent_instance;
MidoriExtensionPrivate* priv;
};
struct _MidoriExtensionClass
{
GObjectClass parent_class;
};
GType
midori_extension_get_type (void);
gboolean
midori_extension_is_prepared (MidoriExtension* extension);
gboolean
midori_extension_is_active (MidoriExtension* extension);
void
midori_extension_deactivate (MidoriExtension* extension);
MidoriApp*
midori_extension_get_app (MidoriExtension* extension);
const gchar*
midori_extension_get_config_dir (MidoriExtension* extension);
void
midori_extension_install_boolean (MidoriExtension* extension,
const gchar* name,
gboolean default_value);
gboolean
midori_extension_get_boolean (MidoriExtension* extension,
const gchar* name);
void
midori_extension_set_boolean (MidoriExtension* extension,
const gchar* name,
gboolean value);
void
midori_extension_install_integer (MidoriExtension* extension,
const gchar* name,
gint default_value);
gint
midori_extension_get_integer (MidoriExtension* extension,
const gchar* name);
void
midori_extension_set_integer (MidoriExtension* extension,
const gchar* name,
gint value);
void
midori_extension_install_string (MidoriExtension* extension,
const gchar* name,
const gchar* default_value);
const gchar*
midori_extension_get_string (MidoriExtension* extension,
const gchar* name);
void
midori_extension_set_string (MidoriExtension* extension,
const gchar* name,
const gchar* value);
G_END_DECLS
#endif /* __MIDORI_EXTENSION_H__ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,108 @@
/*
Copyright (C) 2008 Christian Dywan <christian@twotoasts.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#ifndef __MIDORI_LOCATION_ACTION_H__
#define __MIDORI_LOCATION_ACTION_H__
#include "midori-locationentry.h"
#include <katze/katze.h>
G_BEGIN_DECLS
#define MIDORI_TYPE_LOCATION_ACTION \
(midori_location_action_get_type ())
#define MIDORI_LOCATION_ACTION(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), MIDORI_TYPE_LOCATION_ACTION, MidoriLocationAction))
#define MIDORI_LOCATION_ACTION_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), MIDORI_TYPE_LOCATION_ACTION, MidoriLocationActionClass))
#define MIDORI_IS_LOCATION_ACTION(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), MIDORI_TYPE_LOCATION_ACTION))
#define MIDORI_IS_LOCATION_ACTION_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), MIDORI_TYPE_LOCATION_ACTION))
#define MIDORI_LOCATION_ACTION_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), MIDORI_TYPE_LOCATION_ACTION, MidoriLocationActionClass))
typedef struct _MidoriLocationAction MidoriLocationAction;
typedef struct _MidoriLocationActionClass MidoriLocationActionClass;
struct _MidoriLocationEntryItem
{
GdkPixbuf* favicon;
const gchar* uri;
const gchar* title;
};
GType
midori_location_action_get_type (void);
void
midori_location_action_freeze (MidoriLocationAction* location_action);
void
midori_location_action_thaw (MidoriLocationAction* location_action);
const gchar*
midori_location_action_get_uri (MidoriLocationAction* location_action);
void
midori_location_action_set_uri (MidoriLocationAction* location_action,
const gchar* uri);
void
midori_location_action_set_icon (MidoriLocationAction* location_action,
GdkPixbuf* icon);
void
midori_location_action_add_uri (MidoriLocationAction* location_action,
const gchar* uri);
void
midori_location_action_add_item (MidoriLocationAction* location_action,
const gchar* uri,
GdkPixbuf* icon,
const gchar* title);
void
midori_location_action_set_icon_for_uri (MidoriLocationAction* location_action,
GdkPixbuf* icon,
const gchar* text);
void
midori_location_action_set_title_for_uri (MidoriLocationAction* location_action,
const gchar* title,
const gchar* text);
void
midori_location_action_set_search_engines (MidoriLocationAction* location_action,
KatzeArray* search_engines);
gdouble
midori_location_action_get_progress (MidoriLocationAction* location_action);
void
midori_location_action_set_progress (MidoriLocationAction* location_action,
gdouble progress);
void
midori_location_action_set_secondary_icon (MidoriLocationAction* location_action,
const gchar* stock_id);
void
midori_location_action_delete_item_from_uri (MidoriLocationAction* location_action,
const gchar* uri);
void
midori_location_action_clear (MidoriLocationAction* location_action);
G_END_DECLS
#endif /* __MIDORI_LOCATION_ACTION_H__ */

View file

@ -0,0 +1,436 @@
/*
Copyright (C) 2008 Dale Whittaker <dayul@users.sf.net>
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-locationentry.h"
#include "gtkiconentry.h"
#include "sokoke.h"
#include <gdk/gdkkeysyms.h>
struct _MidoriLocationEntry
{
GtkComboBoxEntry parent_instance;
gdouble progress;
};
struct _MidoriLocationEntryClass
{
GtkComboBoxEntryClass parent_class;
};
G_DEFINE_TYPE (MidoriLocationEntry,
midori_location_entry, GTK_TYPE_COMBO_BOX_ENTRY)
enum
{
FAVICON_COL,
URI_COL,
TITLE_COL,
VISITS_COL,
VISIBLE_COL,
N_COLS
};
static gboolean
entry_key_press_event (GtkWidget* widget,
GdkEventKey* event,
MidoriLocationEntry* location_entry);
static void
midori_location_entry_class_init (MidoriLocationEntryClass* class)
{
}
#if !GTK_CHECK_VERSION (2, 16, 0)
/* GTK+/ GtkEntry internal helper function
Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
Modified by the GTK+ Team and others 1997-2000
Copied from Gtk+ 2.13, whitespace adjusted */
static void
gtk_entry_get_pixel_ranges (GtkEntry *entry,
gint **ranges,
gint *n_ranges)
{
gint start_char, end_char;
if (gtk_editable_get_selection_bounds (GTK_EDITABLE (entry),
&start_char, &end_char))
{
PangoLayout *layout = gtk_entry_get_layout (entry);
PangoLayoutLine *line = pango_layout_get_lines (layout)->data;
const char *text = pango_layout_get_text (layout);
gsize start_index = g_utf8_offset_to_pointer (text, start_char) - text;
gsize end_index = g_utf8_offset_to_pointer (text, end_char) - text;
gint real_n_ranges, i;
pango_layout_line_get_x_ranges (line,
start_index, end_index, ranges, &real_n_ranges);
if (ranges)
{
gint *r = *ranges;
for (i = 0; i < real_n_ranges; ++i)
{
r[2 * i + 1] = (r[2 * i + 1] - r[2 * i]) / PANGO_SCALE;
r[2 * i] = r[2 * i] / PANGO_SCALE;
}
}
if (n_ranges)
*n_ranges = real_n_ranges;
}
else
{
if (n_ranges)
*n_ranges = 0;
if (ranges)
*ranges = NULL;
}
}
/* GTK+/ GtkEntry internal helper function
Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
Modified by the GTK+ Team and others 1997-2000
Copied from Gtk+ 2.13, whitespace adjusted
Code adjusted to not rely on internal qdata */
static void
_gtk_entry_effective_inner_border (GtkEntry *entry,
GtkBorder *border)
{
static const GtkBorder default_inner_border = { 2, 2, 2, 2 };
GtkBorder *tmp_border;
tmp_border = (GtkBorder*) gtk_entry_get_inner_border (entry);
if (tmp_border)
{
*border = *tmp_border;
return;
}
gtk_widget_style_get (GTK_WIDGET (entry), "inner-border", &tmp_border, NULL);
if (tmp_border)
{
*border = *tmp_border;
gtk_border_free (tmp_border);
return;
}
*border = default_inner_border;
}
static void
gtk_entry_borders (GtkEntry* entry,
gint* xborder,
gint* yborder,
gboolean* interior_focus,
gint* focus_width)
{
GtkWidget *widget = GTK_WIDGET (entry);
if (entry->has_frame)
{
*xborder = widget->style->xthickness;
*yborder = widget->style->ythickness;
}
else
{
*xborder = 0;
*yborder = 0;
}
gtk_widget_style_get (widget, "interior-focus", interior_focus,
"focus-line-width", focus_width, NULL);
if (interior_focus)
{
*xborder += *focus_width;
*yborder += *focus_width;
}
}
/* GTK+/ GtkEntry internal helper function
Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
Modified by the GTK+ Team and others 1997-2000
Copied from Gtk+ 2.13, whitespace adjusted */
static void
gtk_entry_get_text_area_size (GtkEntry *entry,
gint *x,
gint *y,
gint *width,
gint *height)
{
gint frame_height;
gint xborder, yborder;
gboolean interior_focus;
gint focus_width;
GtkRequisition requisition;
GtkWidget *widget = GTK_WIDGET (entry);
gtk_widget_get_child_requisition (widget, &requisition);
gtk_entry_borders (entry, &xborder, &yborder, &interior_focus, &focus_width);
if (GTK_WIDGET_REALIZED (widget))
gdk_drawable_get_size (widget->window, NULL, &frame_height);
else
frame_height = requisition.height;
if (GTK_WIDGET_HAS_FOCUS (widget) && interior_focus)
frame_height -= 2 * focus_width;
if (x)
*x = xborder;
if (y)
*y = frame_height / 2 - (requisition.height - yborder * 2) / 2;
if (width)
*width = GTK_WIDGET (entry)->allocation.width - xborder * 2;
if (height)
*height = requisition.height - yborder * 2;
}
/* GTK+/ GtkEntry internal helper function
Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
Modified by the GTK+ Team and others 1997-2000
Copied from Gtk+ 2.13, whitespace adjusted */
static void
get_layout_position (GtkEntry *entry,
gint *x,
gint *y)
{
PangoLayout *layout;
PangoRectangle logical_rect;
gint area_width, area_height;
GtkBorder inner_border;
gint y_pos;
PangoLayoutLine *line;
layout = gtk_entry_get_layout (entry);
gtk_entry_get_text_area_size (entry, NULL, NULL, &area_width, &area_height);
_gtk_entry_effective_inner_border (entry, &inner_border);
area_height = PANGO_SCALE *
(area_height - inner_border.top - inner_border.bottom);
line = pango_layout_get_lines (layout)->data;
pango_layout_line_get_extents (line, NULL, &logical_rect);
/* Align primarily for locale's ascent/descent */
y_pos = ((area_height - entry->ascent - entry->descent) / 2 +
entry->ascent + logical_rect.y);
/* Now see if we need to adjust to fit in actual drawn string */
if (logical_rect.height > area_height)
y_pos = (area_height - logical_rect.height) / 2;
else if (y_pos < 0)
y_pos = 0;
else if (y_pos + logical_rect.height > area_height)
y_pos = area_height - logical_rect.height;
y_pos = inner_border.top + y_pos / PANGO_SCALE;
if (x)
*x = inner_border.left - entry->scroll_offset;
if (y)
*y = y_pos;
}
/* GTK+/ GtkEntry internal helper function
Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
Modified by the GTK+ Team and others 1997-2000
Copied from Gtk+ 2.13, whitespace adjusted
Code adjusted to not rely on internal _gtk_entry_ensure_layout */
static void
gtk_entry_draw_text (GtkEntry *entry)
{
GtkWidget *widget;
if (!entry->visible && entry->invisible_char == 0)
return;
if (GTK_WIDGET_DRAWABLE (entry))
{
PangoLayout *layout = gtk_entry_get_layout (entry);
cairo_t *cr;
gint x, y;
gint start_pos, end_pos;
widget = GTK_WIDGET (entry);
get_layout_position (entry, &x, &y);
cr = gdk_cairo_create (entry->text_area);
cairo_move_to (cr, x, y);
gdk_cairo_set_source_color (cr, &widget->style->text [widget->state]);
pango_cairo_show_layout (cr, layout);
if (gtk_editable_get_selection_bounds (GTK_EDITABLE (entry),
&start_pos, &end_pos))
{
gint *ranges;
gint n_ranges, i;
PangoRectangle logical_rect;
GdkColor *selection_color, *text_color;
GtkBorder inner_border;
pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
gtk_entry_get_pixel_ranges (entry, &ranges, &n_ranges);
if (GTK_WIDGET_HAS_FOCUS (entry))
{
selection_color = &widget->style->base [GTK_STATE_SELECTED];
text_color = &widget->style->text [GTK_STATE_SELECTED];
}
else
{
selection_color = &widget->style->base [GTK_STATE_ACTIVE];
text_color = &widget->style->text [GTK_STATE_ACTIVE];
}
_gtk_entry_effective_inner_border (entry, &inner_border);
for (i = 0; i < n_ranges; ++i)
cairo_rectangle (cr,
inner_border.left -
entry->scroll_offset + ranges[2 * i],
y,
ranges[2 * i + 1],
logical_rect.height);
cairo_clip (cr);
gdk_cairo_set_source_color (cr, selection_color);
cairo_paint (cr);
cairo_move_to (cr, x, y);
gdk_cairo_set_source_color (cr, text_color);
pango_cairo_show_layout (cr, layout);
g_free (ranges);
}
cairo_destroy (cr);
}
}
static gboolean
entry_expose_event (GtkWidget* entry,
GdkEventExpose* event,
MidoriLocationEntry* location_entry)
{
GdkWindow* text_area;
gint width, height;
text_area = GTK_ENTRY (entry)->text_area;
gdk_drawable_get_size (text_area, &width, &height);
if (location_entry->progress > 0.0)
{
gtk_paint_box (entry->style, text_area,
GTK_STATE_SELECTED, GTK_SHADOW_OUT,
&event->area, entry, "bar",
0, 0, location_entry->progress * width, height);
gtk_entry_draw_text (GTK_ENTRY (entry));
}
return FALSE;
}
#endif
void
midori_location_entry_set_progress (MidoriLocationEntry* location_entry,
gdouble progress)
{
GtkWidget* child;
g_return_if_fail (MIDORI_IS_LOCATION_ENTRY (location_entry));
location_entry->progress = CLAMP (progress, 0.0, 1.0);
child = gtk_bin_get_child (GTK_BIN (location_entry));
#if !GTK_CHECK_VERSION (2, 16, 0)
if (GTK_ENTRY (child)->text_area)
gdk_window_invalidate_rect (GTK_ENTRY (child)->text_area, NULL, FALSE);
#else
gtk_entry_set_progress_fraction (GTK_ENTRY (child), progress);
#endif
}
static void
midori_location_entry_init (MidoriLocationEntry* location_entry)
{
GtkWidget* entry;
/* We want the widget to have appears-as-list applied */
gtk_rc_parse_string ("style \"midori-location-entry-style\" {\n"
" GtkComboBox::appears-as-list = 1\n }\n"
"widget_class \"*MidoriLocationEntry\" "
"style \"midori-location-entry-style\"\n");
location_entry->progress = 0.0;
entry = gtk_icon_entry_new ();
gtk_icon_entry_set_icon_from_stock (GTK_ICON_ENTRY (entry),
GTK_ICON_ENTRY_PRIMARY, GTK_STOCK_FILE);
gtk_icon_entry_set_icon_highlight (GTK_ICON_ENTRY (entry),
GTK_ICON_ENTRY_SECONDARY, TRUE);
g_signal_connect_after (entry, "key-press-event",
G_CALLBACK (entry_key_press_event), location_entry);
#if !GTK_CHECK_VERSION (2, 16, 0)
g_signal_connect_after (entry, "expose-event",
G_CALLBACK (entry_expose_event), location_entry);
#endif
gtk_widget_show (entry);
gtk_container_add (GTK_CONTAINER (location_entry), entry);
}
static gboolean
entry_key_press_event (GtkWidget* widget,
GdkEventKey* event,
MidoriLocationEntry* location_entry)
{
switch (event->keyval)
{
case GDK_Down:
case GDK_Up:
{
if (!katze_object_get_boolean (location_entry, "popup-shown"))
gtk_combo_box_popup (GTK_COMBO_BOX (location_entry));
return TRUE;
}
}
return FALSE;
}
/**
* midori_location_entry_new:
*
* Creates a new #MidoriLocationEntry.
*
* Return value: a new #MidoriLocationEntry
**/
GtkWidget*
midori_location_entry_new (void)
{
return g_object_new (MIDORI_TYPE_LOCATION_ENTRY, NULL);
}

View file

@ -0,0 +1,42 @@
/*
Copyright (C) 2008 Dale Whittaker <dayul@users.sf.net>
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_LOCATION_ENTRY_H__
#define __MIDORI_LOCATION_ENTRY_H__
#include <gtk/gtk.h>
G_BEGIN_DECLS
#define MIDORI_TYPE_LOCATION_ENTRY (midori_location_entry_get_type ())
#define MIDORI_LOCATION_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MIDORI_TYPE_LOCATION_ENTRY, MidoriLocationEntry))
#define MIDORI_LOCATION_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MIDORI_TYPE_LOCATION_ENTRY, MidoriLocationEntryClass))
#define MIDORI_IS_LOCATION_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MIDORI_TYPE_LOCATION_ENTRY))
#define MIDORI_IS_LOCATION_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MIDORI_TYPE_LOCATION_ENTRY))
#define MIDORI_LOCATION_ENTRY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MIDORI_TYPE_LOCATION_ENTRY, MidoriLocationEntryClass))
typedef struct _MidoriLocationEntry MidoriLocationEntry;
typedef struct _MidoriLocationEntryClass MidoriLocationEntryClass;
typedef struct _MidoriLocationEntryItem MidoriLocationEntryItem;
GType
midori_location_entry_get_type (void);
GtkWidget*
midori_location_entry_new (void);
void
midori_location_entry_set_progress (MidoriLocationEntry* location_entry,
gdouble progress);
G_END_DECLS
#endif /* __MIDORI_LOCATION_ENTRY_H__ */

943
midori/midori-panel.c Normal file
View file

@ -0,0 +1,943 @@
/*
Copyright (C) 2007-2009 Christian Dywan <christian@twotoasts.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#include "midori-panel.h"
#include "midori-view.h"
#include "compat.h"
#include "marshal.h"
#include "sokoke.h"
#include <glib/gi18n.h>
struct _MidoriPanel
{
GtkHBox parent_instance;
GtkWidget* toolbar;
GtkToolItem* button_align;
GtkWidget* toolbar_label;
GtkWidget* frame;
GtkWidget* toolbook;
GtkWidget* notebook;
GtkMenu* menu;
gboolean right_aligned;
};
struct _MidoriPanelClass
{
GtkHBoxClass parent_class;
/* Signals */
gboolean
(*close) (MidoriPanel* panel);
};
G_DEFINE_TYPE (MidoriPanel, midori_panel, GTK_TYPE_HBOX)
enum
{
PROP_0,
PROP_SHADOW_TYPE,
PROP_MENU,
PROP_PAGE,
PROP_RIGHT_ALIGNED,
};
enum {
CLOSE,
SWITCH_PAGE,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL];
static void
midori_panel_finalize (GObject* object);
static void
midori_panel_set_property (GObject* object,
guint prop_id,
const GValue* value,
GParamSpec* pspec);
static void
midori_panel_get_property (GObject* object,
guint prop_id,
GValue* value,
GParamSpec* pspec);
static gboolean
midori_panel_close (MidoriPanel* panel)
{
gtk_widget_hide (GTK_WIDGET (panel));
return FALSE;
}
static void
midori_panel_class_init (MidoriPanelClass* class)
{
GObjectClass* gobject_class;
GParamFlags flags;
signals[CLOSE] = g_signal_new (
"close",
G_TYPE_FROM_CLASS (class),
(GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
G_STRUCT_OFFSET (MidoriPanelClass, close),
g_signal_accumulator_true_handled,
NULL,
midori_cclosure_marshal_BOOLEAN__VOID,
G_TYPE_BOOLEAN, 0);
signals[SWITCH_PAGE] = g_signal_new (
"switch-page",
G_TYPE_FROM_CLASS (class),
(GSignalFlags)(G_SIGNAL_RUN_LAST),
0,
0,
NULL,
g_cclosure_marshal_VOID__INT,
G_TYPE_NONE, 1,
G_TYPE_INT);
gobject_class = G_OBJECT_CLASS (class);
gobject_class->finalize = midori_panel_finalize;
gobject_class->set_property = midori_panel_set_property;
gobject_class->get_property = midori_panel_get_property;
class->close = midori_panel_close;
flags = G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS;
g_object_class_install_property (gobject_class,
PROP_SHADOW_TYPE,
g_param_spec_enum (
"shadow-type",
"Shadow Type",
"Appearance of the shadow around each panel",
GTK_TYPE_SHADOW_TYPE,
GTK_SHADOW_NONE,
flags));
g_object_class_install_property (gobject_class,
PROP_MENU,
g_param_spec_object (
"menu",
"Menu",
"Menu to hold panel items",
GTK_TYPE_MENU,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class,
PROP_PAGE,
g_param_spec_int (
"page",
"Page",
"The index of the current page",
-1, G_MAXINT, -1,
flags));
/**
* MidoriWebSettings:right-aligned:
*
* Whether to align the panel on the right.
*
* Since: 0.1.3
*/
g_object_class_install_property (gobject_class,
PROP_RIGHT_ALIGNED,
g_param_spec_boolean (
"right-aligned",
"Right aligned",
"Whether the panel is aligned to the right",
FALSE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
}
static void
midori_panel_button_close_clicked_cb (GtkWidget* toolitem,
MidoriPanel* panel)
{
gboolean return_value;
g_signal_emit (panel, signals[CLOSE], 0, &return_value);
}
static GtkToolItem*
midori_panel_construct_tool_item (MidoriPanel* panel,
MidoriViewable* viewable);
static GtkWidget*
_midori_panel_child_for_scrolled (MidoriPanel* panel,
GtkWidget* scrolled);
static gboolean
midori_panel_detached_window_delete_event_cb (GtkWidget* window,
GdkEvent* event,
MidoriPanel* panel)
{
/* FIXME: The panel will not end up at its original position */
/* FIXME: The menuitem may be mispositioned */
GtkWidget* vbox = gtk_bin_get_child (GTK_BIN (window));
GtkWidget* scrolled = g_object_get_data (G_OBJECT (window), "scrolled");
GtkWidget* toolbar = g_object_get_data (G_OBJECT (scrolled), "panel-toolbar");
GtkWidget* menuitem = g_object_get_data (G_OBJECT (scrolled), "panel-menuitem");
GtkToolItem* toolitem;
g_object_ref (toolbar);
gtk_container_remove (GTK_CONTAINER (vbox), toolbar);
gtk_container_add (GTK_CONTAINER (panel->toolbook), toolbar);
g_object_unref (toolbar);
g_object_ref (scrolled);
gtk_container_remove (GTK_CONTAINER (vbox), scrolled);
gtk_container_add (GTK_CONTAINER (panel->notebook), scrolled);
g_object_unref (scrolled);
toolitem = midori_panel_construct_tool_item (panel,
MIDORI_VIEWABLE (_midori_panel_child_for_scrolled (panel, scrolled)));
if (menuitem)
{
gtk_widget_show (menuitem);
g_object_set_data (G_OBJECT (menuitem), "toolitem", toolitem);
}
return FALSE;
}
static void
midori_panel_button_detach_clicked_cb (GtkWidget* toolbutton,
MidoriPanel* panel)
{
/* FIXME: Use stock icon for window */
/* FIXME: What happens when the browser is destroyed? */
/* FIXME: What about multiple browsers? */
/* FIXME: Should we remember if the child was detached? */
/* FIXME: Fix label of the sidepanel after removing the widgets */
gint n = midori_panel_get_current_page (panel);
GtkToolItem* toolitem = gtk_toolbar_get_nth_item (
GTK_TOOLBAR (panel->toolbar), n);
const gchar* title = gtk_tool_button_get_label (GTK_TOOL_BUTTON (toolitem));
GtkWidget* toolbar = gtk_notebook_get_nth_page (
GTK_NOTEBOOK (panel->toolbook), n);
GtkWidget* scrolled = gtk_notebook_get_nth_page (
GTK_NOTEBOOK (panel->notebook), n);
GtkWidget* menuitem = g_object_get_data (G_OBJECT (scrolled), "panel-menuitem");
GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
GtkWidget* vbox = gtk_vbox_new (FALSE, 0);
g_object_set_data (G_OBJECT (window), "scrolled", scrolled);
gtk_window_set_title (GTK_WINDOW (window), title);
gtk_window_set_default_size (GTK_WINDOW (window), 250, 400);
gtk_window_set_transient_for (GTK_WINDOW (window),
GTK_WINDOW (gtk_widget_get_toplevel (panel->notebook)));
gtk_widget_show (vbox);
gtk_container_add (GTK_CONTAINER (window), vbox);
if (menuitem)
gtk_widget_hide (menuitem);
gtk_container_remove (GTK_CONTAINER (panel->toolbar), GTK_WIDGET (toolitem));
g_object_ref (toolbar);
gtk_container_remove (GTK_CONTAINER (panel->toolbook), toolbar);
gtk_box_pack_start (GTK_BOX (vbox), toolbar, FALSE, FALSE, 0);
g_object_unref (toolbar);
g_object_set_data (G_OBJECT (scrolled), "panel-toolbar", toolbar);
g_object_ref (scrolled);
gtk_container_remove (GTK_CONTAINER (panel->notebook), scrolled);
gtk_box_pack_start (GTK_BOX (vbox), scrolled, TRUE, TRUE, 0);
g_object_unref (scrolled);
g_signal_connect (window, "delete-event",
G_CALLBACK (midori_panel_detached_window_delete_event_cb), panel);
gtk_widget_show (window);
}
static void
midori_panel_button_align_clicked_cb (GtkWidget* toolitem,
MidoriPanel* panel)
{
midori_panel_set_right_aligned (panel, !panel->right_aligned);
}
static void
midori_panel_destroy_cb (MidoriPanel* panel)
{
/* Destroy pages first, so they don't need special care */
gtk_container_foreach (GTK_CONTAINER (panel->notebook),
(GtkCallback) gtk_widget_destroy, NULL);
}
static void
midori_panel_init (MidoriPanel* panel)
{
GtkWidget* vbox;
GtkWidget* labelbar;
GtkToolItem* toolitem;
panel->right_aligned = FALSE;
/* Create the sidebar */
panel->toolbar = gtk_toolbar_new ();
gtk_toolbar_set_style (GTK_TOOLBAR (panel->toolbar), GTK_TOOLBAR_BOTH);
gtk_toolbar_set_icon_size (GTK_TOOLBAR (panel->toolbar),
GTK_ICON_SIZE_BUTTON);
gtk_toolbar_set_orientation (GTK_TOOLBAR (panel->toolbar),
GTK_ORIENTATION_VERTICAL);
gtk_box_pack_start (GTK_BOX (panel), panel->toolbar, FALSE, FALSE, 0);
gtk_widget_show_all (panel->toolbar);
vbox = gtk_vbox_new (FALSE, 0);
gtk_box_pack_start (GTK_BOX (panel), vbox, TRUE, TRUE, 0);
/* Create the titlebar */
labelbar = gtk_toolbar_new ();
gtk_toolbar_set_icon_size (GTK_TOOLBAR (labelbar), GTK_ICON_SIZE_MENU);
gtk_toolbar_set_style (GTK_TOOLBAR (labelbar), GTK_TOOLBAR_ICONS);
toolitem = gtk_tool_item_new ();
gtk_tool_item_set_expand (toolitem, TRUE);
panel->toolbar_label = gtk_label_new (NULL);
gtk_misc_set_alignment (GTK_MISC (panel->toolbar_label), 0, 0.5);
gtk_container_add (GTK_CONTAINER (toolitem), panel->toolbar_label);
gtk_container_set_border_width (GTK_CONTAINER (toolitem), 6);
gtk_toolbar_insert (GTK_TOOLBAR (labelbar), toolitem, -1);
toolitem = gtk_tool_button_new_from_stock (GTK_STOCK_FULLSCREEN);
gtk_tool_button_set_label (GTK_TOOL_BUTTON (toolitem),
_("Detach chosen panel from the window"));
gtk_tool_item_set_tooltip_text (GTK_TOOL_ITEM (toolitem),
_("Whether to detach the chosen panel from the window"));
g_signal_connect (toolitem, "clicked",
G_CALLBACK (midori_panel_button_detach_clicked_cb), panel);
#if HAVE_OSX
gtk_toolbar_insert (GTK_TOOLBAR (labelbar), toolitem, 0);
#else
gtk_toolbar_insert (GTK_TOOLBAR (labelbar), toolitem, -1);
#endif
toolitem = gtk_tool_button_new_from_stock (GTK_STOCK_GO_FORWARD);
gtk_tool_button_set_label (GTK_TOOL_BUTTON (toolitem),
_("Align sidepanel on the right"));
gtk_tool_item_set_tooltip_text (GTK_TOOL_ITEM (toolitem),
_("Whether to align the sidepanel on the right"));
g_signal_connect (toolitem, "clicked",
G_CALLBACK (midori_panel_button_align_clicked_cb), panel);
#if HAVE_OSX
gtk_toolbar_insert (GTK_TOOLBAR (labelbar), toolitem, 0);
#else
gtk_toolbar_insert (GTK_TOOLBAR (labelbar), toolitem, -1);
#endif
panel->button_align = toolitem;
toolitem = gtk_tool_button_new_from_stock (GTK_STOCK_CLOSE);
gtk_tool_button_set_label (GTK_TOOL_BUTTON (toolitem), _("Close panel"));
gtk_tool_item_set_tooltip_text (GTK_TOOL_ITEM (toolitem), _("Close panel"));
g_signal_connect (toolitem, "clicked",
G_CALLBACK (midori_panel_button_close_clicked_cb), panel);
#if HAVE_OSX
gtk_toolbar_insert (GTK_TOOLBAR (labelbar), toolitem, 0);
#else
gtk_toolbar_insert (GTK_TOOLBAR (labelbar), toolitem, -1);
#endif
gtk_box_pack_start (GTK_BOX (vbox), labelbar, FALSE, FALSE, 0);
gtk_widget_show_all (vbox);
/* Create the toolbook */
panel->toolbook = gtk_notebook_new ();
gtk_notebook_set_show_border (GTK_NOTEBOOK (panel->toolbook), FALSE);
gtk_notebook_set_show_tabs (GTK_NOTEBOOK (panel->toolbook), FALSE);
gtk_box_pack_start (GTK_BOX (vbox), panel->toolbook, FALSE, FALSE, 0);
gtk_widget_show (panel->toolbook);
/* Create the notebook */
panel->notebook = gtk_notebook_new ();
gtk_notebook_set_show_border (GTK_NOTEBOOK (panel->notebook), FALSE);
gtk_notebook_set_show_tabs (GTK_NOTEBOOK (panel->notebook), FALSE);
panel->frame = gtk_frame_new (NULL);
gtk_container_add (GTK_CONTAINER (panel->frame), panel->notebook);
gtk_box_pack_start (GTK_BOX (vbox), panel->frame, TRUE, TRUE, 0);
gtk_widget_show_all (panel->frame);
g_signal_connect (panel, "destroy",
G_CALLBACK (midori_panel_destroy_cb), NULL);
}
static void
midori_panel_finalize (GObject* object)
{
G_OBJECT_CLASS (midori_panel_parent_class)->finalize (object);
}
static void
midori_panel_set_property (GObject* object,
guint prop_id,
const GValue* value,
GParamSpec* pspec)
{
MidoriPanel* panel = MIDORI_PANEL (object);
switch (prop_id)
{
case PROP_SHADOW_TYPE:
gtk_frame_set_shadow_type (GTK_FRAME (panel->frame),
g_value_get_enum (value));
break;
case PROP_MENU:
katze_object_assign (panel->menu, g_value_dup_object (value));
/* FIXME: Move existing items to the new menu */
break;
case PROP_PAGE:
midori_panel_set_current_page (panel, g_value_get_int (value));
break;
case PROP_RIGHT_ALIGNED:
midori_panel_set_right_aligned (panel, g_value_get_boolean (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
midori_panel_get_property (GObject* object,
guint prop_id,
GValue* value,
GParamSpec* pspec)
{
MidoriPanel* panel = MIDORI_PANEL (object);
switch (prop_id)
{
case PROP_SHADOW_TYPE:
g_value_set_enum (value,
gtk_frame_get_shadow_type (GTK_FRAME (panel->frame)));
break;
case PROP_MENU:
g_value_set_object (value, panel->menu);
break;
case PROP_PAGE:
g_value_set_int (value, midori_panel_get_current_page (panel));
break;
case PROP_RIGHT_ALIGNED:
g_value_set_boolean (value, panel->right_aligned);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
/**
* midori_panel_new:
*
* Creates a new empty panel.
*
* Return value: a new #MidoriPanel
**/
GtkWidget*
midori_panel_new (void)
{
MidoriPanel* panel = g_object_new (MIDORI_TYPE_PANEL,
NULL);
return GTK_WIDGET (panel);
}
/**
* midori_panel_set_compact:
* @compact: %TRUE if the panel should be compact
*
* Determines if the panel should be compact.
**/
void
midori_panel_set_compact (MidoriPanel* panel,
gboolean compact)
{
g_return_if_fail (MIDORI_IS_PANEL (panel));
#if HAVE_HILDON
compact = TRUE;
#endif
gtk_toolbar_set_style (GTK_TOOLBAR (panel->toolbar),
compact ? GTK_TOOLBAR_ICONS : GTK_TOOLBAR_BOTH);
}
/**
* midori_panel_set_right_aligned:
* @compact: %TRUE if the panel should be aligned to the right
*
* Determines if the panel should be right aligned.
*
* Since: 0.1.3
**/
void
midori_panel_set_right_aligned (MidoriPanel* panel,
gboolean right_aligned)
{
GtkWidget* box;
g_return_if_fail (MIDORI_IS_PANEL (panel));
box = gtk_widget_get_parent (panel->toolbar);
gtk_box_reorder_child (GTK_BOX (box), panel->toolbar,
right_aligned ? -1 : 0);
gtk_tool_button_set_stock_id (GTK_TOOL_BUTTON (panel->button_align),
right_aligned ? GTK_STOCK_GO_BACK : GTK_STOCK_GO_FORWARD);
panel->right_aligned = right_aligned;
g_object_notify (G_OBJECT (panel), "right-aligned");
}
static void
midori_panel_menu_item_activate_cb (GtkWidget* widget,
MidoriPanel* panel)
{
GtkWidget* child;
GtkToggleToolButton* toolitem;
guint n;
child = g_object_get_data (G_OBJECT (widget), "page");
toolitem = g_object_get_data (G_OBJECT (widget), "toolitem");
if (toolitem)
{
/* Unsetting the button before setting it ensures that
it will emit signals even if it was active before */
gtk_toggle_tool_button_set_active (toolitem, FALSE);
gtk_toggle_tool_button_set_active (toolitem, TRUE);
}
else
{
n = midori_panel_page_num (panel, child);
midori_panel_set_current_page (panel, n);
g_signal_emit (panel, signals[SWITCH_PAGE], 0, n);
gtk_widget_show (GTK_WIDGET (panel));
}
}
static void
midori_panel_viewable_destroy_cb (GtkWidget* viewable,
MidoriPanel* panel)
{
gint i = gtk_notebook_page_num (GTK_NOTEBOOK (panel->notebook), viewable);
if (i > -1)
gtk_notebook_remove_page (GTK_NOTEBOOK (panel->notebook), i);
g_signal_handlers_disconnect_by_func (
viewable, midori_panel_viewable_destroy_cb, panel);
}
static void
midori_panel_widget_destroy_cb (GtkWidget* viewable,
GtkWidget* widget)
{
gtk_widget_destroy (widget);
g_signal_handlers_disconnect_by_func (
viewable, midori_panel_widget_destroy_cb, widget);
}
static GtkToolItem*
midori_panel_construct_tool_item (MidoriPanel* panel,
MidoriViewable* viewable)
{
const gchar* label = midori_viewable_get_label (viewable);
const gchar* stock_id = midori_viewable_get_stock_id (viewable);
GtkToolItem* toolitem;
GtkWidget* image;
toolitem = gtk_radio_tool_button_new_from_stock (NULL, stock_id);
g_object_set (toolitem, "group",
gtk_toolbar_get_nth_item (GTK_TOOLBAR (panel->toolbar), 0), NULL);
image = gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_BUTTON);
gtk_tool_button_set_icon_widget (GTK_TOOL_BUTTON (toolitem), image);
if (label)
{
gtk_tool_button_set_label (GTK_TOOL_BUTTON (toolitem), label);
gtk_widget_set_tooltip_text (GTK_WIDGET (toolitem), label);
}
g_object_set_data (G_OBJECT (toolitem), "page", viewable);
g_signal_connect (toolitem, "clicked",
G_CALLBACK (midori_panel_menu_item_activate_cb), panel);
gtk_widget_show_all (GTK_WIDGET (toolitem));
gtk_toolbar_insert (GTK_TOOLBAR (panel->toolbar), toolitem, -1);
g_signal_connect (viewable, "destroy",
G_CALLBACK (midori_panel_widget_destroy_cb), toolitem);
return toolitem;
}
/**
* midori_panel_append_page:
* @panel: a #MidoriPanel
* @viewable: a viewable widget
* @toolbar: a toolbar widget, or %NULL
* @stock_id: a stock ID
* @label: a string to use as the label
*
* Appends a new page to the panel. If @toolbar is specified it will
* be packed above @viewable.
*
* Since 0.1.3 destroying the @viewable implicitly removes
* the page including the menu and eventual toolbar.
*
* In the case of an error, -1 is returned.
*
* Return value: the index of the new page, or -1
**/
gint
midori_panel_append_page (MidoriPanel* panel,
MidoriViewable* viewable)
{
GtkWidget* scrolled;
GObjectClass* gobject_class;
GtkWidget* widget;
GtkWidget* toolbar;
const gchar* label;
const gchar* stock_id;
GtkToolItem* toolitem;
GtkWidget* menuitem;
guint n;
g_return_val_if_fail (MIDORI_IS_PANEL (panel), -1);
g_return_val_if_fail (MIDORI_IS_VIEWABLE (viewable), -1);
if (GTK_IS_SCROLLED_WINDOW (viewable))
scrolled = (GtkWidget*)viewable;
else
{
scrolled = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
GTK_WIDGET_SET_FLAGS (scrolled, GTK_CAN_FOCUS);
gtk_widget_show (scrolled);
gobject_class = G_OBJECT_GET_CLASS (viewable);
if (GTK_WIDGET_CLASS (gobject_class)->set_scroll_adjustments_signal)
widget = (GtkWidget*)viewable;
else
{
widget = gtk_viewport_new (NULL, NULL);
gtk_widget_show (widget);
gtk_container_add (GTK_CONTAINER (widget), GTK_WIDGET (viewable));
}
gtk_container_add (GTK_CONTAINER (scrolled), widget);
}
gtk_container_add (GTK_CONTAINER (panel->notebook), scrolled);
toolbar = midori_viewable_get_toolbar (viewable);
gtk_widget_show (toolbar);
gtk_container_add (GTK_CONTAINER (panel->toolbook), toolbar);
g_signal_connect (viewable, "destroy",
G_CALLBACK (midori_panel_widget_destroy_cb), toolbar);
n = midori_panel_page_num (panel, scrolled);
label = midori_viewable_get_label (viewable);
stock_id = midori_viewable_get_stock_id (viewable);
toolitem = midori_panel_construct_tool_item (panel, viewable);
if (panel->menu)
{
menuitem = gtk_image_menu_item_new_from_stock (stock_id, NULL);
gtk_widget_show (menuitem);
g_object_set_data (G_OBJECT (menuitem), "page", viewable);
g_object_set_data (G_OBJECT (menuitem), "toolitem", toolitem);
g_signal_connect (menuitem, "activate",
G_CALLBACK (midori_panel_menu_item_activate_cb),
panel);
gtk_menu_shell_append (GTK_MENU_SHELL (panel->menu), menuitem);
g_object_set_data (G_OBJECT (scrolled), "panel-menuitem", menuitem);
g_signal_connect (viewable, "destroy",
G_CALLBACK (midori_panel_widget_destroy_cb), menuitem);
}
g_signal_connect (viewable, "destroy",
G_CALLBACK (midori_panel_viewable_destroy_cb), panel);
return n;
}
/**
* midori_panel_get_current_page:
* @panel: a #MidoriPanel
*
* Retrieves the index of the currently selected page.
*
* If @panel has no children, -1 is returned.
*
* Return value: the index of the current page, or -1
**/
gint
midori_panel_get_current_page (MidoriPanel* panel)
{
g_return_val_if_fail (MIDORI_IS_PANEL (panel), -1);
return gtk_notebook_get_current_page (GTK_NOTEBOOK (panel->notebook));
}
static GtkWidget*
_midori_panel_child_for_scrolled (MidoriPanel* panel,
GtkWidget* scrolled)
{
GtkWidget* child;
/* This is a lazy hack, we should have a way of determining
whether the scrolled is the actual child. */
if (MIDORI_IS_VIEW (scrolled))
return scrolled;
child = gtk_bin_get_child (GTK_BIN (scrolled));
if (GTK_IS_VIEWPORT (child))
child = gtk_bin_get_child (GTK_BIN (child));
return child;
}
/**
* midori_panel_get_nth_page:
* @panel: a #MidoriPanel
*
* Retrieves the child widget of the nth page.
*
* If @panel has no children, %NULL is returned.
*
* Return value: the child widget of the new page, or %NULL
**/
GtkWidget*
midori_panel_get_nth_page (MidoriPanel* panel,
guint page_num)
{
GtkWidget* scrolled;
g_return_val_if_fail (MIDORI_IS_PANEL (panel), NULL);
scrolled = gtk_notebook_get_nth_page (
GTK_NOTEBOOK (panel->notebook), page_num);
if (scrolled)
return _midori_panel_child_for_scrolled (panel, scrolled);
return NULL;
}
/**
* midori_panel_get_n_pages:
* @panel: a #MidoriPanel
*
* Retrieves the number of pages contained in the panel.
*
* Return value: the number of pages
**/
guint
midori_panel_get_n_pages (MidoriPanel* panel)
{
g_return_val_if_fail (MIDORI_IS_PANEL (panel), 0);
return gtk_notebook_get_n_pages (GTK_NOTEBOOK (panel->notebook));
}
static GtkWidget*
_midori_panel_scrolled_for_child (MidoriPanel* panel,
GtkWidget* child)
{
GtkWidget* scrolled;
/* This is a lazy hack, we should have a way of determining
whether the scrolled is the actual child. */
if (MIDORI_IS_VIEW (child))
return child;
scrolled = gtk_widget_get_parent (GTK_WIDGET (child));
if (GTK_IS_VIEWPORT (scrolled))
scrolled = gtk_widget_get_parent (scrolled);
return scrolled;
}
/**
* midori_panel_page_num:
* @panel: a #MidoriPanel
*
* Retrieves the index of the page associated to @widget.
*
* If @panel has no children, -1 is returned.
*
* Return value: the index of page associated to @widget, or -1
**/
gint
midori_panel_page_num (MidoriPanel* panel,
GtkWidget* child)
{
GtkWidget* scrolled;
g_return_val_if_fail (MIDORI_IS_PANEL (panel), -1);
g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
scrolled = _midori_panel_scrolled_for_child (panel, child);
return gtk_notebook_page_num (GTK_NOTEBOOK (panel->notebook), scrolled);
}
/**
* midori_panel_set_current_page:
* @panel: a #MidoriPanel
* @n: index of the page to switch to, or -1 to mean the last page
*
* Switches to the page with the given index.
*
* The child must be visible, otherwise the underlying GtkNotebook will
* silently ignore the attempt to switch the page.
**/
void
midori_panel_set_current_page (MidoriPanel* panel,
gint n)
{
GtkWidget* viewable;
g_return_if_fail (MIDORI_IS_PANEL (panel));
gtk_notebook_set_current_page (GTK_NOTEBOOK (panel->toolbook), n);
gtk_notebook_set_current_page (GTK_NOTEBOOK (panel->notebook), n);
if ((viewable = midori_panel_get_nth_page (panel, n)))
{
const gchar* label;
label = midori_viewable_get_label (MIDORI_VIEWABLE (viewable));
g_object_set (panel->toolbar_label, "label", label, NULL);
}
}
typedef struct
{
GtkAlignment parent_instance;
gchar* label;
gchar* stock_id;
GtkWidget* toolbar;
} MidoriDummyViewable;
typedef struct
{
GtkAlignmentClass parent_class;
} MidoriDummyViewableClass;
GType midori_dummy_viewable_get_type (void) G_GNUC_CONST;
#define MIDORI_TYPE_DUMMY_VIEWABLE (midori_dummy_viewable_get_type ())
#define MIDORI_DUMMY_VIEWABLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
MIDORI_TYPE_DUMMY_VIEWABLE, MidoriDummyViewable))
#define MIDORI_IS_DUMMY_VIEWABLE(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), MIDORI_TYPE_DUMMY_VIEWABLE))
static void
midori_dummy_viewable_iface_init (MidoriViewableIface* iface);
static void
midori_dummy_viewable_finalize (GObject* object);
G_DEFINE_TYPE_WITH_CODE (MidoriDummyViewable, midori_dummy_viewable,
GTK_TYPE_ALIGNMENT,
G_IMPLEMENT_INTERFACE (MIDORI_TYPE_VIEWABLE,
midori_dummy_viewable_iface_init));
static void
midori_dummy_viewable_class_init (MidoriDummyViewableClass* class)
{
GObjectClass* gobject_class;
gobject_class = G_OBJECT_CLASS (class);
gobject_class->finalize = midori_dummy_viewable_finalize;
}
static const gchar*
midori_dummy_viewable_get_label (MidoriViewable* viewable)
{
return MIDORI_DUMMY_VIEWABLE (viewable)->label;
}
static const gchar*
midori_dummy_viewable_get_stock_id (MidoriViewable* viewable)
{
return MIDORI_DUMMY_VIEWABLE (viewable)->stock_id;
}
static GtkWidget*
midori_dummy_viewable_get_toolbar (MidoriViewable* viewable)
{
return MIDORI_DUMMY_VIEWABLE (viewable)->toolbar;
}
static void
midori_dummy_viewable_iface_init (MidoriViewableIface* iface)
{
iface->get_stock_id = midori_dummy_viewable_get_stock_id;
iface->get_label = midori_dummy_viewable_get_label;
iface->get_toolbar = midori_dummy_viewable_get_toolbar;
}
static void
midori_dummy_viewable_init (MidoriDummyViewable* viewable)
{
viewable->stock_id = NULL;
viewable->label = NULL;
viewable->toolbar = NULL;
}
static void
midori_dummy_viewable_finalize (GObject* object)
{
MidoriDummyViewable* viewable = MIDORI_DUMMY_VIEWABLE (object);
katze_assign (viewable->stock_id, NULL);
katze_assign (viewable->label, NULL);
G_OBJECT_CLASS (midori_dummy_viewable_parent_class)->finalize (object);
}
/* static */ GtkWidget*
midori_dummy_viewable_new (const gchar* stock_id,
const gchar* label,
GtkWidget* toolbar)
{
GtkWidget* viewable = g_object_new (MIDORI_TYPE_DUMMY_VIEWABLE, NULL);
MIDORI_DUMMY_VIEWABLE (viewable)->stock_id = g_strdup (stock_id);
MIDORI_DUMMY_VIEWABLE (viewable)->label = g_strdup (label);
MIDORI_DUMMY_VIEWABLE (viewable)->toolbar = toolbar;
return viewable;
}
/**
* midori_panel_append_widget:
* @panel: a #MidoriPanel
* @widget: the child widget
* @stock_id: a stock ID
* @label: a string to use as the label, or %NULL
* @toolbar: a toolbar widget, or %NULL
*
* Appends an arbitrary widget to the panel by wrapping it
* in a #MidoriViewable created on the fly.
*
* Actually implementing #MidoriViewable instead of using
* this convenience is recommended.
*
* Since 0.1.3 destroying the @widget implicitly removes
* the page including the menu and eventual toolbar.
*
* In the case of an error, -1 is returned.
*
* Return value: the index of the new page, or -1
**/
gint
midori_panel_append_widget (MidoriPanel* panel,
GtkWidget* widget,
const gchar* stock_id,
const gchar* label,
GtkWidget* toolbar)
{
GtkWidget* viewable;
g_return_val_if_fail (MIDORI_IS_PANEL (panel), -1);
g_return_val_if_fail (GTK_IS_WIDGET (widget), -1);
g_return_val_if_fail (stock_id != NULL, -1);
g_return_val_if_fail (!toolbar || GTK_IS_WIDGET (toolbar), -1);
viewable = midori_dummy_viewable_new (stock_id, label, toolbar);
gtk_widget_show (viewable);
gtk_container_add (GTK_CONTAINER (viewable), widget);
g_signal_connect (widget, "destroy",
G_CALLBACK (midori_panel_widget_destroy_cb), viewable);
return midori_panel_append_page (panel, MIDORI_VIEWABLE (viewable));
}

84
midori/midori-panel.h Normal file
View file

@ -0,0 +1,84 @@
/*
Copyright (C) 2008 Christian Dywan <christian@twotoasts.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#ifndef __MIDORI_PANEL_H__
#define __MIDORI_PANEL_H__
#include <gtk/gtk.h>
#include <katze/katze.h>
#include "midori-viewable.h"
G_BEGIN_DECLS
#define MIDORI_TYPE_PANEL \
(midori_panel_get_type ())
#define MIDORI_PANEL(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), MIDORI_TYPE_PANEL, MidoriPanel))
#define MIDORI_PANEL_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), MIDORI_TYPE_PANEL, MidoriPanelClass))
#define MIDORI_IS_PANEL(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), MIDORI_TYPE_PANEL))
#define MIDORI_IS_PANEL_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), MIDORI_TYPE_PANEL))
#define MIDORI_PANEL_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), MIDORI_TYPE_PANEL, MidoriPanelClass))
typedef struct _MidoriPanel MidoriPanel;
typedef struct _MidoriPanelClass MidoriPanelClass;
GType
midori_panel_get_type (void);
GtkWidget*
midori_panel_new (void);
void
midori_panel_set_compact (MidoriPanel* panel,
gboolean compact);
void
midori_panel_set_right_aligned (MidoriPanel* panel,
gboolean right_aligned);
gint
midori_panel_append_page (MidoriPanel* panel,
MidoriViewable* viewable);
gint
midori_panel_get_current_page (MidoriPanel* panel);
GtkWidget*
midori_panel_get_nth_page (MidoriPanel* panel,
guint page_num);
guint
midori_panel_get_n_pages (MidoriPanel* panel);
gint
midori_panel_page_num (MidoriPanel* panel,
GtkWidget* child);
void
midori_panel_set_current_page (MidoriPanel* panel,
gint n);
gint
midori_panel_append_widget (MidoriPanel* panel,
GtkWidget* widget,
const gchar* stock_id,
const gchar* label,
GtkWidget* toolbar);
G_END_DECLS
#endif /* __MIDORI_PANEL_H__ */

672
midori/midori-preferences.c Normal file
View file

@ -0,0 +1,672 @@
/*
Copyright (C) 2007-2009 Christian Dywan <christian@twotoasts.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#include "midori-preferences.h"
#if HAVE_CONFIG_H
#include <config.h>
#endif
#include "sokoke.h"
#include "compat.h"
#include <string.h>
#include <glib/gi18n.h>
#include <libsoup/soup.h>
struct _MidoriPreferences
{
GtkDialog parent_instance;
MidoriWebSettings* settings;
GtkWidget* notebook;
};
G_DEFINE_TYPE (MidoriPreferences, midori_preferences, GTK_TYPE_DIALOG)
enum
{
PROP_0,
PROP_SETTINGS
};
static void
midori_preferences_finalize (GObject* object);
static void
midori_preferences_set_property (GObject* object,
guint prop_id,
const GValue* value,
GParamSpec* pspec);
static void
midori_preferences_get_property (GObject* object,
guint prop_id,
GValue* value,
GParamSpec* pspec);
static void
midori_preferences_class_init (MidoriPreferencesClass* class)
{
GObjectClass* gobject_class = G_OBJECT_CLASS (class);
gobject_class->finalize = midori_preferences_finalize;
gobject_class->set_property = midori_preferences_set_property;
gobject_class->get_property = midori_preferences_get_property;
g_object_class_install_property (gobject_class,
PROP_SETTINGS,
g_param_spec_object (
"settings",
"Settings",
"Settings instance to provide properties",
MIDORI_TYPE_WEB_SETTINGS,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
}
static void
midori_preferences_response_cb (MidoriPreferences* preferences,
gint response)
{
if (response == GTK_RESPONSE_CLOSE)
gtk_widget_destroy (GTK_WIDGET (preferences));
}
static void
midori_preferences_init (MidoriPreferences* preferences)
{
gchar* dialog_title;
preferences->settings = NULL;
preferences->notebook = NULL;
dialog_title = g_strdup_printf (_("Preferences for %s"),
g_get_application_name ());
g_object_set (preferences,
"icon-name", GTK_STOCK_PREFERENCES,
"title", dialog_title,
"has-separator", FALSE,
NULL);
g_free (dialog_title);
#if !HAVE_OSX
gtk_dialog_add_buttons (GTK_DIALOG (preferences),
GTK_STOCK_HELP, GTK_RESPONSE_HELP,
GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
NULL);
#endif
g_signal_connect (preferences, "response",
G_CALLBACK (midori_preferences_response_cb), NULL);
}
static void
midori_preferences_finalize (GObject* object)
{
G_OBJECT_CLASS (midori_preferences_parent_class)->finalize (object);
}
static void
midori_preferences_set_property (GObject* object,
guint prop_id,
const GValue* value,
GParamSpec* pspec)
{
MidoriPreferences* preferences = MIDORI_PREFERENCES (object);
switch (prop_id)
{
case PROP_SETTINGS:
midori_preferences_set_settings (preferences,
g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
midori_preferences_get_property (GObject* object,
guint prop_id,
GValue* value,
GParamSpec* pspec)
{
MidoriPreferences* preferences = MIDORI_PREFERENCES (object);
switch (prop_id)
{
case PROP_SETTINGS:
g_value_set_object (value, preferences->settings);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
/**
* midori_preferences_new:
* @parent: the parent window
* @settings: the settings
*
* Creates a new preferences dialog.
*
* Since 0.1.2 @parent may be %NULL.
*
* Return value: a new #MidoriPreferences
**/
GtkWidget*
midori_preferences_new (GtkWindow* parent,
MidoriWebSettings* settings)
{
MidoriPreferences* preferences;
g_return_val_if_fail (!parent || GTK_IS_WINDOW (parent), NULL);
g_return_val_if_fail (MIDORI_IS_WEB_SETTINGS (settings), NULL);
preferences = g_object_new (MIDORI_TYPE_PREFERENCES,
"transient-for", parent,
"settings", settings,
NULL);
return GTK_WIDGET (preferences);
}
static void
midori_preferences_homepage_current_clicked_cb (GtkWidget* button,
MidoriWebSettings* settings)
{
GtkWidget* preferences = gtk_widget_get_toplevel (button);
GtkWidget* browser = katze_object_get_object (preferences, "transient-for");
if (GTK_IS_WINDOW (browser))
{
gchar* uri = katze_object_get_string (browser, "uri");
g_object_set (settings, "homepage", uri, NULL);
g_free (uri);
}
}
static gboolean
proxy_download_manager_icon_cb (GtkWidget* entry,
GdkEventFocus* event,
GtkImage* icon)
{
const gchar* command;
gchar* first_space;
gchar* first_part;
gchar* path;
command = gtk_entry_get_text (GTK_ENTRY (entry));
if ((first_space = strstr (command, " ")))
first_part = g_strndup (command, first_space - command);
else
first_part = g_strdup (command);
path = g_find_program_in_path (first_part);
if (path)
{
if (gtk_icon_theme_has_icon (gtk_icon_theme_get_for_screen (
gtk_widget_get_screen (entry)), first_part))
gtk_image_set_from_icon_name (icon, first_part, GTK_ICON_SIZE_MENU);
else
gtk_image_set_from_stock (icon, GTK_STOCK_EXECUTE, GTK_ICON_SIZE_MENU);
g_free (path);
}
else if (first_part && *first_part)
gtk_image_set_from_stock (icon, GTK_STOCK_STOP, GTK_ICON_SIZE_MENU);
else
gtk_image_clear (icon);
g_free (first_part);
return FALSE;
}
static void
midori_preferences_notify_preferred_encoding_cb (MidoriWebSettings* settings,
GParamSpec* pspec,
GtkWidget* entry)
{
MidoriPreferredEncoding preferred_encoding;
preferred_encoding = katze_object_get_enum (settings, "preferred-encoding");
gtk_widget_set_sensitive (entry, preferred_encoding == MIDORI_ENCODING_CUSTOM);
}
static void
midori_preferences_notify_auto_detect_proxy_cb (MidoriWebSettings* settings,
GParamSpec* pspec,
GtkWidget* entry)
{
MidoriIdentity auto_detect_proxy = katze_object_get_enum (settings,
"auto-detect-proxy");
gtk_widget_set_sensitive (entry, !auto_detect_proxy);
}
static void
midori_preferences_notify_identify_as_cb (MidoriWebSettings* settings,
GParamSpec* pspec,
GtkWidget* entry)
{
MidoriIdentity identify_as = katze_object_get_enum (settings, "identify-as");
gtk_widget_set_sensitive (entry, identify_as == MIDORI_IDENT_CUSTOM);
}
#if HAVE_OSX
static void
midori_preferences_help_clicked_cb (GtkWidget* button,
GtkDialog* dialog)
{
gtk_dialog_response (dialog, GTK_RESPONSE_HELP);
}
static void
midori_preferences_toolbutton_clicked_cb (GtkWidget* toolbutton,
GtkWidget* page)
{
gpointer notebook = g_object_get_data (G_OBJECT (toolbutton), "notebook");
guint n = gtk_notebook_page_num (notebook, page);
gtk_notebook_set_current_page (notebook, n);
}
#endif
static inline void
midori_preferences_add_toolbutton (GtkWidget* toolbar,
GtkWidget** toolbutton,
const gchar* icon,
const gchar* label,
GtkWidget* page)
{
#if HAVE_OSX
*toolbutton = GTK_WIDGET (*toolbutton ? gtk_radio_tool_button_new_from_widget (
GTK_RADIO_TOOL_BUTTON (*toolbutton)) : gtk_radio_tool_button_new (NULL));
gtk_tool_button_set_label (GTK_TOOL_BUTTON (*toolbutton), label);
gtk_tool_button_set_stock_id (GTK_TOOL_BUTTON (*toolbutton), icon);
gtk_toolbar_insert (GTK_TOOLBAR (toolbar), GTK_TOOL_ITEM (*toolbutton), -1);
g_signal_connect (*toolbutton, "clicked",
G_CALLBACK (midori_preferences_toolbutton_clicked_cb), page);
#endif
}
/**
* midori_preferences_set_settings:
* @settings: the settings
*
* Assigns a settings instance to a preferences dialog.
*
* Note: This must not be called more than once.
*
* Since 0.1.2 this is equal to setting #MidoriPreferences:settings:.
**/
void
midori_preferences_set_settings (MidoriPreferences* preferences,
MidoriWebSettings* settings)
{
GtkWidget* header;
GtkWindow* parent;
const gchar* icon_name;
GtkSizeGroup* sizegroup;
GtkWidget* toolbar;
GtkWidget* toolbutton;
GtkWidget* page;
GtkWidget* frame;
GtkWidget* table;
GtkWidget* align;
GtkWidget* label;
GtkWidget* button;
GtkWidget* entry;
GtkWidget* hbox;
gint icon_width, icon_height;
g_return_if_fail (MIDORI_IS_PREFERENCES (preferences));
g_return_if_fail (MIDORI_IS_WEB_SETTINGS (settings));
g_return_if_fail (!preferences->notebook);
katze_assign (preferences->settings, g_object_ref (settings));
g_object_get (preferences, "transient-for", &parent, NULL);
icon_name = parent ? gtk_window_get_icon_name (parent) : NULL;
if ((header = sokoke_xfce_header_new (icon_name,
gtk_window_get_title (GTK_WINDOW (preferences)))))
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (preferences)->vbox),
header, FALSE, FALSE, 0);
preferences->notebook = gtk_notebook_new ();
gtk_container_set_border_width (GTK_CONTAINER (preferences->notebook), 6);
#if HAVE_OSX
gtk_notebook_set_show_tabs (GTK_NOTEBOOK (preferences->notebook), FALSE);
gtk_notebook_set_show_border (GTK_NOTEBOOK (preferences->notebook), FALSE);
toolbar = gtk_toolbar_new ();
gtk_toolbar_set_style (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_BOTH);
gtk_toolbar_set_show_arrow (GTK_TOOLBAR (toolbar), FALSE);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (preferences)->vbox),
toolbar, FALSE, FALSE, 0);
#else
toolbar = NULL;
#endif
toolbutton = NULL;
sizegroup = NULL;
#define PAGE_NEW(__icon, __label) \
page = gtk_vbox_new (FALSE, 0); \
midori_preferences_add_toolbutton (toolbar, &toolbutton, \
__icon, __label, page); \
if (toolbutton) g_object_set_data (G_OBJECT (toolbutton), \
"notebook", preferences->notebook); \
if (sizegroup) g_object_unref (sizegroup); \
sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); \
gtk_container_set_border_width (GTK_CONTAINER (page), 4); \
gtk_notebook_append_page (GTK_NOTEBOOK (preferences->notebook), page, \
gtk_label_new (__label))
#define FRAME_NEW(__label) frame = sokoke_hig_frame_new (__label); \
gtk_container_set_border_width (GTK_CONTAINER (frame), 4); \
gtk_box_pack_start (GTK_BOX (page), frame, FALSE, FALSE, 0);
#define TABLE_NEW(__rows, __cols) table = gtk_table_new ( \
__rows, __cols, FALSE); \
gtk_container_set_border_width (GTK_CONTAINER (table), 4); \
gtk_container_add (GTK_CONTAINER (frame), table);
#define WIDGET_ADD(__widget, __left, __right, __top, __bottom) \
gtk_table_attach (GTK_TABLE (table), __widget \
, __left, __right, __top, __bottom \
, GTK_FILL, GTK_FILL, 8, 2)
#define FILLED_ADD(__widget, __left, __right, __top, __bottom) \
gtk_table_attach (GTK_TABLE (table), __widget \
, __left, __right, __top, __bottom\
, GTK_EXPAND | GTK_FILL, GTK_FILL, 8, 2)
#define INDENTED_ADD(__widget, __left, __right, __top, __bottom) \
align = gtk_alignment_new (0, 0.5, 0, 0); \
gtk_container_add (GTK_CONTAINER (align), __widget); \
gtk_size_group_add_widget (sizegroup, align); \
WIDGET_ADD (align, __left, __right, __top, __bottom)
#define SPANNED_ADD(__widget, __left, __right, __top, __bottom) \
align = gtk_alignment_new (0, 0.5, 0, 0); \
gtk_container_add (GTK_CONTAINER (align), __widget); \
FILLED_ADD (align, __left, __right, __top, __bottom)
/* Page "General" */
PAGE_NEW (GTK_STOCK_HOME, _("General"));
FRAME_NEW (_("Startup"));
TABLE_NEW (3, 2);
label = katze_property_label (settings, "load-on-startup");
INDENTED_ADD (label, 0, 1, 0, 1);
button = katze_property_proxy (settings, "load-on-startup", NULL);
FILLED_ADD (button, 1, 2, 0, 1);
label = katze_property_label (settings, "homepage");
INDENTED_ADD (label, 0, 1, 1, 2);
hbox = gtk_hbox_new (FALSE, 4);
entry = katze_property_proxy (settings, "homepage", NULL);
gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
if (parent && katze_object_has_property (parent, "uri"))
{
button = gtk_button_new ();
label = gtk_image_new_from_stock (GTK_STOCK_JUMP_TO, GTK_ICON_SIZE_BUTTON);
gtk_button_set_image (GTK_BUTTON (button), label);
gtk_widget_set_tooltip_text (button, _("Use current page as homepage"));
g_signal_connect (button, "clicked",
G_CALLBACK (midori_preferences_homepage_current_clicked_cb), settings);
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
}
FILLED_ADD (hbox, 1, 2, 1, 2);
button = katze_property_proxy (settings, "show-crash-dialog", NULL);
SPANNED_ADD (button, 0, 2, 2, 3);
FRAME_NEW (_("Transfers"));
TABLE_NEW (4, 2);
#if WEBKIT_CHECK_VERSION (1, 1, 3)
label = katze_property_label (settings, "download-folder");
INDENTED_ADD (label, 0, 1, 0, 1);
button = katze_property_proxy (settings, "download-folder", "folder");
FILLED_ADD (button, 1, 2, 0, 1);
#endif
label = katze_property_label (settings, "download-manager");
INDENTED_ADD (label, 0, 1, 1, 2);
hbox = gtk_hbox_new (FALSE, 4);
button = gtk_image_new ();
gtk_icon_size_lookup_for_settings (gtk_widget_get_settings (button),
GTK_ICON_SIZE_MENU, &icon_width, &icon_height);
gtk_widget_set_size_request (button, icon_width, icon_height);
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 4);
entry = katze_property_proxy (settings, "download-manager", NULL);
gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
proxy_download_manager_icon_cb (entry, NULL, GTK_IMAGE (button));
g_signal_connect (entry, "focus-out-event",
G_CALLBACK (proxy_download_manager_icon_cb), button);
FILLED_ADD (hbox, 1, 2, 1, 2);
label = katze_property_label (settings, "text-editor");
INDENTED_ADD (label, 0, 1, 2, 3);
hbox = gtk_hbox_new (FALSE, 4);
button = gtk_image_new ();
gtk_icon_size_lookup_for_settings (gtk_widget_get_settings (button),
GTK_ICON_SIZE_MENU, &icon_width, &icon_height);
gtk_widget_set_size_request (button, icon_width, icon_height);
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 4);
entry = katze_property_proxy (settings, "text-editor", NULL);
gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
proxy_download_manager_icon_cb (entry, NULL, GTK_IMAGE (button));
g_signal_connect (entry, "focus-out-event",
G_CALLBACK (proxy_download_manager_icon_cb), button);
FILLED_ADD (hbox, 1, 2, 2, 3);
label = katze_property_label (settings, "news-aggregator");
INDENTED_ADD (label, 0, 1, 3, 4);
hbox = gtk_hbox_new (FALSE, 4);
button = gtk_image_new ();
gtk_icon_size_lookup_for_settings (gtk_widget_get_settings (button),
GTK_ICON_SIZE_MENU, &icon_width, &icon_height);
gtk_widget_set_size_request (button, icon_width, icon_height);
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 4);
entry = katze_property_proxy (settings, "news-aggregator", NULL);
gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
proxy_download_manager_icon_cb (entry, NULL, GTK_IMAGE (button));
g_signal_connect (entry, "focus-out-event",
G_CALLBACK (proxy_download_manager_icon_cb), button);
FILLED_ADD (hbox, 1, 2, 3, 4);
/* Page "Appearance" */
PAGE_NEW (GTK_STOCK_SELECT_FONT, _("Appearance"));
FRAME_NEW (_("Font settings"));
TABLE_NEW (6, 2);
label = gtk_label_new (_("Default Font Family"));
INDENTED_ADD (label, 0, 1, 0, 1);
hbox = gtk_hbox_new (FALSE, 4);
button = katze_property_proxy (settings, "default-font-family", "font");
gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
entry = katze_property_proxy (settings, "default-font-size", NULL);
gtk_widget_set_tooltip_text (entry, _("The default font size used to display text"));
gtk_box_pack_end (GTK_BOX (hbox), entry, FALSE, FALSE, 4);
FILLED_ADD (hbox, 1, 2, 0, 1);
label = gtk_label_new (_("Minimum Font Size"));
INDENTED_ADD (label, 0, 1, 1, 2);
entry = katze_property_proxy (settings, "minimum-font-size", NULL);
gtk_widget_set_tooltip_text (entry, _("The minimum font size used to display text"));
INDENTED_ADD (entry, 1, 2, 1, 2);
label = katze_property_label (settings, "preferred-encoding");
INDENTED_ADD (label, 0, 1, 2, 3);
button = katze_property_proxy (settings, "preferred-encoding", NULL);
FILLED_ADD (button, 1, 2, 2, 3);
label = katze_property_label (settings, "default-encoding");
gtk_label_set_label (GTK_LABEL (label), _("Encoding"));
INDENTED_ADD (label, 0, 1, 3, 4);
entry = katze_property_proxy (settings, "default-encoding", NULL);
gtk_widget_set_tooltip_text (entry, _("The character encoding to use by default"));
g_signal_connect (settings, "notify::preferred-encoding",
G_CALLBACK (midori_preferences_notify_preferred_encoding_cb), entry);
midori_preferences_notify_preferred_encoding_cb (settings, NULL, entry);
FILLED_ADD (entry, 1, 2, 3, 4);
/* Page "Behavior" */
PAGE_NEW (GTK_STOCK_SELECT_COLOR, _("Behavior"));
FRAME_NEW (_("Features"));
TABLE_NEW (6, 2);
button = katze_property_proxy (settings, "auto-load-images", NULL);
gtk_button_set_label (GTK_BUTTON (button), _("Load images automatically"));
gtk_widget_set_tooltip_text (button, _("Load and display images automatically"));
INDENTED_ADD (button, 0, 1, 0, 1);
button = katze_property_proxy (settings, "auto-shrink-images", NULL);
gtk_button_set_label (GTK_BUTTON (button), _("Shrink images automatically"));
gtk_widget_set_tooltip_text (button, _("Automatically shrink standalone images to fit"));
SPANNED_ADD (button, 1, 2, 0, 1);
button = katze_property_proxy (settings, "print-backgrounds", NULL);
gtk_button_set_label (GTK_BUTTON (button), _("Print background images"));
gtk_widget_set_tooltip_text (button, _("Whether background images should be printed"));
INDENTED_ADD (button, 0, 1, 1, 2);
button = katze_property_proxy (settings, "resizable-text-areas", NULL);
gtk_button_set_label (GTK_BUTTON (button), _("Resizable text areas"));
gtk_widget_set_tooltip_text (button, _("Whether text areas are resizable"));
SPANNED_ADD (button, 1, 2, 1, 2);
button = katze_property_proxy (settings, "enable-scripts", NULL);
gtk_button_set_label (GTK_BUTTON (button), _("Enable scripts"));
gtk_widget_set_tooltip_text (button, _("Enable embedded scripting languages"));
INDENTED_ADD (button, 0, 1, 2, 3);
button = katze_property_proxy (settings, "enable-plugins", NULL);
gtk_button_set_label (GTK_BUTTON (button), _("Enable plugins"));
gtk_widget_set_tooltip_text (button, _("Enable embedded plugin objects"));
SPANNED_ADD (button, 1, 2, 2, 3);
button = katze_property_proxy (settings, "enforce-96-dpi", NULL);
gtk_button_set_label (GTK_BUTTON (button), _("Enforce 96 dots per inch"));
gtk_widget_set_tooltip_text (button, _("Enforce a video dot density of 96 DPI"));
SPANNED_ADD (button, 0, 1, 3, 4);
button = katze_property_proxy (settings, "enable-developer-extras", NULL);
gtk_button_set_label (GTK_BUTTON (button), _("Enable developer tools"));
gtk_widget_set_tooltip_text (button, _("Enable special extensions for developers"));
SPANNED_ADD (button, 1, 2, 3, 4);
button = katze_property_proxy (settings, "zoom-text-and-images", NULL);
SPANNED_ADD (button, 0, 1, 4, 5);
button = katze_property_proxy (settings, "find-while-typing", NULL);
SPANNED_ADD (button, 1, 2, 4, 5);
/* Page "Interface" */
PAGE_NEW (GTK_STOCK_CONVERT, _("Interface"));
FRAME_NEW (_("Navigationbar"));
TABLE_NEW (2, 2);
#if !HAVE_HILDON
INDENTED_ADD (katze_property_label (settings, "toolbar-style"), 0, 1, 0, 1);
button = katze_property_proxy (settings, "toolbar-style", NULL);
FILLED_ADD (button, 1, 2, 0, 1);
#endif
button = katze_property_proxy (settings, "progress-in-location", NULL);
FILLED_ADD (button, 0, 1, 1, 2);
button = katze_property_proxy (settings, "search-engines-in-completion", NULL);
FILLED_ADD (button, 1, 2, 1, 2);
FRAME_NEW (_("Browsing"));
TABLE_NEW (5, 2);
label = katze_property_label (settings, "open-new-pages-in");
INDENTED_ADD (label, 0, 1, 0, 1);
button = katze_property_proxy (settings, "open-new-pages-in", NULL);
FILLED_ADD (button, 1, 2, 0, 1);
#if HAVE_UNIQUE
label = katze_property_label (settings, "open-external-pages-in");
INDENTED_ADD (label, 0, 1, 1, 2);
button = katze_property_proxy (settings, "open-external-pages-in", NULL);
FILLED_ADD (button, 1, 2, 1, 2);
#endif
button = katze_property_proxy (settings, "always-show-tabbar", NULL);
INDENTED_ADD (button, 0, 1, 2, 3);
button = katze_property_proxy (settings, "open-tabs-in-the-background", NULL);
INDENTED_ADD (button, 1, 2, 2, 3);
#if !HAVE_HILDON
button = katze_property_proxy (settings, "middle-click-opens-selection", NULL);
INDENTED_ADD (button, 0, 1, 3, 4);
button = katze_property_proxy (settings, "compact-sidepanel", NULL);
WIDGET_ADD (button, 1, 2, 3, 4);
#endif
/* button = katze_property_proxy (settings, "open-popups-in-tabs", NULL);
SPANNED_ADD (button, 0, 1, 4, 5);*/
button = katze_property_proxy (settings, "open-tabs-next-to-current", NULL);
WIDGET_ADD (button, 0, 1, 5, 6);
button = katze_property_proxy (settings, "close-buttons-on-tabs", NULL);
WIDGET_ADD (button, 1, 2, 5, 6);
/* Page "Network" */
PAGE_NEW (GTK_STOCK_NETWORK, _("Network"));
FRAME_NEW (_("Network"));
TABLE_NEW (5, 2);
label = katze_property_label (settings, "http-proxy");
INDENTED_ADD (label, 0, 1, 0, 1);
entry = katze_property_proxy (settings, "http-proxy", NULL);
FILLED_ADD (entry, 1, 2, 0, 1);
button = katze_property_proxy (settings, "auto-detect-proxy", NULL);
FILLED_ADD (button, 1, 2, 1, 2);
g_signal_connect (settings, "notify::auto-detect-proxy",
G_CALLBACK (midori_preferences_notify_auto_detect_proxy_cb), entry);
midori_preferences_notify_auto_detect_proxy_cb (settings, NULL, entry);
label = katze_property_label (settings, "identify-as");
INDENTED_ADD (label, 0, 1, 2, 3);
button = katze_property_proxy (settings, "identify-as", NULL);
FILLED_ADD (button, 1, 2, 2, 3);
label = katze_property_label (settings, "ident-string");
INDENTED_ADD (label, 0, 1, 3, 4);
entry = katze_property_proxy (settings, "ident-string", NULL);
g_signal_connect (settings, "notify::identify-as",
G_CALLBACK (midori_preferences_notify_identify_as_cb), entry);
midori_preferences_notify_identify_as_cb (settings, NULL, entry);
FILLED_ADD (entry, 1, 2, 3, 4);
label = katze_property_label (settings, "cache-size");
INDENTED_ADD (label, 0, 1, 4, 5);
hbox = gtk_hbox_new (FALSE, 4);
entry = katze_property_proxy (settings, "cache-size", NULL);
gtk_box_pack_start (GTK_BOX (hbox), entry, FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (hbox), gtk_label_new (_("MB")),
FALSE, FALSE, 0);
FILLED_ADD (hbox, 1, 2, 4, 5);
/* Page "Privacy" */
PAGE_NEW (GTK_STOCK_INDEX, _("Privacy"));
FRAME_NEW (_("Web Cookies"));
TABLE_NEW (3, 2);
label = katze_property_label (settings, "accept-cookies");
INDENTED_ADD (label, 0, 1, 0, 1);
button = katze_property_proxy (settings, "accept-cookies", NULL);
FILLED_ADD (button, 1, 2, 0, 1);
button = katze_property_proxy (settings, "original-cookies-only", NULL);
SPANNED_ADD (button, 0, 2, 1, 2);
label = katze_property_label (settings, "maximum-cookie-age");
INDENTED_ADD (label, 0, 1, 2, 3);
hbox = gtk_hbox_new (FALSE, 4);
entry = katze_property_proxy (settings, "maximum-cookie-age", NULL);
gtk_box_pack_start (GTK_BOX (hbox), entry, FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (hbox), gtk_label_new (_("days")),
FALSE, FALSE, 0);
FILLED_ADD (hbox, 1, 2, 2, 3);
FRAME_NEW (_("History"));
TABLE_NEW (3, 2);
button = katze_property_proxy (settings, "remember-last-visited-pages", NULL);
SPANNED_ADD (button, 0, 1, 0, 1);
hbox = gtk_hbox_new (FALSE, 4);
button = katze_property_proxy (settings, "maximum-history-age", NULL);
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (hbox), gtk_label_new (_("days")),
FALSE, FALSE, 0);
SPANNED_ADD (hbox, 1, 2, 0, 1);
button = katze_property_proxy (settings, "remember-last-form-inputs", NULL);
SPANNED_ADD (button, 0, 2, 1, 2);
button = katze_property_proxy (settings, "remember-last-downloaded-files", NULL);
SPANNED_ADD (button, 0, 2, 2, 3);
g_object_unref (sizegroup);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (preferences)->vbox),
preferences->notebook, FALSE, FALSE, 4);
#if HAVE_OSX
GtkWidget* icon;
hbox = gtk_hbox_new (FALSE, 0);
button = gtk_button_new ();
icon = gtk_image_new_from_stock (GTK_STOCK_HELP, GTK_ICON_SIZE_BUTTON);
gtk_button_set_image (GTK_BUTTON (button), icon);
g_signal_connect (button, "clicked",
G_CALLBACK (midori_preferences_help_clicked_cb), preferences);
gtk_box_pack_end (GTK_BOX (hbox),
button, FALSE, FALSE, 4);
gtk_box_pack_end (GTK_BOX (GTK_DIALOG (preferences)->vbox),
hbox, FALSE, FALSE, 0);
#endif
gtk_widget_show_all (GTK_DIALOG (preferences)->vbox);
}

View file

@ -0,0 +1,57 @@
/*
Copyright (C) 2008 Christian Dywan <christian@twotoasts.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#ifndef __MIDORI_PREFERENCES_H__
#define __MIDORI_PREFERENCES_H__
#include "midori-websettings.h"
#include <gtk/gtk.h>
#include <katze/katze.h>
G_BEGIN_DECLS
#define MIDORI_TYPE_PREFERENCES \
(midori_preferences_get_type ())
#define MIDORI_PREFERENCES(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), MIDORI_TYPE_PREFERENCES, MidoriPreferences))
#define MIDORI_PREFERENCES_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), MIDORI_TYPE_PREFERENCES, MidoriPreferencesClass))
#define MIDORI_IS_PREFERENCES(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), MIDORI_TYPE_PREFERENCES))
#define MIDORI_IS_PREFERENCES_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), MIDORI_TYPE_PREFERENCES))
#define MIDORI_PREFERENCES_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), MIDORI_TYPE_PREFERENCES, MidoriPreferencesClass))
typedef struct _MidoriPreferences MidoriPreferences;
typedef struct _MidoriPreferencesClass MidoriPreferencesClass;
struct _MidoriPreferencesClass
{
GtkDialogClass parent_class;
};
GType
midori_preferences_get_type (void);
GtkWidget*
midori_preferences_new (GtkWindow* parent,
MidoriWebSettings* settings);
void
midori_preferences_set_settings (MidoriPreferences* preferences,
MidoriWebSettings* settings);
G_END_DECLS
#endif /* __MIDORI_PREFERENCES_H__ */

1337
midori/midori-searchaction.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,71 @@
/*
Copyright (C) 2008 Christian Dywan <christian@twotoasts.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#ifndef __MIDORI_SEARCH_ACTION_H__
#define __MIDORI_SEARCH_ACTION_H__
#include <katze/katze.h>
G_BEGIN_DECLS
#define MIDORI_TYPE_SEARCH_ACTION \
(midori_search_action_get_type ())
#define MIDORI_SEARCH_ACTION(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), MIDORI_TYPE_SEARCH_ACTION, MidoriSearchAction))
#define MIDORI_SEARCH_ACTION_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), MIDORI_TYPE_SEARCH_ACTION, MidoriSearchActionClass))
#define MIDORI_IS_SEARCH_ACTION(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), MIDORI_TYPE_SEARCH_ACTION))
#define MIDORI_IS_SEARCH_ACTION_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), MIDORI_TYPE_SEARCH_ACTION))
#define MIDORI_SEARCH_ACTION_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), MIDORI_TYPE_SEARCH_ACTION, MidoriSearchActionClass))
typedef struct _MidoriSearchAction MidoriSearchAction;
typedef struct _MidoriSearchActionClass MidoriSearchActionClass;
GType
midori_search_action_get_type (void);
const gchar*
midori_search_action_get_text (MidoriSearchAction* action);
void
midori_search_action_set_text (MidoriSearchAction* search_action,
const gchar* text);
KatzeArray*
midori_search_action_get_search_engines (MidoriSearchAction* search_action);
void
midori_search_action_set_search_engines (MidoriSearchAction* search_action,
KatzeArray* search_engines);
KatzeItem*
midori_search_action_get_current_item (MidoriSearchAction* search_action);
void
midori_search_action_set_current_item (MidoriSearchAction* search_action,
KatzeItem* item);
KatzeItem*
midori_search_action_get_default_item (MidoriSearchAction* search_action);
void
midori_search_action_set_default_item (MidoriSearchAction* search_action,
KatzeItem* item);
GtkWidget*
midori_search_action_get_dialog (MidoriSearchAction* search_action);
G_END_DECLS
#endif /* __MIDORI_SEARCH_ACTION_H__ */

46
midori/midori-stock.h Normal file
View file

@ -0,0 +1,46 @@
/*
Copyright (C) 2007-2008 Christian Dywan <christian@twotoasts.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#ifndef __MIDORI_STOCK_H__
#define __MIDORI_STOCK_H__ 1
#include <gtk/gtk.h>
/* Custom stock items
We should distribute these
Names should match with epiphany and/ or xdg spec */
#define STOCK_BOOKMARK "stock_bookmark"
#define STOCK_BOOKMARKS "vcard"
#define STOCK_CONSOLE "terminal"
#define STOCK_EXTENSION "extension"
#define STOCK_EXTENSIONS "extension"
#define STOCK_HISTORY "document-open-recent"
#define STOCK_NEWS_FEED "news-feed"
#define STOCK_STYLE "gnome-settings-theme"
#define STOCK_STYLES "gnome-settings-theme"
#define STOCK_TRANSFER "package"
#define STOCK_TRANSFERS "package"
#define STOCK_PLUGINS GTK_STOCK_CONVERT
#define STOCK_BOOKMARK_ADD "stock_add-bookmark"
#define STOCK_HOMEPAGE GTK_STOCK_HOME
#define STOCK_IMAGE "gnome-mime-image"
#define STOCK_NETWORK_OFFLINE "network-offline"
#define STOCK_SCRIPT "stock_script"
#define STOCK_SCRIPTS "stock_script"
#define STOCK_SEND "stock_mail-send"
#define STOCK_TAB_NEW "stock_new-tab"
#define STOCK_USER_TRASH "gnome-stock-trash"
#define STOCK_WINDOW_NEW "stock_new-window"
#endif /* !__MIDORI_STOCK_H__ */

2681
midori/midori-view.c Normal file

File diff suppressed because it is too large Load diff

194
midori/midori-view.h Normal file
View file

@ -0,0 +1,194 @@
/*
Copyright (C) 2008 Christian Dywan <christian@twotoasts.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#ifndef __MIDORI_VIEW_H__
#define __MIDORI_VIEW_H__
#include "midori-websettings.h"
#include <katze/katze.h>
G_BEGIN_DECLS
typedef enum
{
MIDORI_LOAD_PROVISIONAL,
MIDORI_LOAD_COMMITTED,
MIDORI_LOAD_FINISHED
} MidoriLoadStatus;
GType
midori_load_status_get_type (void) G_GNUC_CONST;
#define MIDORI_TYPE_LOAD_STATUS \
(midori_load_status_get_type ())
typedef enum
{
MIDORI_NEW_VIEW_TAB,
MIDORI_NEW_VIEW_BACKGROUND,
MIDORI_NEW_VIEW_WINDOW
} MidoriNewView;
GType
midori_new_view_get_type (void) G_GNUC_CONST;
#define MIDORI_TYPE_NEW_VIEW \
(midori_new_view_get_type ())
#define MIDORI_TYPE_VIEW \
(midori_view_get_type ())
#define MIDORI_VIEW(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), MIDORI_TYPE_VIEW, MidoriView))
#define MIDORI_VIEW_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), MIDORI_TYPE_VIEW, MidoriViewClass))
#define MIDORI_IS_VIEW(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), MIDORI_TYPE_VIEW))
#define MIDORI_IS_VIEW_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), MIDORI_TYPE_VIEW))
#define MIDORI_VIEW_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), MIDORI_TYPE_VIEW, MidoriViewClass))
typedef struct _MidoriView MidoriView;
typedef struct _MidoriViewClass MidoriViewClass;
GType
midori_view_get_type (void);
GtkWidget*
midori_view_new (KatzeNet* net);
void
midori_view_set_settings (MidoriView* view,
MidoriWebSettings* settings);
gdouble
midori_view_get_progress (MidoriView* view);
MidoriLoadStatus
midori_view_get_load_status (MidoriView* view);
void
midori_view_set_uri (MidoriView* view,
const gchar* uri);
gboolean
midori_view_is_blank (MidoriView* view);
const gchar*
midori_view_get_display_uri (MidoriView* view);
const gchar*
midori_view_get_display_title (MidoriView* view);
GdkPixbuf*
midori_view_get_icon (MidoriView* view);
const gchar*
midori_view_get_link_uri (MidoriView* view);
gboolean
midori_view_has_selection (MidoriView* view);
const gchar*
midori_view_get_selected_text (MidoriView* view);
gboolean
midori_view_can_cut_clipboard (MidoriView* view);
gboolean
midori_view_can_copy_clipboard (MidoriView* view);
gboolean
midori_view_can_paste_clipboard (MidoriView* view);
GtkWidget*
midori_view_get_proxy_menu_item (MidoriView* view);
GtkWidget*
midori_view_get_proxy_tab_label (MidoriView* view);
KatzeItem*
midori_view_get_proxy_item (MidoriView* view);
gfloat
midori_view_get_zoom_level (MidoriView* view);
gboolean
midori_view_can_zoom_in (MidoriView* view);
gboolean
midori_view_can_zoom_out (MidoriView* view);
void
midori_view_set_zoom_level (MidoriView* view,
gfloat zoom_level);
gboolean
midori_view_can_reload (MidoriView* view);
void
midori_view_reload (MidoriView* view,
gboolean from_cache);
void
midori_view_stop_loading (MidoriView* view);
gboolean
midori_view_can_go_back (MidoriView* view);
void
midori_view_go_back (MidoriView* view);
gboolean
midori_view_can_go_forward (MidoriView* view);
void
midori_view_go_forward (MidoriView* view);
gboolean
midori_view_can_print (MidoriView* view);
void
midori_view_print (MidoriView* view);
gboolean
midori_view_can_view_source (MidoriView* view);
gboolean
midori_view_can_find (MidoriView* view);
void
midori_view_unmark_text_matches (MidoriView* view);
void
midori_view_search_text (MidoriView* view,
const gchar* text,
gboolean case_sensitive,
gboolean forward);
void
midori_view_mark_text_matches (MidoriView* view,
const gchar* text,
gboolean case_sensitive);
void
midori_view_set_highlight_text_matches (MidoriView* view,
gboolean highlight);
gboolean
midori_view_execute_script (MidoriView* view,
const gchar* script,
gchar** exception);
G_END_DECLS
#endif /* __MIDORI_VIEW_H__ */

263
midori/midori-viewable.c Normal file
View file

@ -0,0 +1,263 @@
/*
Copyright (C) 2008 Christian Dywan <christian@twotoasts.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#include "midori-viewable.h"
#include <glib/gi18n.h>
static void
midori_viewable_base_init (MidoriViewableIface* iface);
static void
midori_viewable_base_finalize (MidoriViewableIface* iface);
GType
midori_viewable_get_type (void)
{
static GType viewable_type = 0;
if (!viewable_type)
{
const GTypeInfo viewable_info =
{
sizeof (MidoriViewableIface),
(GBaseInitFunc) midori_viewable_base_init,
(GBaseFinalizeFunc) midori_viewable_base_finalize,
};
viewable_type = g_type_register_static (G_TYPE_INTERFACE,
"MidoriViewable",
&viewable_info, 0);
g_type_interface_add_prerequisite (viewable_type, GTK_TYPE_WIDGET);
}
return viewable_type;
}
static const gchar*
midori_viewable_default_get_stock_id (MidoriViewable* viewable)
{
return NULL;
}
static const gchar*
midori_viewable_default_get_label (MidoriViewable* viewable)
{
return NULL;
}
static GtkWidget*
midori_viewable_default_get_toolbar (MidoriViewable* viewable)
{
return NULL;
}
static void
midori_viewable_base_init (MidoriViewableIface* iface)
{
static gboolean initialized = FALSE;
if (initialized)
return;
iface->p = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
iface->get_stock_id = midori_viewable_default_get_stock_id;
iface->get_label = midori_viewable_default_get_label;
iface->get_toolbar = midori_viewable_default_get_toolbar;
initialized = TRUE;
}
static void
midori_viewable_base_finalize (MidoriViewableIface* iface)
{
g_hash_table_destroy (iface->p);
}
/**
* midori_viewable_new_from_uri:
* @uri: an URI
*
* Attempts to create a new #MidoriViewable from the specified URI.
*
* The protocol of @uri must previously have been registered by
* the #MidoriViewable via midori_viewable_register_protocol().
*
* Return value: a new #MidoriViewable, or %NULL
**/
GtkWidget*
midori_viewable_new_from_uri (const gchar* uri)
{
MidoriViewableIface* iface;
gchar** parts;
gchar* type_name;
GType type;
if (!(iface = g_type_default_interface_peek (MIDORI_TYPE_VIEWABLE)))
{
g_warning ("No viewable interface available");
return NULL;
}
g_return_val_if_fail (uri != NULL, NULL);
if (!g_hash_table_size (iface->p))
return NULL;
if ((parts = g_strsplit (uri, "://", 2)))
{
if (!(type_name = g_hash_table_lookup (iface->p, parts[0])))
{
/* FIXME: Support midori://dummy/foo */
type_name = g_hash_table_lookup (iface->p, uri);
}
g_strfreev (parts);
if (type_name)
{
type = g_type_from_name (type_name);
g_free (type_name);
if (type)
return g_object_new (type, "uri", uri, NULL);
}
}
else if ((parts = g_strsplit_set (uri, ":", 2)))
{
type_name = g_hash_table_lookup (iface->p, parts[0]);
g_strfreev (parts);
if (type_name)
{
type = g_type_from_name (type_name);
g_free (type_name);
if (type)
return g_object_new (type, "uri", uri, NULL);
}
}
return NULL;
}
static gboolean
viewable_type_implements (GType type,
GType interface)
{
GType *interfaces;
guint i;
if (!(interfaces = g_type_interfaces (type, NULL)))
return FALSE;
for (i = 0; interfaces[i]; i++)
{
if (interfaces[i] == interface)
{
g_free (interfaces);
return TRUE;
}
}
g_free (interfaces);
return FALSE;
}
/**
* midori_viewable_register_protocol:
* @type: a type that implements #MidoriViewable
* @protocol: a protocol
*
* Registers the specified protocol as supported by @type.
*
* The following kinds of protocols are supported:
*
* "dummy": support URIs like "dummy://foo/bar"
* "about:dummy": support URIs like "about:dummy"
* FIXME: The following is not yet fully supported
* "midori://dummy": support URIs like "midori://dummy/foo"
*
* Return value: a new #MidoriViewable, or %NULL
**/
void
midori_viewable_register_protocol (GType type,
const gchar* protocol)
{
MidoriViewableIface* iface;
GObjectClass* class;
if (!(iface = g_type_default_interface_peek (MIDORI_TYPE_VIEWABLE)))
{
g_warning ("No viewable interface available");
return;
}
g_return_if_fail (viewable_type_implements (type, MIDORI_TYPE_VIEWABLE));
if (!(class = g_type_class_peek (type)))
{
g_warning ("No class for %s available", g_type_name (type));
return;
}
g_return_if_fail (g_object_class_find_property (class, "uri"));
/* FIXME: Verify the syntax of protocol */
g_hash_table_insert (iface->p, g_strdup (protocol),
g_strdup (g_type_name (type)));
}
/**
* midori_viewable_get_stock_id:
* @viewable: a #MidoriViewable
*
* Retrieves the stock ID of the viewable.
*
* Return value: a stock ID
**/
const gchar*
midori_viewable_get_stock_id (MidoriViewable* viewable)
{
g_return_val_if_fail (MIDORI_IS_VIEWABLE (viewable), NULL);
return MIDORI_VIEWABLE_GET_IFACE (viewable)->get_stock_id (viewable);
}
/**
* midori_viewable_get_label:
* @viewable: a #MidoriViewable
*
* Retrieves the label of the viewable.
*
* Return value: a label string
**/
const gchar*
midori_viewable_get_label (MidoriViewable* viewable)
{
g_return_val_if_fail (MIDORI_IS_VIEWABLE (viewable), NULL);
return MIDORI_VIEWABLE_GET_IFACE (viewable)->get_label (viewable);
}
/**
* midori_viewable_get_toolbar:
* @viewable: a #MidoriViewable
*
* Retrieves the toolbar of the viewable.
*
* Return value: a toolbar
**/
GtkWidget*
midori_viewable_get_toolbar (MidoriViewable* viewable)
{
GtkWidget* toolbar;
g_return_val_if_fail (MIDORI_IS_VIEWABLE (viewable), NULL);
toolbar = MIDORI_VIEWABLE_GET_IFACE (viewable)->get_toolbar (viewable);
if (!toolbar)
toolbar = gtk_event_box_new ();
return toolbar;
}

73
midori/midori-viewable.h Normal file
View file

@ -0,0 +1,73 @@
/*
Copyright (C) 2008 Christian Dywan <christian@twotoasts.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#ifndef __MIDORI_VIEWABLE_H__
#define __MIDORI_VIEWABLE_H__
#include <gtk/gtk.h>
#include <katze/katze.h>
G_BEGIN_DECLS
#define MIDORI_TYPE_VIEWABLE \
(midori_viewable_get_type ())
#define MIDORI_VIEWABLE(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), MIDORI_TYPE_VIEWABLE, MidoriViewable))
#define MIDORI_IS_VIEWABLE(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), MIDORI_TYPE_VIEWABLE))
#define MIDORI_VIEWABLE_GET_IFACE(inst) \
(G_TYPE_INSTANCE_GET_INTERFACE ((inst), MIDORI_TYPE_VIEWABLE, \
MidoriViewableIface))
typedef struct _MidoriViewable MidoriViewable;
typedef struct _MidoriViewableIface MidoriViewableIface;
struct _MidoriViewableIface
{
GTypeInterface base_iface;
/* Virtual functions */
const gchar*
(*get_stock_id) (MidoriViewable* viewable);
const gchar*
(*get_label) (MidoriViewable* viewable);
GtkWidget*
(*get_toolbar) (MidoriViewable* viewable);
/* Private data */
gpointer p;
};
GType
midori_viewable_get_type (void);
GtkWidget*
midori_viewable_new_from_uri (const gchar* uri);
void
midori_viewable_register_protocol (GType type,
const gchar* protocol);
const gchar*
midori_viewable_get_stock_id (MidoriViewable* viewable);
const gchar*
midori_viewable_get_label (MidoriViewable* viewable);
GtkWidget*
midori_viewable_get_toolbar (MidoriViewable* viewable);
G_END_DECLS
#endif /* __MIDORI_VIEWABLE_H__ */

1399
midori/midori-websettings.c Normal file

File diff suppressed because it is too large Load diff

144
midori/midori-websettings.h Normal file
View file

@ -0,0 +1,144 @@
/*
Copyright (C) 2008 Christian Dywan <christian@twotoasts.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#ifndef __MIDORI_WEB_SETTINGS_H__
#define __MIDORI_WEB_SETTINGS_H__
#include <webkit/webkit.h>
#include <katze/katze.h>
G_BEGIN_DECLS
#define MIDORI_TYPE_WEB_SETTINGS \
(midori_web_settings_get_type ())
#define MIDORI_WEB_SETTINGS(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), MIDORI_TYPE_WEB_SETTINGS, MidoriWebSettings))
#define MIDORI_WEB_SETTINGS_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), MIDORI_TYPE_WEB_SETTINGS, MidoriWebSettingsClass))
#define MIDORI_IS_WEB_SETTINGS(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), MIDORI_TYPE_WEB_SETTINGS))
#define MIDORI_IS_WEB_SETTINGS_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), MIDORI_TYPE_WEB_SETTINGS))
#define MIDORI_WEB_SETTINGS_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), MIDORI_TYPE_WEB_SETTINGS, MidoriWebSettingsClass))
typedef struct _MidoriWebSettings MidoriWebSettings;
typedef struct _MidoriWebSettingsClass MidoriWebSettingsClass;
typedef enum
{
MIDORI_WINDOW_NORMAL,
MIDORI_WINDOW_MINIMIZED,
MIDORI_WINDOW_MAXIMIZED,
MIDORI_WINDOW_FULLSCREEN,
} MidoriWindowState;
GType
midori_window_state_get_type (void) G_GNUC_CONST;
#define MIDORI_TYPE_WINDOW_STATE \
(midori_window_state_get_type ())
typedef enum
{
MIDORI_STARTUP_BLANK_PAGE,
MIDORI_STARTUP_HOMEPAGE,
MIDORI_STARTUP_LAST_OPEN_PAGES
} MidoriStartup;
GType
midori_startup_get_type (void) G_GNUC_CONST;
#define MIDORI_TYPE_STARTUP \
(midori_startup_get_type ())
typedef enum
{
MIDORI_ENCODING_CHINESE,
MIDORI_ENCODING_JAPANESE,
MIDORI_ENCODING_RUSSIAN,
MIDORI_ENCODING_UNICODE,
MIDORI_ENCODING_WESTERN,
MIDORI_ENCODING_CUSTOM
} MidoriPreferredEncoding;
GType
midori_preferred_encoding_get_type (void) G_GNUC_CONST;
#define MIDORI_TYPE_PREFERRED_ENCODING \
(midori_preferred_encoding_get_type ())
typedef enum
{
MIDORI_NEW_PAGE_TAB,
MIDORI_NEW_PAGE_WINDOW,
MIDORI_NEW_PAGE_CURRENT
} MidoriNewPage;
GType
midori_new_page_get_type (void) G_GNUC_CONST;
#define MIDORI_TYPE_NEW_PAGE \
(midori_new_page_get_type ())
typedef enum
{
MIDORI_TOOLBAR_DEFAULT,
MIDORI_TOOLBAR_ICONS,
MIDORI_TOOLBAR_TEXT,
MIDORI_TOOLBAR_BOTH,
MIDORI_TOOLBAR_BOTH_HORIZ
} MidoriToolbarStyle;
GType
midori_toolbar_style_get_type (void) G_GNUC_CONST;
#define MIDORI_TYPE_TOOLBAR_STYLE \
(midori_toolbar_style_get_type ())
typedef enum
{
MIDORI_ACCEPT_COOKIES_ALL,
MIDORI_ACCEPT_COOKIES_SESSION,
MIDORI_ACCEPT_COOKIES_NONE
} MidoriAcceptCookies;
GType
midori_accept_cookies_get_type (void) G_GNUC_CONST;
#define MIDORI_TYPE_ACCEPT_COOKIES \
(midori_accept_cookies_get_type ())
typedef enum
{
MIDORI_IDENT_MIDORI,
MIDORI_IDENT_SAFARI,
MIDORI_IDENT_FIREFOX,
MIDORI_IDENT_EXPLORER,
MIDORI_IDENT_CUSTOM
} MidoriIdentity;
GType
midori_identity_get_type (void) G_GNUC_CONST;
#define MIDORI_TYPE_IDENTITY \
(midori_identity_get_type ())
GType
midori_web_settings_get_type (void);
MidoriWebSettings*
midori_web_settings_new (void);
G_END_DECLS
#endif /* __MIDORI_WEB_SETTINGS_H__ */

38
midori/midori.h Normal file
View file

@ -0,0 +1,38 @@
/*
Copyright (C) 2008-2009 Christian Dywan <christian@twotoasts.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#ifndef __MIDORI_H__
#define __MIDORI_H__
#include "midori-app.h"
#include "midori-array.h"
#include "midori-browser.h"
#include "midori-extension.h"
#include "midori-locationaction.h"
#include "midori-locationentry.h"
#include "midori-panel.h"
#include "midori-preferences.h"
#include "midori-searchaction.h"
#include "midori-stock.h"
#include "midori-view.h"
#include "midori-viewable.h"
#include "midori-websettings.h"
/* For convenience, include localization header */
#include <glib/gi18n.h>
#define MIDORI_CHECK_VERSION(major, minor, micro) \
(MIDORI_MAJOR_VERSION > (major) || \
(MIDORI_MAJOR_VERSION == (major) && MIDORI_MINOR_VERSION > (minor)) || \
(MIDORI_MAJOR_VERSION == (major) && MIDORI_MINOR_VERSION == (minor) && \
MIDORI_MICRO_VERSION >= (micro)))
#endif /* __MIDORI_H__ */

882
midori/sokoke.c Normal file
View file

@ -0,0 +1,882 @@
/*
Copyright (C) 2007-2009 Christian Dywan <christian@twotoasts.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#include "sokoke.h"
#include "midori-stock.h"
#if HAVE_CONFIG_H
#include <config.h>
#endif
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <stdlib.h>
#include <string.h>
#include <gdk/gdkkeysyms.h>
#include <glib/gi18n.h>
#include <glib/gprintf.h>
#include <glib/gstdio.h>
#if HAVE_LIBIDN
#include <stringprep.h>
#include <punycode.h>
#include <idna.h>
#endif
static gchar*
sokoke_js_string_utf8 (JSStringRef js_string)
{
size_t size_utf8;
gchar* string_utf8;
g_return_val_if_fail (js_string, NULL);
size_utf8 = JSStringGetMaximumUTF8CStringSize (js_string);
string_utf8 = g_new (gchar, size_utf8);
JSStringGetUTF8CString (js_string, string_utf8, size_utf8);
return string_utf8;
}
gchar*
sokoke_js_script_eval (JSContextRef js_context,
const gchar* script,
gchar** exception)
{
gchar* value;
JSStringRef js_value_string;
g_return_val_if_fail (js_context, FALSE);
g_return_val_if_fail (script, FALSE);
JSStringRef js_script = JSStringCreateWithUTF8CString (script);
JSValueRef js_exception = NULL;
JSValueRef js_value = JSEvaluateScript (js_context, js_script,
JSContextGetGlobalObject (js_context), NULL, 0, &js_exception);
if (!js_value && exception)
{
JSStringRef js_message = JSValueToStringCopy (js_context,
js_exception, NULL);
*exception = sokoke_js_string_utf8 (js_message);
JSStringRelease (js_message);
js_value = JSValueMakeNull (js_context);
}
JSStringRelease (js_script);
js_value_string = JSValueToStringCopy (js_context, js_value, NULL);
value = sokoke_js_string_utf8 (js_value_string);
JSStringRelease (js_value_string);
return value;
}
static void
error_dialog (const gchar* short_message,
const gchar* detailed_message)
{
GtkWidget* dialog = gtk_message_dialog_new (
NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "%s", short_message);
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
"%s", detailed_message);
gtk_widget_show (dialog);
g_signal_connect_swapped (dialog, "response",
G_CALLBACK (gtk_widget_destroy), dialog);
}
gboolean
sokoke_spawn_program (const gchar* command,
const gchar* argument)
{
gchar* argument_escaped;
gchar* command_ready;
gchar** argv;
GError* error;
g_return_val_if_fail (command != NULL, FALSE);
g_return_val_if_fail (argument != NULL, FALSE);
argument_escaped = g_shell_quote (argument);
if (strstr (command, "%s"))
command_ready = g_strdup_printf (command, argument_escaped);
else
command_ready = g_strconcat (command, " ", argument_escaped, NULL);
error = NULL;
if (!g_shell_parse_argv (command_ready, NULL, &argv, &error))
{
error_dialog (_("Could not run external program."), error->message);
g_error_free (error);
g_free (command_ready);
g_free (argument_escaped);
return FALSE;
}
error = NULL;
if (!g_spawn_async (NULL, argv, NULL,
(GSpawnFlags)G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
NULL, NULL, NULL, &error))
{
error_dialog (_("Could not run external program."), error->message);
g_error_free (error);
}
g_strfreev (argv);
g_free (command_ready);
g_free (argument_escaped);
return TRUE;
}
static gchar*
sokoke_idn_to_punycode (gchar* uri)
{
#if HAVE_LIBIDN
gchar* proto;
gchar* hostname;
gchar* path;
char *s;
uint32_t *q;
int rc;
gchar *result;
if ((proto = g_utf8_strchr (uri, -1, ':')))
{
gulong offset;
gchar* buffer;
/* 'file' URIs don't have a hostname */
if (!strcmp (proto, "file"))
return uri;
offset = g_utf8_pointer_to_offset (uri, proto);
buffer = g_malloc0 (offset + 1);
g_utf8_strncpy (buffer, uri, offset);
proto = buffer;
}
path = NULL;
if ((hostname = g_utf8_strchr (uri, -1, '/')))
{
if (hostname[1] == '/')
hostname += 2;
if ((path = g_utf8_strchr (hostname, -1, '/')))
{
gulong offset = g_utf8_pointer_to_offset (hostname, path);
gchar* buffer = g_malloc0 (offset + 1);
g_utf8_strncpy (buffer, hostname, offset);
hostname = buffer;
}
}
else
hostname = g_strdup (uri);
if (!(q = stringprep_utf8_to_ucs4 (hostname, -1, NULL)))
{
g_free (proto);
g_free (hostname);
return uri;
}
rc = idna_to_ascii_4z (q, &s, IDNA_ALLOW_UNASSIGNED);
free (q);
if (rc != IDNA_SUCCESS)
{
g_free (proto);
g_free (hostname);
return uri;
}
if (proto)
{
result = g_strconcat (proto, "://", s, path ? path : "", NULL);
g_free (proto);
if (path)
g_free (hostname);
}
else
result = g_strdup (s);
g_free (uri);
free (s);
return result;
#else
return uri;
#endif
}
gchar*
sokoke_magic_uri (const gchar* uri,
KatzeArray* search_engines)
{
gchar* current_dir;
gchar* result;
gchar** parts;
gchar* search;
const gchar* search_uri;
KatzeItem* item;
g_return_val_if_fail (uri, NULL);
g_return_val_if_fail (!search_engines ||
katze_array_is_a (search_engines, KATZE_TYPE_ITEM), NULL);
/* Just return if it's a javascript: or mailto: uri */
if (g_str_has_prefix (uri, "javascript:")
|| g_str_has_prefix (uri, "mailto:")
|| g_str_has_prefix (uri, "data:"))
return g_strdup (uri);
/* Add file:// if we have a local path */
if (g_path_is_absolute (uri))
return g_strconcat ("file://", uri, NULL);
/* Construct an absolute path if the file is relative */
if (g_file_test (uri, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR))
{
current_dir = g_get_current_dir ();
result = g_strconcat ("file://", current_dir,
G_DIR_SEPARATOR_S, uri, NULL);
g_free (current_dir);
return result;
}
/* Do we have a protocol? */
if (g_strstr_len (uri, 8, "://"))
return sokoke_idn_to_punycode (g_strdup (uri));
/* Do we have a domain, ip address or localhost? */
search = NULL;
if (!strchr (uri, ' ') &&
((search = strchr (uri, ':')) || (search = strchr (uri, '@'))) &&
search[0] && !g_ascii_isalpha (search[1]))
return sokoke_idn_to_punycode (g_strconcat ("http://", uri, NULL));
if (!strcmp (uri, "localhost") || g_str_has_prefix (uri, "localhost/"))
return g_strconcat ("http://", uri, NULL);
parts = g_strsplit (uri, ".", 0);
if (!search && parts[0] && parts[1])
{
if (!(parts[1][1] == '\0' && !g_ascii_isalpha (parts[1][0])))
if (!strchr (parts[0], ' ') && !strchr (parts[1], ' '))
if ((search = g_strconcat ("http://", uri, NULL)))
{
g_strfreev (parts);
return sokoke_idn_to_punycode (search);
}
}
g_strfreev (parts);
/* We don't want to search? So return early. */
if (!search_engines)
return g_strdup (uri);
search = NULL;
search_uri = NULL;
/* Do we have a keyword and a string? */
parts = g_strsplit (uri, " ", 2);
if (parts[0] && parts[1])
if ((item = katze_array_find_token (search_engines, parts[0])))
{
gchar* uri_ = g_uri_escape_string (parts[1], " :/", TRUE);
search_uri = katze_item_get_uri (item);
if (strstr (search_uri, "%s"))
search = g_strdup_printf (search_uri, uri_);
else
search = g_strconcat (search_uri, uri_, NULL);
g_free (uri_);
}
g_strfreev (parts);
return search;
}
void
sokoke_combo_box_add_strings (GtkComboBox* combobox,
const gchar* label_first, ...)
{
const gchar* label;
/* Add a number of strings to a combobox, terminated with NULL
This works only for text comboboxes */
va_list args;
va_start (args, label_first);
for (label = label_first; label; label = va_arg (args, const gchar*))
gtk_combo_box_append_text (combobox, label);
va_end (args);
}
void sokoke_widget_set_visible (GtkWidget* widget, gboolean visible)
{
/* Show or hide the widget */
if (visible)
gtk_widget_show (widget);
else
gtk_widget_hide (widget);
}
void
sokoke_container_show_children (GtkContainer* container)
{
/* Show every child but not the container itself */
gtk_container_foreach (container, (GtkCallback)(gtk_widget_show_all), NULL);
}
void
sokoke_widget_popup (GtkWidget* widget,
GtkMenu* menu,
GdkEventButton* event,
SokokeMenuPos pos)
{
katze_widget_popup (widget, menu, event, (KatzeMenuPos)pos);
}
typedef enum
{
SOKOKE_DESKTOP_UNTESTED,
SOKOKE_DESKTOP_XFCE,
SOKOKE_DESKTOP_OSX,
SOKOKE_DESKTOP_UNKNOWN
} SokokeDesktop;
static SokokeDesktop
sokoke_get_desktop (void)
{
#if HAVE_OSX
return SOKOKE_DESKTOP_OSX;
#else
static SokokeDesktop desktop = SOKOKE_DESKTOP_UNTESTED;
if (G_UNLIKELY (desktop == SOKOKE_DESKTOP_UNTESTED))
{
/* Are we running in Xfce? */
gint result;
gchar *out = NULL;
gboolean success = g_spawn_command_line_sync ("xprop -root _DT_SAVE_MODE",
&out, NULL, &result, NULL);
if (success && ! result && out != NULL && strstr (out, "xfce4") != NULL)
desktop = SOKOKE_DESKTOP_XFCE;
else
desktop = SOKOKE_DESKTOP_UNKNOWN;
g_free (out);
}
return desktop;
#endif
}
/**
* sokoke_xfce_header_new:
* @icon: an icon name
* @title: the title of the header
*
* Creates an Xfce style header *if* Xfce is running.
*
* Return value: A #GtkWidget or %NULL
*
* Since 0.1.2 @icon may be NULL, and a default is used.
**/
GtkWidget*
sokoke_xfce_header_new (const gchar* icon,
const gchar* title)
{
g_return_val_if_fail (title, NULL);
/* Create an xfce header with icon and title
This returns NULL if the desktop is not Xfce */
if (sokoke_get_desktop () == SOKOKE_DESKTOP_XFCE)
{
GtkWidget* entry;
gchar* markup;
GtkWidget* xfce_heading;
GtkWidget* hbox;
GtkWidget* image;
GtkWidget* label;
GtkWidget* vbox;
GtkWidget* separator;
xfce_heading = gtk_event_box_new ();
entry = gtk_entry_new ();
gtk_widget_modify_bg (xfce_heading, GTK_STATE_NORMAL,
&entry->style->base[GTK_STATE_NORMAL]);
hbox = gtk_hbox_new (FALSE, 12);
gtk_container_set_border_width (GTK_CONTAINER (hbox), 6);
if (icon)
image = gtk_image_new_from_icon_name (icon, GTK_ICON_SIZE_DIALOG);
else
image = gtk_image_new_from_stock (GTK_STOCK_PREFERENCES,
GTK_ICON_SIZE_DIALOG);
gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
label = gtk_label_new (NULL);
gtk_widget_modify_fg (label, GTK_STATE_NORMAL
, &entry->style->text[GTK_STATE_NORMAL]);
markup = g_strdup_printf ("<span size='large' weight='bold'>%s</span>",
title);
gtk_label_set_markup (GTK_LABEL (label), markup);
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
gtk_container_add (GTK_CONTAINER (xfce_heading), hbox);
g_free (markup);
gtk_widget_destroy (entry);
vbox = gtk_vbox_new (FALSE, 0);
gtk_box_pack_start (GTK_BOX (vbox), xfce_heading, FALSE, FALSE, 0);
separator = gtk_hseparator_new ();
gtk_box_pack_start (GTK_BOX (vbox), separator, FALSE, FALSE, 0);
return vbox;
}
return NULL;
}
GtkWidget*
sokoke_superuser_warning_new (void)
{
/* Create a horizontal bar with a security warning
This returns NULL if the user is no superuser */
#if HAVE_UNISTD_H
if (G_UNLIKELY (!geteuid ())) /* effective superuser? */
{
GtkWidget* hbox;
GtkWidget* label;
hbox = gtk_event_box_new ();
gtk_widget_modify_bg (hbox, GTK_STATE_NORMAL,
&hbox->style->bg[GTK_STATE_SELECTED]);
/* i18n: A superuser, or system administrator, may not be 'root' */
label = gtk_label_new (_("Warning: You are using a superuser account!"));
gtk_misc_set_padding (GTK_MISC (label), 0, 2);
gtk_widget_modify_fg (GTK_WIDGET (label), GTK_STATE_NORMAL,
&GTK_WIDGET (label)->style->fg[GTK_STATE_SELECTED]);
gtk_widget_show (label);
gtk_container_add (GTK_CONTAINER (hbox), GTK_WIDGET (label));
gtk_widget_show (hbox);
return hbox;
}
#endif
return NULL;
}
GtkWidget*
sokoke_hig_frame_new (const gchar* title)
{
/* Create a frame with no actual frame but a bold label and indentation */
GtkWidget* frame = gtk_frame_new (NULL);
gchar* title_bold = g_strdup_printf ("<b>%s</b>", title);
GtkWidget* label = gtk_label_new (NULL);
gtk_label_set_markup (GTK_LABEL (label), title_bold);
g_free (title_bold);
gtk_frame_set_label_widget (GTK_FRAME (frame), label);
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_NONE);
return frame;
}
void
sokoke_widget_set_pango_font_style (GtkWidget* widget,
PangoStyle style)
{
/* Conveniently change the pango font style
For some reason we need to reset if we actually want the normal style */
if (style == PANGO_STYLE_NORMAL)
gtk_widget_modify_font (widget, NULL);
else
{
PangoFontDescription* font_description = pango_font_description_new ();
pango_font_description_set_style (font_description, PANGO_STYLE_ITALIC);
gtk_widget_modify_font (widget, font_description);
pango_font_description_free (font_description);
}
}
static gboolean
sokoke_on_entry_focus_in_event (GtkEntry* entry,
GdkEventFocus* event,
gpointer userdata)
{
gint has_default = GPOINTER_TO_INT (
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));
sokoke_widget_set_pango_font_style (GTK_WIDGET (entry),
PANGO_STYLE_NORMAL);
}
return FALSE;
}
static gboolean
sokoke_on_entry_focus_out_event (GtkEntry* entry,
GdkEventFocus* event,
gpointer userdata)
{
const gchar* text = gtk_entry_get_text (entry);
if (text && !*text)
{
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));
sokoke_widget_set_pango_font_style (GTK_WIDGET (entry),
PANGO_STYLE_ITALIC);
}
return FALSE;
}
void
sokoke_entry_set_default_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)
{
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);
}
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"));
if (has_default)
{
gtk_entry_set_text (entry, default_text);
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);
g_signal_connect (entry, "focus-in-event",
G_CALLBACK (sokoke_on_entry_focus_in_event), NULL);
g_signal_connect (entry, "focus-out-event",
G_CALLBACK (sokoke_on_entry_focus_out_event), NULL);
}
gchar*
sokoke_key_file_get_string_default (GKeyFile* key_file,
const gchar* group,
const gchar* key,
const gchar* default_value,
GError** error)
{
gchar* value = g_key_file_get_string (key_file, group, key, error);
return value == NULL ? g_strdup (default_value) : value;
}
gint
sokoke_key_file_get_integer_default (GKeyFile* key_file,
const gchar* group,
const gchar* key,
const gint default_value,
GError** error)
{
if (!g_key_file_has_key (key_file, group, key, NULL))
return default_value;
return g_key_file_get_integer (key_file, group, key, error);
}
gdouble
sokoke_key_file_get_double_default (GKeyFile* key_file,
const gchar* group,
const gchar* key,
const gdouble default_value,
GError** error)
{
if (!g_key_file_has_key (key_file, group, key, NULL))
return default_value;
return g_key_file_get_double (key_file, group, key, error);
}
gboolean
sokoke_key_file_get_boolean_default (GKeyFile* key_file,
const gchar* group,
const gchar* key,
const gboolean default_value,
GError** error)
{
if (!g_key_file_has_key (key_file, group, key, NULL))
return default_value;
return g_key_file_get_boolean (key_file, group, key, error);
}
gboolean
sokoke_key_file_save_to_file (GKeyFile* key_file,
const gchar* filename,
GError** error)
{
gchar* data;
FILE* fp;
data = g_key_file_to_data (key_file, NULL, error);
if (!data)
return FALSE;
if (!(fp = fopen (filename, "w")))
{
*error = g_error_new (G_FILE_ERROR, G_FILE_ERROR_ACCES,
_("Writing failed."));
return FALSE;
}
fputs (data, fp);
fclose (fp);
g_free (data);
return TRUE;
}
void
sokoke_widget_get_text_size (GtkWidget* widget,
const gchar* text,
gint* width,
gint* height)
{
PangoLayout* layout = gtk_widget_create_pango_layout (widget, text);
pango_layout_get_pixel_size (layout, width, height);
g_object_unref (layout);
}
/**
* sokoke_action_create_popup_menu_item:
* @action: a #GtkAction
*
* Creates a menu item from an action, just like
* gtk_action_create_menu_item(), but it won't
* display an accelerator.
*
* Note: This menu item is not a proxy and will
* not reflect any changes to the action.
*
* Return value: a new #GtkMenuItem
**/
GtkWidget*
sokoke_action_create_popup_menu_item (GtkAction* action)
{
GtkWidget* menuitem;
GtkWidget* icon;
gchar* label;
gchar* stock_id;
gchar* icon_name;
gboolean sensitive;
gboolean visible;
g_return_val_if_fail (GTK_IS_ACTION (action), NULL);
g_object_get (action,
"label", &label,
"stock-id", &stock_id,
"icon-name", &icon_name,
"sensitive", &sensitive,
"visible", &visible,
NULL);
if (GTK_IS_TOGGLE_ACTION (action))
{
menuitem = gtk_check_menu_item_new_with_mnemonic (label);
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menuitem),
gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)));
}
else if (stock_id)
{
if (label)
{
menuitem = gtk_image_menu_item_new_with_mnemonic (label);
icon = gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_MENU);
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), icon);
}
else
menuitem = gtk_image_menu_item_new_from_stock (stock_id, NULL);
}
else
{
menuitem = gtk_image_menu_item_new_with_mnemonic (label);
if (icon_name)
{
icon = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_MENU);
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), icon);
}
}
gtk_widget_set_sensitive (menuitem, sensitive);
sokoke_widget_set_visible (menuitem, visible);
g_signal_connect_swapped (menuitem, "activate",
G_CALLBACK (gtk_action_activate), action);
return menuitem;
}
/**
* sokoke_image_menu_item_new_ellipsized:
* @label: the text of the menu item
*
* Creates a new #GtkImageMenuItem containing an ellipsized label.
*
* Return value: a new #GtkImageMenuItem
**/
GtkWidget*
sokoke_image_menu_item_new_ellipsized (const gchar* label)
{
return katze_image_menu_item_new_ellipsized (label);
}
/**
* sokoke_time_t_to_julian:
* @timestamp: a time_t timestamp value
*
* Calculates a unix timestamp to a julian day value.
*
* Return value: an integer.
**/
gint64
sokoke_time_t_to_julian (const time_t* timestamp)
{
GDate* date;
gint64 julian;
date = g_date_new ();
g_date_set_time_t (date, *timestamp);
julian = (gint64)g_date_get_julian (date);
g_date_free (date);
return julian;
}
/**
* sokoke_register_stock_items:
*
* Registers several custom stock items used throughout Midori.
**/
void
sokoke_register_stock_items (void)
{
typedef struct
{
const gchar* stock_id;
const gchar* label;
GdkModifierType modifier;
guint keyval;
const gchar* fallback;
} FatStockItem;
GtkIconSource* icon_source;
GtkIconSet* icon_set;
GtkIconFactory* factory = gtk_icon_factory_new ();
gsize i;
static FatStockItem items[] =
{
{ STOCK_EXTENSION, NULL, 0, 0, GTK_STOCK_CONVERT },
{ STOCK_IMAGE, NULL, 0, 0, GTK_STOCK_ORIENTATION_PORTRAIT },
{ 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_BOOKMARK, N_("_Bookmark"), 0, 0, GTK_STOCK_FILE },
{ STOCK_BOOKMARKS, N_("_Bookmarks"), 0, 0, GTK_STOCK_DIRECTORY },
{ STOCK_BOOKMARK_ADD, N_("_Add Bookmark"), 0, 0, GTK_STOCK_ADD },
{ STOCK_CONSOLE, N_("_Console"), 0, 0, GTK_STOCK_DIALOG_WARNING },
{ STOCK_EXTENSIONS, N_("_Extensions"), 0, 0, GTK_STOCK_CONVERT },
{ STOCK_HISTORY, N_("_History"), 0, 0, GTK_STOCK_SORT_ASCENDING },
{ STOCK_HOMEPAGE, N_("_Homepage"), 0, 0, GTK_STOCK_HOME },
{ STOCK_SCRIPTS, N_("_Userscripts"), 0, 0, GTK_STOCK_EXECUTE },
{ STOCK_STYLES, N_("User_styles"), 0, 0, GTK_STOCK_SELECT_COLOR },
{ STOCK_TAB_NEW, N_("New _Tab"), 0, 0, GTK_STOCK_ADD },
{ STOCK_TRANSFERS, N_("_Transfers"), 0, 0, GTK_STOCK_SAVE },
{ STOCK_PLUGINS, N_("P_lugins"), 0, 0, GTK_STOCK_CONVERT },
{ STOCK_USER_TRASH, N_("_Closed Tabs and Windows"), 0, 0, "gtk-undo-ltr" },
{ STOCK_WINDOW_NEW, N_("New _Window"), 0, 0, GTK_STOCK_ADD },
};
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 ((GtkStockItem*)items, G_N_ELEMENTS (items));
gtk_icon_factory_add_default (factory);
g_object_unref (factory);
}
/**
* sokoke_set_config_dir:
* @new_config_dir: an absolute path, or %NULL
*
* Retrieves and/ or sets the base configuration folder.
*
* Return value: the configuration folder, or %NULL
**/
const gchar*
sokoke_set_config_dir (const gchar* new_config_dir)
{
static gchar* config_dir = NULL;
if (config_dir)
return config_dir;
if (!new_config_dir)
config_dir = g_build_filename (g_get_user_config_dir (),
PACKAGE_NAME, NULL);
else
{
g_return_val_if_fail (g_path_is_absolute (new_config_dir), NULL);
katze_assign (config_dir, g_strdup (new_config_dir));
}
return config_dir;
}
/**
* sokoke_remove_path:
* @path: an absolute path
* @ignore_errors: keep removing even if an error occurred
*
* Removes the file at @path or the folder including any
* child folders and files if @path is a folder.
*
* If @ignore_errors is %TRUE and @path is a folder with
* children, one of which can't be removed, remaining
* children will be deleted nevertheless
* If @ignore_errors is %FALSE and @path is a folder, the
* removal process will cancel immediately.
*
* Return value: %TRUE on success, %FALSE if an error occurred
**/
gboolean
sokoke_remove_path (const gchar* path,
gboolean ignore_errors)
{
GDir* dir = g_dir_open (path, 0, NULL);
const gchar* name;
if (!dir)
return g_remove (path) == 0;
while ((name = g_dir_read_name (dir)))
{
gchar* sub_path = g_build_filename (path, name, NULL);
if (!sokoke_remove_path (sub_path, ignore_errors) && !ignore_errors)
return FALSE;
g_free (sub_path);
}
g_dir_close (dir);
g_rmdir (path);
return TRUE;
}

137
midori/sokoke.h Normal file
View file

@ -0,0 +1,137 @@
/*
Copyright (C) 2007-2008 Christian Dywan <christian@twotoasts.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#ifndef __SOKOKE_H__
#define __SOKOKE_H__ 1
#include <katze/katze.h>
#include <gtk/gtk.h>
#include <JavaScriptCore/JavaScript.h>
gchar*
sokoke_js_script_eval (JSContextRef js_context,
const gchar* script,
gchar** exception);
/* Many themes need this hack for small toolbars to work */
#define GTK_ICON_SIZE_SMALL_TOOLBAR GTK_ICON_SIZE_BUTTON
gboolean
sokoke_spawn_program (const gchar* command,
const gchar* argument);
gchar*
sokoke_magic_uri (const gchar* uri,
KatzeArray* search_engines);
typedef enum {
SOKOKE_MENU_POSITION_CURSOR = 0,
SOKOKE_MENU_POSITION_LEFT,
SOKOKE_MENU_POSITION_RIGHT
} SokokeMenuPos;
void
sokoke_combo_box_add_strings (GtkComboBox* combobox,
const gchar* label_first,
...);
void
sokoke_widget_set_visible (GtkWidget* widget,
gboolean visible);
void
sokoke_container_show_children (GtkContainer* container);
void
sokoke_widget_popup (GtkWidget* widget,
GtkMenu* menu,
GdkEventButton* event,
SokokeMenuPos pos);
GtkWidget*
sokoke_xfce_header_new (const gchar* icon,
const gchar* title);
GtkWidget*
sokoke_superuser_warning_new (void);
GtkWidget*
sokoke_hig_frame_new (const gchar* title);
void
sokoke_widget_set_pango_font_style (GtkWidget* widget,
PangoStyle style);
void
sokoke_entry_set_default_text (GtkEntry* entry,
const gchar* default_text);
gchar*
sokoke_key_file_get_string_default (GKeyFile* key_file,
const gchar* group,
const gchar* key,
const gchar* default_value,
GError** error);
gint
sokoke_key_file_get_integer_default (GKeyFile* key_file,
const gchar* group,
const gchar* key,
const gint default_value,
GError** error);
gdouble
sokoke_key_file_get_double_default (GKeyFile* key_file,
const gchar* group,
const gchar* key,
gdouble default_value,
GError** error);
gboolean
sokoke_key_file_get_boolean_default (GKeyFile* key_file,
const gchar* group,
const gchar* key,
gboolean default_value,
GError** error);
gboolean
sokoke_key_file_save_to_file (GKeyFile* key_file,
const gchar* filename,
GError** error);
void
sokoke_widget_get_text_size (GtkWidget* widget,
const gchar* text,
gint* width,
gint* height);
GtkWidget*
sokoke_action_create_popup_menu_item (GtkAction* action);
GtkWidget*
sokoke_image_menu_item_new_ellipsized (const gchar* label);
gint64
sokoke_time_t_to_julian (const time_t* timestamp);
void
sokoke_register_stock_items (void);
const gchar*
sokoke_set_config_dir (const gchar* new_config_dir);
gboolean
sokoke_remove_path (const gchar* path,
gboolean ignore_errors);
#endif /* !__SOKOKE_H__ */

31
midori/wscript_build Normal file
View file

@ -0,0 +1,31 @@
#! /usr/bin/env python
# WAF build script for midori
# This file is licensed under the terms of the expat license, see the file EXPAT.
import platform
obj = bld.new_task_gen ('cc', 'staticlib')
obj.name = 'midori'
obj.target = 'midori'
obj.includes = '. ..'
obj.find_sources_in_dirs ('.', excludes=['main.c'])
obj.add_marshal_file ('marshal.list', 'midori_cclosure_marshal')
obj.uselib = 'UNIQUE LIBSOUP LIBIDN GIO GTK SQLITE WEBKIT LIBXML HILDON'
obj.uselib_local = 'katze'
obj.install_path = None
obj = bld.new_task_gen ('cc', 'staticlib')
obj.name = 'panels'
obj.target = 'panels'
obj.includes = '. ..'
obj.find_sources_in_dirs ('../panels')
obj.uselib = 'UNIQUE LIBSOUP GMODULE GTHREAD GIO GTK SQLITE WEBKIT LIBXML'
obj.uselib_local = 'midori'
obj.install_path = None
obj = bld.new_task_gen ('cc', 'program')
obj.target = 'midori'
obj.includes = '. .. ../panels'
obj.source = 'main.c'
obj.uselib = 'UNIQUE LIBSOUP GMODULE GTHREAD GIO GTK SQLITE WEBKIT LIBXML'
obj.uselib_local = 'panels'

1081
panels/midori-addons.c Normal file

File diff suppressed because it is too large Load diff

67
panels/midori-addons.h Normal file
View file

@ -0,0 +1,67 @@
/*
Copyright (C) 2008 Christian Dywan <christian@twotoasts.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#ifndef __MIDORI_ADDONS_H__
#define __MIDORI_ADDONS_H__
#include <gtk/gtk.h>
#include <katze/katze.h>
#include "midori-viewable.h"
G_BEGIN_DECLS
#define MIDORI_TYPE_ADDONS \
(midori_addons_get_type ())
#define MIDORI_ADDONS(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), MIDORI_TYPE_ADDONS, MidoriAddons))
#define MIDORI_ADDONS_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), MIDORI_TYPE_ADDONS, MidoriAddonsClass))
#define MIDORI_IS_ADDONS(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), MIDORI_TYPE_ADDONS))
#define MIDORI_IS_ADDONS_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), MIDORI_TYPE_ADDONS))
#define MIDORI_ADDONS_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), MIDORI_TYPE_ADDONS, MidoriAddonsClass))
typedef struct _MidoriAddons MidoriAddons;
typedef struct _MidoriAddonsClass MidoriAddonsClass;
typedef enum
{
MIDORI_ADDON_NONE,
MIDORI_ADDON_USER_SCRIPTS,
MIDORI_ADDON_USER_STYLES
} MidoriAddonKind;
GType
midori_addon_kind_get_type (void) G_GNUC_CONST;
#define MIDORI_TYPE_ADDON_KIND \
(midori_addon_kind_get_type ())
GType
midori_addons_get_type (void);
GtkWidget*
midori_addons_new (MidoriAddonKind kind,
GtkWidget* web_widget);
GtkWidget*
midori_addons_get_toolbar (MidoriViewable* addons);
void
midori_addons_update_elements (MidoriAddons* addons);
G_END_DECLS
#endif /* __MIDORI_ADDONS_H__ */

959
panels/midori-bookmarks.c Normal file
View file

@ -0,0 +1,959 @@
/*
Copyright (C) 2008-2009 Christian Dywan <christian@twotoasts.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#include "midori-bookmarks.h"
#include "midori-app.h"
#include "midori-browser.h"
#include "midori-stock.h"
#include "midori-view.h"
#include "midori-viewable.h"
#include "sokoke.h"
#include <glib/gi18n.h>
#include <string.h>
#include <katze/katze.h>
#include <gdk/gdkkeysyms.h>
void
midori_browser_edit_bookmark_dialog_new (MidoriBrowser* browser,
KatzeItem* bookmark,
gboolean new_bookmark,
gboolean is_folder);
struct _MidoriBookmarks
{
GtkVBox parent_instance;
GtkWidget* toolbar;
GtkWidget* edit;
GtkWidget* delete;
GtkWidget* treeview;
MidoriApp* app;
KatzeArray* array;
KatzeNet* net;
};
struct _MidoriBookmarksClass
{
GtkVBoxClass parent_class;
};
static void
midori_bookmarks_viewable_iface_init (MidoriViewableIface* iface);
G_DEFINE_TYPE_WITH_CODE (MidoriBookmarks, midori_bookmarks, GTK_TYPE_VBOX,
G_IMPLEMENT_INTERFACE (MIDORI_TYPE_VIEWABLE,
midori_bookmarks_viewable_iface_init));
enum
{
PROP_0,
PROP_APP
};
static void
midori_bookmarks_finalize (GObject* object);
static void
midori_bookmarks_set_property (GObject* object,
guint prop_id,
const GValue* value,
GParamSpec* pspec);
static void
midori_bookmarks_get_property (GObject* object,
guint prop_id,
GValue* value,
GParamSpec* pspec);
static void
midori_bookmarks_class_init (MidoriBookmarksClass* class)
{
GObjectClass* gobject_class;
GParamFlags flags;
gobject_class = G_OBJECT_CLASS (class);
gobject_class->finalize = midori_bookmarks_finalize;
gobject_class->set_property = midori_bookmarks_set_property;
gobject_class->get_property = midori_bookmarks_get_property;
flags = G_PARAM_READWRITE | G_PARAM_CONSTRUCT;
g_object_class_install_property (gobject_class,
PROP_APP,
g_param_spec_object (
"app",
"App",
"The app",
MIDORI_TYPE_APP,
flags));
}
static const gchar*
midori_bookmarks_get_label (MidoriViewable* viewable)
{
return _("Bookmarks");
}
static const gchar*
midori_bookmarks_get_stock_id (MidoriViewable* viewable)
{
return STOCK_BOOKMARKS;
}
static void
midori_bookmarks_add_clicked_cb (GtkWidget* toolitem)
{
GtkWidget* browser = gtk_widget_get_toplevel (toolitem);
/* FIXME: Take selected folder into account */
midori_browser_edit_bookmark_dialog_new (MIDORI_BROWSER (browser),
NULL, TRUE, FALSE);
}
static void
midori_bookmarks_edit_clicked_cb (GtkWidget* toolitem,
MidoriBookmarks* bookmarks)
{
GtkTreeModel* model;
GtkTreeIter iter;
if (katze_tree_view_get_selected_iter (GTK_TREE_VIEW (bookmarks->treeview),
&model, &iter))
{
KatzeItem* item;
gboolean is_separator;
gtk_tree_model_get (model, &iter, 0, &item, -1);
is_separator = !KATZE_IS_ARRAY (item) && !katze_item_get_uri (item);
if (!is_separator)
{
GtkWidget* browser = gtk_widget_get_toplevel (toolitem);
midori_browser_edit_bookmark_dialog_new (MIDORI_BROWSER (browser),
item, FALSE, FALSE);
}
g_object_unref (item);
}
}
static void
midori_bookmarks_delete_clicked_cb (GtkWidget* toolitem,
MidoriBookmarks* bookmarks)
{
GtkTreeModel* model;
GtkTreeIter iter;
if (katze_tree_view_get_selected_iter (GTK_TREE_VIEW (bookmarks->treeview),
&model, &iter))
{
KatzeItem* item;
KatzeArray* parent;
gtk_tree_model_get (model, &iter, 0, &item, -1);
/* FIXME: Even toplevel items should technically have a parent */
g_return_if_fail (katze_item_get_parent (item));
parent = katze_item_get_parent (item);
katze_array_remove_item (parent, item);
g_object_unref (item);
}
}
static void
midori_bookmarks_folder_clicked_cb (GtkWidget* toolitem)
{
GtkWidget* browser = gtk_widget_get_toplevel (toolitem);
/* FIXME: Take selected folder into account */
midori_browser_edit_bookmark_dialog_new (MIDORI_BROWSER (browser),
NULL, TRUE, TRUE);
}
static void
midori_bookmarks_cursor_or_row_changed_cb (GtkTreeView* treeview,
MidoriBookmarks* bookmarks)
{
GtkTreeModel* model;
GtkTreeIter iter;
KatzeItem* item;
if (!bookmarks->edit)
return;
if (katze_tree_view_get_selected_iter (treeview, &model, &iter))
{
gboolean is_separator;
gtk_tree_model_get (model, &iter, 0, &item, -1);
is_separator = !KATZE_IS_ARRAY (item) && !katze_item_get_uri (item);
gtk_widget_set_sensitive (bookmarks->edit, !is_separator);
gtk_widget_set_sensitive (bookmarks->delete, TRUE);
g_object_unref (item);
}
else
{
gtk_widget_set_sensitive (bookmarks->edit, FALSE);
gtk_widget_set_sensitive (bookmarks->delete, FALSE);
}
}
static GtkWidget*
midori_bookmarks_get_toolbar (MidoriViewable* viewable)
{
MidoriBookmarks* bookmarks = MIDORI_BOOKMARKS (viewable);
if (!bookmarks->toolbar)
{
GtkWidget* toolbar;
GtkToolItem* toolitem;
toolbar = gtk_toolbar_new ();
gtk_toolbar_set_style (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_BOTH_HORIZ);
gtk_toolbar_set_icon_size (GTK_TOOLBAR (toolbar), GTK_ICON_SIZE_BUTTON);
bookmarks->toolbar = toolbar;
toolitem = gtk_tool_button_new_from_stock (GTK_STOCK_ADD);
gtk_widget_set_tooltip_text (GTK_WIDGET (toolitem),
_("Add a new bookmark"));
gtk_tool_item_set_is_important (toolitem, TRUE);
g_signal_connect (toolitem, "clicked",
G_CALLBACK (midori_bookmarks_add_clicked_cb), bookmarks);
gtk_toolbar_insert (GTK_TOOLBAR (toolbar), toolitem, -1);
gtk_widget_show (GTK_WIDGET (toolitem));
toolitem = gtk_tool_button_new_from_stock (GTK_STOCK_EDIT);
gtk_widget_set_tooltip_text (GTK_WIDGET (toolitem),
_("Edit the selected bookmark"));
g_signal_connect (toolitem, "clicked",
G_CALLBACK (midori_bookmarks_edit_clicked_cb), bookmarks);
gtk_toolbar_insert (GTK_TOOLBAR (toolbar), toolitem, -1);
gtk_widget_show (GTK_WIDGET (toolitem));
bookmarks->edit = GTK_WIDGET (toolitem);
toolitem = gtk_tool_button_new_from_stock (GTK_STOCK_DELETE);
gtk_widget_set_tooltip_text (GTK_WIDGET (toolitem),
_("Delete the selected bookmark"));
g_signal_connect (toolitem, "clicked",
G_CALLBACK (midori_bookmarks_delete_clicked_cb), bookmarks);
gtk_toolbar_insert (GTK_TOOLBAR (toolbar), toolitem, -1);
gtk_widget_show (GTK_WIDGET (toolitem));
bookmarks->delete = GTK_WIDGET (toolitem);
toolitem = gtk_separator_tool_item_new ();
gtk_separator_tool_item_set_draw (GTK_SEPARATOR_TOOL_ITEM (toolitem), FALSE);
gtk_tool_item_set_expand (toolitem, TRUE);
gtk_toolbar_insert (GTK_TOOLBAR (toolbar), toolitem, -1);
gtk_widget_show (GTK_WIDGET (toolitem));
toolitem = gtk_tool_button_new_from_stock (GTK_STOCK_DIRECTORY);
gtk_widget_set_tooltip_text (GTK_WIDGET (toolitem),
_("Add a new folder"));
g_signal_connect (toolitem, "clicked",
G_CALLBACK (midori_bookmarks_folder_clicked_cb), bookmarks);
gtk_toolbar_insert (GTK_TOOLBAR (toolbar), toolitem, -1);
gtk_widget_show (GTK_WIDGET (toolitem));
midori_bookmarks_cursor_or_row_changed_cb (
GTK_TREE_VIEW (bookmarks->treeview), bookmarks);
g_signal_connect (bookmarks->edit, "destroy",
G_CALLBACK (gtk_widget_destroyed), &bookmarks->edit);
g_signal_connect (bookmarks->delete, "destroy",
G_CALLBACK (gtk_widget_destroyed), &bookmarks->delete);
}
return bookmarks->toolbar;
}
static void
midori_bookmarks_viewable_iface_init (MidoriViewableIface* iface)
{
iface->get_stock_id = midori_bookmarks_get_stock_id;
iface->get_label = midori_bookmarks_get_label;
iface->get_toolbar = midori_bookmarks_get_toolbar;
}
static void
midori_bookmarks_add_item_cb (KatzeArray* array,
KatzeItem* added_item,
MidoriBookmarks* bookmarks);
static void
midori_bookmarks_remove_item_cb (KatzeArray* array,
KatzeItem* removed_item,
MidoriBookmarks* bookmarks);
static void
midori_bookmarks_clear_cb (KatzeArray* array,
MidoriBookmarks* bookmarks);
static void
midori_bookmarks_disconnect_folder (MidoriBookmarks* bookmarks,
KatzeArray* array)
{
KatzeItem* item;
guint i;
g_return_if_fail (KATZE_IS_ARRAY (array));
g_signal_handlers_disconnect_by_func (array,
midori_bookmarks_add_item_cb, bookmarks);
g_signal_handlers_disconnect_by_func (array,
midori_bookmarks_remove_item_cb, bookmarks);
g_signal_handlers_disconnect_by_func (array,
midori_bookmarks_clear_cb, bookmarks);
i = 0;
while ((item = katze_array_get_nth_item (array, i++)))
{
if (KATZE_IS_ARRAY (item))
midori_bookmarks_disconnect_folder (bookmarks, KATZE_ARRAY (item));
g_object_unref (item);
}
}
static void
midori_bookmarks_add_item_cb (KatzeArray* array,
KatzeItem* added_item,
MidoriBookmarks* bookmarks)
{
GtkTreeModel* model;
GtkTreeIter iter;
guint i;
g_return_if_fail (KATZE_IS_ARRAY (array));
g_return_if_fail (KATZE_IS_ITEM (added_item));
if (KATZE_IS_ARRAY (added_item))
{
g_signal_connect (added_item, "add-item",
G_CALLBACK (midori_bookmarks_add_item_cb), bookmarks);
g_signal_connect (added_item, "remove-item",
G_CALLBACK (midori_bookmarks_remove_item_cb), bookmarks);
g_signal_connect (added_item, "clear",
G_CALLBACK (midori_bookmarks_clear_cb), bookmarks);
}
g_object_ref (added_item);
model = gtk_tree_view_get_model (GTK_TREE_VIEW (bookmarks->treeview));
if (array == bookmarks->array)
{
gtk_tree_store_insert_with_values (GTK_TREE_STORE (model),
&iter, NULL, G_MAXINT, 0, added_item, -1);
return;
}
i = 0;
/* FIXME: Recurse over children of folders, too */
while (gtk_tree_model_iter_nth_child (model, &iter, NULL, i))
{
KatzeItem* item;
gtk_tree_model_get (model, &iter, 0, &item, -1);
if (item == (KatzeItem*)array)
{
GtkTreeIter child_iter;
gtk_tree_store_insert_with_values (GTK_TREE_STORE (model),
&child_iter, &iter, G_MAXINT, 0, added_item, -1);
break;
}
g_object_unref (item);
i++;
}
}
static void
midori_bookmarks_remove_iter (GtkTreeModel* model,
GtkTreeIter* parent,
KatzeItem* removed_item)
{
guint i;
GtkTreeIter iter;
i = 0;
while (gtk_tree_model_iter_nth_child (model, &iter, parent, i))
{
KatzeItem* item;
gtk_tree_model_get (model, &iter, 0, &item, -1);
if (item == removed_item)
{
gtk_tree_store_remove (GTK_TREE_STORE (model), &iter);
g_object_unref (item);
break;
}
if (KATZE_IS_ARRAY (item))
midori_bookmarks_remove_iter (model, &iter, removed_item);
g_object_unref (item);
i++;
}
}
static void
midori_bookmarks_remove_item_cb (KatzeArray* array,
KatzeItem* removed_item,
MidoriBookmarks* bookmarks)
{
GtkTreeModel* model;
g_return_if_fail (KATZE_IS_ARRAY (array));
g_return_if_fail (KATZE_IS_ITEM (removed_item));
if (KATZE_IS_ARRAY (removed_item))
midori_bookmarks_disconnect_folder (bookmarks, KATZE_ARRAY (removed_item));
model = gtk_tree_view_get_model (GTK_TREE_VIEW (bookmarks->treeview));
midori_bookmarks_remove_iter (model, NULL, removed_item);
g_object_unref (removed_item);
}
static void
midori_bookmarks_clear_cb (KatzeArray* array,
MidoriBookmarks* bookmarks)
{
GtkTreeView* treeview;
GtkTreeStore* store;
g_return_if_fail (KATZE_IS_ARRAY (array));
if (array == bookmarks->array)
{
treeview = GTK_TREE_VIEW (bookmarks->treeview);
store = GTK_TREE_STORE (gtk_tree_view_get_model (treeview));
gtk_tree_store_clear (store);
}
else
{
KatzeItem* item;
guint i;
i = 0;
while ((item = katze_array_get_nth_item (array, i++)))
midori_bookmarks_remove_item_cb (array, item, bookmarks);
}
}
static void
midori_bookmarks_insert_folder (MidoriBookmarks* bookmarks,
GtkTreeStore* treestore,
GtkTreeIter* parent,
KatzeArray* array)
{
KatzeItem* item;
guint i;
GtkTreeIter iter;
g_return_if_fail (KATZE_IS_ARRAY (array));
g_signal_connect (array, "add-item",
G_CALLBACK (midori_bookmarks_add_item_cb), bookmarks);
g_signal_connect (array, "remove-item",
G_CALLBACK (midori_bookmarks_remove_item_cb), bookmarks);
g_signal_connect (array, "clear",
G_CALLBACK (midori_bookmarks_clear_cb), bookmarks);
i = 0;
while ((item = katze_array_get_nth_item (array, i++)))
{
g_object_ref (item);
gtk_tree_store_insert_with_values (treestore, &iter, parent, i,
0, item, -1);
if (KATZE_IS_ARRAY (item))
midori_bookmarks_insert_folder (bookmarks, treestore,
&iter, KATZE_ARRAY (item));
}
}
static void
midori_bookmarks_set_app (MidoriBookmarks* bookmarks,
MidoriApp* app)
{
GtkTreeModel* model;
if (bookmarks->array)
{
midori_bookmarks_disconnect_folder (bookmarks, bookmarks->array);
g_object_unref (bookmarks->array);
model = gtk_tree_view_get_model (GTK_TREE_VIEW (bookmarks->treeview));
gtk_tree_store_clear (GTK_TREE_STORE (model));
}
katze_assign (bookmarks->app, app);
if (!app)
return;
g_object_ref (app);
bookmarks->array = katze_object_get_object (app, "bookmarks");
if (bookmarks->array)
{
/* FIXME: Dereference the app on finalization */
model = gtk_tree_view_get_model (GTK_TREE_VIEW (bookmarks->treeview));
midori_bookmarks_insert_folder (bookmarks, GTK_TREE_STORE (model),
NULL, g_object_ref (bookmarks->array));
}
}
static void
midori_bookmarks_set_property (GObject* object,
guint prop_id,
const GValue* value,
GParamSpec* pspec)
{
MidoriBookmarks* bookmarks = MIDORI_BOOKMARKS (object);
switch (prop_id)
{
case PROP_APP:
midori_bookmarks_set_app (bookmarks, g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
midori_bookmarks_get_property (GObject* object,
guint prop_id,
GValue* value,
GParamSpec* pspec)
{
MidoriBookmarks* bookmarks = MIDORI_BOOKMARKS (object);
switch (prop_id)
{
case PROP_APP:
g_value_set_object (value, bookmarks->app);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
midori_bookmarks_treeview_render_icon_cb (GtkTreeViewColumn* column,
GtkCellRenderer* renderer,
GtkTreeModel* model,
GtkTreeIter* iter,
GtkWidget* treeview)
{
KatzeItem* item;
GdkPixbuf* pixbuf;
gtk_tree_model_get (model, iter, 0, &item, -1);
/* TODO: Would it be better to not do this on every redraw? */
pixbuf = NULL;
if (KATZE_IS_ARRAY (item))
pixbuf = gtk_widget_render_icon (treeview, GTK_STOCK_DIRECTORY,
GTK_ICON_SIZE_MENU, NULL);
else if (katze_item_get_uri (item))
pixbuf = katze_net_load_icon (
MIDORI_BOOKMARKS (gtk_widget_get_parent (treeview))->net,
katze_item_get_uri (item), NULL, treeview, NULL);
g_object_set (renderer, "pixbuf", pixbuf, NULL);
if (pixbuf)
g_object_unref (pixbuf);
g_object_unref (item);
}
static void
midori_bookmarks_treeview_render_text_cb (GtkTreeViewColumn* column,
GtkCellRenderer* renderer,
GtkTreeModel* model,
GtkTreeIter* iter,
GtkWidget* treeview)
{
KatzeItem* item;
gtk_tree_model_get (model, iter, 0, &item, -1);
if (KATZE_IS_ARRAY (item) || katze_item_get_uri (item))
g_object_set (renderer, "markup", NULL,
"text", katze_item_get_name (item), NULL);
else
g_object_set (renderer, "markup", _("<i>Separator</i>"), NULL);
g_object_unref (item);
}
static void
midori_bookmarks_row_activated_cb (GtkTreeView* treeview,
GtkTreePath* path,
GtkTreeViewColumn* column,
MidoriBookmarks* bookmarks)
{
GtkTreeModel* model;
GtkTreeIter iter;
KatzeItem* item;
const gchar* uri;
model = gtk_tree_view_get_model (treeview);
if (gtk_tree_model_get_iter (model, &iter, path))
{
gtk_tree_model_get (model, &iter, 0, &item, -1);
uri = katze_item_get_uri (item);
if (uri && *uri)
{
GtkWidget* browser;
browser = gtk_widget_get_toplevel (GTK_WIDGET (bookmarks));
midori_browser_set_current_uri (MIDORI_BROWSER (browser), uri);
}
g_object_unref (item);
}
}
static void
midori_bookmarks_popup_item (GtkWidget* menu,
const gchar* stock_id,
const gchar* label,
KatzeItem* item,
gpointer callback,
MidoriBookmarks* bookmarks)
{
const gchar* uri;
GtkWidget* menuitem;
uri = katze_item_get_uri (item);
menuitem = gtk_image_menu_item_new_from_stock (stock_id, NULL);
if (label)
gtk_label_set_text_with_mnemonic (GTK_LABEL (gtk_bin_get_child (
GTK_BIN (menuitem))), label);
if (!strcmp (stock_id, GTK_STOCK_EDIT))
gtk_widget_set_sensitive (menuitem,
KATZE_IS_ARRAY (item) || uri != NULL);
else if (!KATZE_IS_ARRAY (item) && strcmp (stock_id, GTK_STOCK_DELETE))
gtk_widget_set_sensitive (menuitem, uri != NULL);
g_object_set_data (G_OBJECT (menuitem), "KatzeItem", item);
g_signal_connect (menuitem, "activate", G_CALLBACK (callback), bookmarks);
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
gtk_widget_show (menuitem);
}
static void
midori_bookmarks_open_activate_cb (GtkWidget* menuitem,
MidoriBookmarks* bookmarks)
{
KatzeItem* item;
const gchar* uri;
item = (KatzeItem*)g_object_get_data (G_OBJECT (menuitem), "KatzeItem");
uri = katze_item_get_uri (item);
if (uri && *uri)
{
GtkWidget* browser = gtk_widget_get_toplevel (GTK_WIDGET (bookmarks));
midori_browser_set_current_uri (MIDORI_BROWSER (browser), uri);
}
}
static void
midori_bookmarks_open_in_tab_activate_cb (GtkWidget* menuitem,
MidoriBookmarks* bookmarks)
{
KatzeItem* item;
const gchar* uri;
guint n;
item = (KatzeItem*)g_object_get_data (G_OBJECT (menuitem), "KatzeItem");
if (KATZE_IS_ARRAY (item))
{
KatzeItem* child;
guint i = 0;
while ((child = katze_array_get_nth_item (KATZE_ARRAY (item), i)))
{
if ((uri = katze_item_get_uri (child)) && *uri)
{
GtkWidget* browser;
MidoriWebSettings* settings;
browser = gtk_widget_get_toplevel (GTK_WIDGET (bookmarks));
n = midori_browser_add_item (MIDORI_BROWSER (browser), child);
settings = katze_object_get_object (browser, "settings");
if (!katze_object_get_boolean (settings, "open-tabs-in-the-background"))
midori_browser_set_current_page (MIDORI_BROWSER (browser), n);
g_object_unref (settings);
}
i++;
}
}
else
{
if ((uri = katze_item_get_uri (item)) && *uri)
{
GtkWidget* browser;
MidoriWebSettings* settings;
browser = gtk_widget_get_toplevel (GTK_WIDGET (bookmarks));
n = midori_browser_add_item (MIDORI_BROWSER (browser), item);
settings = katze_object_get_object (browser, "settings");
if (!katze_object_get_boolean (settings, "open-tabs-in-the-background"))
midori_browser_set_current_page (MIDORI_BROWSER (browser), n);
g_object_unref (settings);
}
}
}
static void
midori_bookmarks_open_in_window_activate_cb (GtkWidget* menuitem,
MidoriBookmarks* bookmarks)
{
KatzeItem* item;
const gchar* uri;
item = (KatzeItem*)g_object_get_data (G_OBJECT (menuitem), "KatzeItem");
uri = katze_item_get_uri (item);
if (uri && *uri)
{
GtkWidget* browser = gtk_widget_get_toplevel (GTK_WIDGET (bookmarks));
g_signal_emit_by_name (browser, "new-window", uri);
}
}
static void
midori_bookmarks_edit_activate_cb (GtkWidget* menuitem,
MidoriBookmarks* bookmarks)
{
KatzeItem* item;
gboolean is_separator;
item = (KatzeItem*)g_object_get_data (G_OBJECT (menuitem), "KatzeItem");
is_separator = !KATZE_IS_ARRAY (item) && !katze_item_get_uri (item);
if (!is_separator)
{
GtkWidget* browser = gtk_widget_get_toplevel (GTK_WIDGET (bookmarks));
midori_browser_edit_bookmark_dialog_new (MIDORI_BROWSER (browser), item, FALSE, FALSE);
}
}
static void
midori_bookmarks_delete_activate_cb (GtkWidget* menuitem,
MidoriBookmarks* bookmarks)
{
KatzeItem* item;
KatzeArray* parent;
item = (KatzeItem*)g_object_get_data (G_OBJECT (menuitem), "KatzeItem");
/* FIXME: Even toplevel items should technically have a parent */
g_return_if_fail (katze_item_get_parent (item));
parent = katze_item_get_parent (item);
katze_array_remove_item (parent, item);
}
static void
midori_bookmarks_popup (GtkWidget* widget,
GdkEventButton* event,
KatzeItem* item,
MidoriBookmarks* bookmarks)
{
GtkWidget* menu;
GtkWidget* menuitem;
menu = gtk_menu_new ();
if (KATZE_IS_ARRAY (item))
midori_bookmarks_popup_item (menu,
STOCK_TAB_NEW, _("Open all in _Tabs"),
item, midori_bookmarks_open_in_tab_activate_cb, bookmarks);
else
{
midori_bookmarks_popup_item (menu, GTK_STOCK_OPEN, NULL,
item, midori_bookmarks_open_activate_cb, bookmarks);
midori_bookmarks_popup_item (menu, STOCK_TAB_NEW, _("Open in New _Tab"),
item, midori_bookmarks_open_in_tab_activate_cb, bookmarks);
midori_bookmarks_popup_item (menu, STOCK_WINDOW_NEW, _("Open in New _Window"),
item, midori_bookmarks_open_in_window_activate_cb, bookmarks);
}
menuitem = gtk_separator_menu_item_new ();
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
gtk_widget_show (menuitem);
midori_bookmarks_popup_item (menu, GTK_STOCK_EDIT, NULL,
item, midori_bookmarks_edit_activate_cb, bookmarks);
midori_bookmarks_popup_item (menu, GTK_STOCK_DELETE, NULL,
item, midori_bookmarks_delete_activate_cb, bookmarks);
sokoke_widget_popup (widget, GTK_MENU (menu),
event, SOKOKE_MENU_POSITION_CURSOR);
}
static gboolean
midori_bookmarks_button_release_event_cb (GtkWidget* widget,
GdkEventButton* event,
MidoriBookmarks* bookmarks)
{
GtkTreeModel* model;
GtkTreeIter iter;
if (event->button != 2 && event->button != 3)
return FALSE;
if (katze_tree_view_get_selected_iter (GTK_TREE_VIEW (widget), &model, &iter))
{
KatzeItem* item;
gtk_tree_model_get (model, &iter, 0, &item, -1);
if (event->button == 2)
{
const gchar* uri = katze_item_get_uri (item);
if (uri && *uri)
{
GtkWidget* browser;
gint n;
browser = gtk_widget_get_toplevel (widget);
n = midori_browser_add_uri (MIDORI_BROWSER (browser), uri);
midori_browser_set_current_page (MIDORI_BROWSER (browser), n);
}
}
else
midori_bookmarks_popup (widget, event, item, bookmarks);
g_object_unref (item);
return TRUE;
}
return FALSE;
}
static gboolean
midori_bookmarks_key_release_event_cb (GtkWidget* widget,
GdkEventKey* event,
MidoriBookmarks* bookmarks)
{
GtkTreeModel* model;
GtkTreeIter iter;
if (event->keyval != GDK_Delete)
return FALSE;
if (katze_tree_view_get_selected_iter (GTK_TREE_VIEW (widget), &model, &iter))
{
KatzeItem* item;
KatzeArray* parent;
gtk_tree_model_get (model, &iter, 0, &item, -1);
parent = katze_item_get_parent (item);
katze_array_remove_item (parent, item);
g_object_unref (item);
}
return FALSE;
}
static void
midori_bookmarks_popup_menu_cb (GtkWidget* widget,
MidoriBookmarks* bookmarks)
{
GtkTreeModel* model;
GtkTreeIter iter;
KatzeItem* item;
if (katze_tree_view_get_selected_iter (GTK_TREE_VIEW (widget), &model, &iter))
{
gtk_tree_model_get (model, &iter, 0, &item, -1);
midori_bookmarks_popup (widget, NULL, item, bookmarks);
g_object_unref (item);
}
}
static void
midori_bookmarks_init (MidoriBookmarks* bookmarks)
{
GtkTreeStore* model;
GtkWidget* treeview;
GtkTreeViewColumn* column;
GtkCellRenderer* renderer_pixbuf;
GtkCellRenderer* renderer_text;
bookmarks->net = katze_net_new ();
/* Create the treeview */
model = gtk_tree_store_new (1, KATZE_TYPE_ITEM);
treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
column = gtk_tree_view_column_new ();
renderer_pixbuf = gtk_cell_renderer_pixbuf_new ();
gtk_tree_view_column_pack_start (column, renderer_pixbuf, FALSE);
gtk_tree_view_column_set_cell_data_func (column, renderer_pixbuf,
(GtkTreeCellDataFunc)midori_bookmarks_treeview_render_icon_cb,
treeview, NULL);
renderer_text = gtk_cell_renderer_text_new ();
gtk_tree_view_column_pack_start (column, renderer_text, FALSE);
gtk_tree_view_column_set_cell_data_func (column, renderer_text,
(GtkTreeCellDataFunc)midori_bookmarks_treeview_render_text_cb,
treeview, NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
g_object_unref (model);
g_object_connect (treeview,
"signal::row-activated",
midori_bookmarks_row_activated_cb, bookmarks,
"signal::cursor-changed",
midori_bookmarks_cursor_or_row_changed_cb, bookmarks,
"signal::columns-changed",
midori_bookmarks_cursor_or_row_changed_cb, bookmarks,
"signal::button-release-event",
midori_bookmarks_button_release_event_cb, bookmarks,
"signal::key-release-event",
midori_bookmarks_key_release_event_cb, bookmarks,
"signal::popup-menu",
midori_bookmarks_popup_menu_cb, bookmarks,
NULL);
gtk_widget_show (treeview);
gtk_box_pack_start (GTK_BOX (bookmarks), treeview, TRUE, TRUE, 0);
bookmarks->treeview = treeview;
}
static void
midori_bookmarks_finalize (GObject* object)
{
MidoriBookmarks* bookmarks = MIDORI_BOOKMARKS (object);
if (bookmarks->app)
g_object_unref (bookmarks->app);
g_object_unref (bookmarks->net);
}
/**
* midori_bookmarks_new:
*
* Creates a new empty bookmarks.
*
* Return value: a new #MidoriBookmarks
*
* Since: 0.1.3
**/
GtkWidget*
midori_bookmarks_new (void)
{
MidoriBookmarks* bookmarks = g_object_new (MIDORI_TYPE_BOOKMARKS, NULL);
return GTK_WIDGET (bookmarks);
}

43
panels/midori-bookmarks.h Normal file
View file

@ -0,0 +1,43 @@
/*
Copyright (C) 2009 Christian Dywan <christian@twotoasts.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#ifndef __MIDORI_BOOKMARKS_H__
#define __MIDORI_BOOKMARKS_H__
#include <gtk/gtk.h>
G_BEGIN_DECLS
#define MIDORI_TYPE_BOOKMARKS \
(midori_bookmarks_get_type ())
#define MIDORI_BOOKMARKS(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), MIDORI_TYPE_BOOKMARKS, MidoriBookmarks))
#define MIDORI_BOOKMARKS_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), MIDORI_TYPE_BOOKMARKS, MidoriBookmarksClass))
#define MIDORI_IS_BOOKMARKS(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), MIDORI_TYPE_BOOKMARKS))
#define MIDORI_IS_BOOKMARKS_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), MIDORI_TYPE_BOOKMARKS))
#define MIDORI_BOOKMARKS_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), MIDORI_TYPE_BOOKMARKS, MidoriBookmarksClass))
typedef struct _MidoriBookmarks MidoriBookmarks;
typedef struct _MidoriBookmarksClass MidoriBookmarksClass;
GType
midori_bookmarks_get_type (void);
GtkWidget*
midori_bookmarks_new (void);
G_END_DECLS
#endif /* __MIDORI_BOOKMARKS_H__ */

362
panels/midori-console.c Normal file
View file

@ -0,0 +1,362 @@
/*
Copyright (C) 2008-2009 Christian Dywan <christian@twotoasts.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#include "midori-console.h"
#include "midori-app.h"
#include "midori-browser.h"
#include "midori-stock.h"
#include "midori-view.h"
#include "sokoke.h"
#include <glib/gi18n.h>
struct _MidoriConsole
{
GtkVBox parent_instance;
GtkWidget* toolbar;
GtkWidget* treeview;
MidoriApp* app;
};
struct _MidoriConsoleClass
{
GtkVBoxClass parent_class;
};
static void
midori_console_viewable_iface_init (MidoriViewableIface* iface);
G_DEFINE_TYPE_WITH_CODE (MidoriConsole, midori_console, GTK_TYPE_VBOX,
G_IMPLEMENT_INTERFACE (MIDORI_TYPE_VIEWABLE,
midori_console_viewable_iface_init));
enum
{
PROP_0,
PROP_APP
};
static void
midori_console_set_property (GObject* object,
guint prop_id,
const GValue* value,
GParamSpec* pspec);
static void
midori_console_get_property (GObject* object,
guint prop_id,
GValue* value,
GParamSpec* pspec);
static void
midori_console_class_init (MidoriConsoleClass* class)
{
GObjectClass* gobject_class;
GParamFlags flags;
gobject_class = G_OBJECT_CLASS (class);
gobject_class->set_property = midori_console_set_property;
gobject_class->get_property = midori_console_get_property;
flags = G_PARAM_READWRITE | G_PARAM_CONSTRUCT;
g_object_class_install_property (gobject_class,
PROP_APP,
g_param_spec_object (
"app",
"App",
"The app",
MIDORI_TYPE_APP,
flags));
}
static const gchar*
midori_console_get_label (MidoriViewable* viewable)
{
return _("Console");
}
static const gchar*
midori_console_get_stock_id (MidoriViewable* viewable)
{
return STOCK_CONSOLE;
}
static void
midori_console_viewable_iface_init (MidoriViewableIface* iface)
{
iface->get_stock_id = midori_console_get_stock_id;
iface->get_label = midori_console_get_label;
iface->get_toolbar = midori_console_get_toolbar;
}
static void
midori_view_console_message_cb (GtkWidget* view,
const gchar* message,
gint line,
const gchar* source_id,
MidoriConsole* console)
{
midori_console_add (console, message, line, source_id);
}
static void
midori_console_browser_add_tab_cb (MidoriBrowser* browser,
MidoriView* view,
MidoriConsole* console)
{
g_signal_connect (view, "console-message",
G_CALLBACK (midori_view_console_message_cb), console);
}
static void
midori_console_set_property (GObject* object,
guint prop_id,
const GValue* value,
GParamSpec* pspec)
{
MidoriConsole* console = MIDORI_CONSOLE (object);
switch (prop_id)
{
case PROP_APP:
console->app = g_value_get_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
midori_console_get_property (GObject* object,
guint prop_id,
GValue* value,
GParamSpec* pspec)
{
MidoriConsole* console = MIDORI_CONSOLE (object);
switch (prop_id)
{
case PROP_APP:
g_value_set_object (value, console->app);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
midori_console_button_copy_clicked_cb (GtkToolItem* toolitem,
MidoriConsole* console)
{
GtkTreeModel* model;
GtkTreeIter iter;
if (katze_tree_view_get_selected_iter (GTK_TREE_VIEW (console->treeview),
&model, &iter))
{
GdkDisplay* display;
GtkClipboard* clipboard;
gchar* text;
gchar* message;
gint line;
gchar* source_id;
display = gtk_widget_get_display (GTK_WIDGET (console));
clipboard = gtk_clipboard_get_for_display (display, GDK_SELECTION_CLIPBOARD);
gtk_tree_model_get (model, &iter, 0, &message, 1, &line, 2, &source_id, -1);
text = g_strdup_printf ("%d @ %s: %s", line, source_id, message);
g_free (source_id);
g_free (message);
gtk_clipboard_set_text (clipboard, text, -1);
g_free (text);
}
}
static void
midori_console_button_clear_clicked_cb (GtkToolItem* toolitem,
MidoriConsole* console)
{
GtkTreeModel* model = gtk_tree_view_get_model (
GTK_TREE_VIEW (console->treeview));
gtk_tree_store_clear (GTK_TREE_STORE (model));
}
static void
midori_console_treeview_render_icon_cb (GtkTreeViewColumn* column,
GtkCellRenderer* renderer,
GtkTreeModel* model,
GtkTreeIter* iter,
GtkWidget* treeview)
{
g_object_set (renderer, "stock-id", GTK_STOCK_DIALOG_WARNING, NULL);
}
static void
midori_console_treeview_render_text_cb (GtkTreeViewColumn* column,
GtkCellRenderer* renderer,
GtkTreeModel* model,
GtkTreeIter* iter,
GtkWidget* treeview)
{
gchar* message;
gint line;
gchar* source_id;
gchar* text;
gtk_tree_model_get (model, iter, 0, &message, 1, &line, 2, &source_id, -1);
text = g_strdup_printf ("%d @ %s\n%s", line, source_id, message);
g_object_set (renderer, "text", text, NULL);
g_free (text);
g_free (message);
g_free (source_id);
}
static void
midori_console_hierarchy_changed_cb (MidoriConsole* console,
GtkWidget* old_parent)
{
GtkWidget* browser = gtk_widget_get_toplevel (GTK_WIDGET (console));
if (GTK_WIDGET_TOPLEVEL (browser))
g_signal_connect (browser, "add-tab",
G_CALLBACK (midori_console_browser_add_tab_cb), console);
}
static void
midori_console_init (MidoriConsole* console)
{
/* Create the treeview */
GtkTreeViewColumn* column;
GtkCellRenderer* renderer_text;
GtkCellRenderer* renderer_pixbuf;
GtkTreeStore* treestore = gtk_tree_store_new (3, G_TYPE_STRING,
G_TYPE_INT,
G_TYPE_STRING);
console->treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (treestore));
gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (console->treeview), FALSE);
column = gtk_tree_view_column_new ();
renderer_pixbuf = gtk_cell_renderer_pixbuf_new ();
gtk_tree_view_column_pack_start (column, renderer_pixbuf, FALSE);
gtk_tree_view_column_set_cell_data_func (column, renderer_pixbuf,
(GtkTreeCellDataFunc)midori_console_treeview_render_icon_cb,
console->treeview, NULL);
renderer_text = gtk_cell_renderer_text_new ();
gtk_tree_view_column_pack_start (column, renderer_text, FALSE);
gtk_tree_view_column_set_cell_data_func (column, renderer_text,
(GtkTreeCellDataFunc)midori_console_treeview_render_text_cb,
console->treeview, NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (console->treeview), column);
g_object_unref (treestore);
gtk_widget_show (console->treeview);
gtk_box_pack_start (GTK_BOX (console), console->treeview, TRUE, TRUE, 0);
g_signal_connect (console, "hierarchy-changed",
G_CALLBACK (midori_console_hierarchy_changed_cb), NULL);
}
/**
* midori_console_new:
*
* Creates a new empty console.
*
* Return value: a new #MidoriConsole
**/
GtkWidget*
midori_console_new (void)
{
MidoriConsole* console = g_object_new (MIDORI_TYPE_CONSOLE,
NULL);
return GTK_WIDGET (console);
}
/**
* midori_console_get_toolbar:
* @console: a #MidoriConsole
*
* Retrieves the toolbar of the console. A new widget is created on
* the first call of this function.
*
* Return value: a toolbar widget
*
* Deprecated: 0.1.2: Use midori_viewable_get_toolbar() instead.
**/
GtkWidget*
midori_console_get_toolbar (MidoriViewable* console)
{
g_return_val_if_fail (MIDORI_IS_CONSOLE (console), NULL);
if (!MIDORI_CONSOLE (console)->toolbar)
{
GtkWidget* toolbar;
GtkToolItem* toolitem;
toolbar = gtk_toolbar_new ();
gtk_toolbar_set_style (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_BOTH_HORIZ);
gtk_toolbar_set_icon_size (GTK_TOOLBAR (toolbar), GTK_ICON_SIZE_BUTTON);
toolitem = gtk_tool_button_new_from_stock (GTK_STOCK_COPY);
gtk_tool_item_set_is_important (toolitem, TRUE);
g_signal_connect (toolitem, "clicked",
G_CALLBACK (midori_console_button_copy_clicked_cb), console);
gtk_toolbar_insert (GTK_TOOLBAR (toolbar), toolitem, -1);
gtk_widget_show (GTK_WIDGET (toolitem));
/* TODO: What about a find entry here that filters e.g. by url? */
toolitem = gtk_separator_tool_item_new ();
gtk_separator_tool_item_set_draw (GTK_SEPARATOR_TOOL_ITEM (toolitem),
FALSE);
gtk_tool_item_set_expand (toolitem, TRUE);
gtk_toolbar_insert (GTK_TOOLBAR (toolbar), toolitem, -1);
gtk_widget_show (GTK_WIDGET (toolitem));
toolitem = gtk_tool_button_new_from_stock (GTK_STOCK_CLEAR);
gtk_tool_item_set_is_important (toolitem, TRUE);
g_signal_connect (toolitem, "clicked",
G_CALLBACK (midori_console_button_clear_clicked_cb), console);
gtk_toolbar_insert (GTK_TOOLBAR (toolbar), toolitem, -1);
gtk_widget_show (GTK_WIDGET (toolitem));
MIDORI_CONSOLE (console)->toolbar = toolbar;
}
return MIDORI_CONSOLE (console)->toolbar;
}
/**
* midori_console_add:
* @console: a #MidoriConsole
* @message: a descriptive message
* @line: the line in the source file
* @source_id: the source
*
* Adds a new message to the console.
**/
void
midori_console_add (MidoriConsole* console,
const gchar* message,
gint line,
const gchar* source_id)
{
GtkTreeView* treeview;
GtkTreeModel* model;
g_return_if_fail (MIDORI_IS_CONSOLE (console));
treeview = GTK_TREE_VIEW (console->treeview);
model = gtk_tree_view_get_model (treeview);
gtk_tree_store_insert_with_values (GTK_TREE_STORE (model),
NULL, NULL, G_MAXINT,
0, message, 1, line, 2, source_id, -1);
}

56
panels/midori-console.h Normal file
View file

@ -0,0 +1,56 @@
/*
Copyright (C) 2008 Christian Dywan <christian@twotoasts.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#ifndef __MIDORI_CONSOLE_H__
#define __MIDORI_CONSOLE_H__
#include <gtk/gtk.h>
#include <katze/katze.h>
#include "midori-viewable.h"
G_BEGIN_DECLS
#define MIDORI_TYPE_CONSOLE \
(midori_console_get_type ())
#define MIDORI_CONSOLE(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), MIDORI_TYPE_CONSOLE, MidoriConsole))
#define MIDORI_CONSOLE_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), MIDORI_TYPE_CONSOLE, MidoriConsoleClass))
#define MIDORI_IS_CONSOLE(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), MIDORI_TYPE_CONSOLE))
#define MIDORI_IS_CONSOLE_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), MIDORI_TYPE_CONSOLE))
#define MIDORI_CONSOLE_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), MIDORI_TYPE_CONSOLE, MidoriConsoleClass))
typedef struct _MidoriConsole MidoriConsole;
typedef struct _MidoriConsoleClass MidoriConsoleClass;
GType
midori_console_get_type (void);
GtkWidget*
midori_console_new (void);
GtkWidget*
midori_console_get_toolbar (MidoriViewable* console);
void
midori_console_add (MidoriConsole* console,
const gchar* message,
gint line,
const gchar* source_id);
G_END_DECLS
#endif /* __MIDORI_CONSOLE_H__ */

390
panels/midori-extensions.c Normal file
View file

@ -0,0 +1,390 @@
/*
Copyright (C) 2008 Christian Dywan <christian@twotoasts.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#include "midori-extensions.h"
#include "midori-app.h"
#include "midori-extension.h"
#include "midori-stock.h"
#include "midori-viewable.h"
#include "sokoke.h"
#include <glib/gi18n.h>
struct _MidoriExtensions
{
GtkVBox parent_instance;
GtkWidget* toolbar;
GtkWidget* treeview;
MidoriApp* app;
};
struct _MidoriExtensionsClass
{
GtkVBoxClass parent_class;
};
static void
midori_extensions_viewable_iface_init (MidoriViewableIface* iface);
G_DEFINE_TYPE_WITH_CODE (MidoriExtensions, midori_extensions, GTK_TYPE_VBOX,
G_IMPLEMENT_INTERFACE (MIDORI_TYPE_VIEWABLE,
midori_extensions_viewable_iface_init));
enum
{
PROP_0,
PROP_APP
};
static void
midori_extensions_set_property (GObject* object,
guint prop_id,
const GValue* value,
GParamSpec* pspec);
static void
midori_extensions_get_property (GObject* object,
guint prop_id,
GValue* value,
GParamSpec* pspec);
static void
midori_extensions_class_init (MidoriExtensionsClass* class)
{
GObjectClass* gobject_class;
GParamFlags flags;
gobject_class = G_OBJECT_CLASS (class);
gobject_class->set_property = midori_extensions_set_property;
gobject_class->get_property = midori_extensions_get_property;
flags = G_PARAM_READWRITE | G_PARAM_CONSTRUCT;
g_object_class_install_property (gobject_class,
PROP_APP,
g_param_spec_object (
"app",
"App",
"The app",
MIDORI_TYPE_APP,
flags));
}
static const gchar*
midori_extensions_get_label (MidoriViewable* viewable)
{
return _("Extensions");
}
static const gchar*
midori_extensions_get_stock_id (MidoriViewable* viewable)
{
return STOCK_EXTENSIONS;
}
static void
midori_extensions_button_status_clicked_cb (GtkToolItem* toolitem,
MidoriExtensions* extensions)
{
GtkTreeView* treeview;
GtkTreeModel* model;
GtkTreeIter iter;
MidoriExtension* extension;
treeview = GTK_TREE_VIEW (extensions->treeview);
if (katze_tree_view_get_selected_iter (treeview, &model, &iter))
{
GtkToolItem* button_enable = gtk_toolbar_get_nth_item (
GTK_TOOLBAR (extensions->toolbar), 1);
GtkToolItem* button_disable = gtk_toolbar_get_nth_item (
GTK_TOOLBAR (extensions->toolbar), 2);
gtk_tree_model_get (model, &iter, 0, &extension, -1);
if (toolitem == button_enable)
g_signal_emit_by_name (extension, "activate", extensions->app);
else if (toolitem == button_disable)
midori_extension_deactivate (extension);
gtk_widget_set_sensitive (GTK_WIDGET (button_enable),
!midori_extension_is_active (extension));
gtk_widget_set_sensitive (GTK_WIDGET (button_disable),
midori_extension_is_active (extension));
}
}
static GtkWidget*
midori_extensions_get_toolbar (MidoriViewable* extensions)
{
if (!MIDORI_EXTENSIONS (extensions)->toolbar)
{
GtkWidget* toolbar;
GtkToolItem* toolitem;
toolbar = gtk_toolbar_new ();
gtk_toolbar_set_style (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_BOTH_HORIZ);
gtk_toolbar_set_icon_size (GTK_TOOLBAR (toolbar), GTK_ICON_SIZE_BUTTON);
toolitem = gtk_tool_item_new ();
gtk_toolbar_insert (GTK_TOOLBAR (toolbar), toolitem, -1);
gtk_widget_show (GTK_WIDGET (toolitem));
/* enable button */
toolitem = gtk_tool_button_new_from_stock (GTK_STOCK_YES);
gtk_tool_button_set_label (GTK_TOOL_BUTTON (toolitem), _("_Enable"));
gtk_widget_set_tooltip_text (GTK_WIDGET (toolitem), _("Enable"));
g_signal_connect (toolitem, "clicked",
G_CALLBACK (midori_extensions_button_status_clicked_cb), extensions);
gtk_toolbar_insert (GTK_TOOLBAR (toolbar), toolitem, -1);
gtk_widget_set_sensitive (GTK_WIDGET (toolitem), FALSE);
gtk_widget_show (GTK_WIDGET (toolitem));
/* disable button */
toolitem = gtk_tool_button_new_from_stock (GTK_STOCK_NO);
gtk_tool_button_set_label (GTK_TOOL_BUTTON (toolitem), _("_Disable"));
gtk_widget_set_tooltip_text (GTK_WIDGET (toolitem), _("Disable"));
g_signal_connect (toolitem, "clicked",
G_CALLBACK (midori_extensions_button_status_clicked_cb), extensions);
gtk_toolbar_insert (GTK_TOOLBAR (toolbar), toolitem, -1);
gtk_widget_set_sensitive (GTK_WIDGET (toolitem), FALSE);
gtk_widget_show (GTK_WIDGET (toolitem));
MIDORI_EXTENSIONS (extensions)->toolbar = toolbar;
}
return MIDORI_EXTENSIONS (extensions)->toolbar;
}
static void
midori_extensions_viewable_iface_init (MidoriViewableIface* iface)
{
iface->get_stock_id = midori_extensions_get_stock_id;
iface->get_label = midori_extensions_get_label;
iface->get_toolbar = midori_extensions_get_toolbar;
}
static void
midori_extensions_add_item_cb (KatzeArray* array,
MidoriExtension* extension,
MidoriExtensions* extensions)
{
GtkTreeIter iter;
GtkTreeModel* model;
model = gtk_tree_view_get_model (GTK_TREE_VIEW (extensions->treeview));
gtk_list_store_append (GTK_LIST_STORE (model), &iter);
gtk_list_store_set (GTK_LIST_STORE (model), &iter, 0, extension, -1);
}
static void
midori_extensions_set_property (GObject* object,
guint prop_id,
const GValue* value,
GParamSpec* pspec)
{
MidoriExtensions* extensions = MIDORI_EXTENSIONS (object);
switch (prop_id)
{
case PROP_APP:
{
KatzeArray* array;
guint i, n;
/* FIXME: Handle NULL and subsequent assignments */
extensions->app = g_value_get_object (value);
array = katze_object_get_object (extensions->app, "extensions");
g_signal_connect (array, "add-item",
G_CALLBACK (midori_extensions_add_item_cb), extensions);
if ((n = katze_array_get_length (array)))
for (i = 0; i < n; i++)
midori_extensions_add_item_cb (array,
katze_array_get_nth_item (array, i), extensions);
}
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
midori_extensions_get_property (GObject* object,
guint prop_id,
GValue* value,
GParamSpec* pspec)
{
MidoriExtensions* extensions = MIDORI_EXTENSIONS (object);
switch (prop_id)
{
case PROP_APP:
g_value_set_object (value, extensions->app);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
midori_extensions_treeview_render_icon_cb (GtkTreeViewColumn* column,
GtkCellRenderer* renderer,
GtkTreeModel* model,
GtkTreeIter* iter,
GtkWidget* treeview)
{
g_object_set (renderer, "stock-id", GTK_STOCK_EXECUTE, NULL);
}
static void
midori_extensions_treeview_render_text_cb (GtkTreeViewColumn* column,
GtkCellRenderer* renderer,
GtkTreeModel* model,
GtkTreeIter* iter,
GtkWidget* treeview)
{
MidoriExtension* extension;
gchar* name;
gchar* version;
gchar* desc;
gchar* text;
gtk_tree_model_get (model, iter, 0, &extension, -1);
name = katze_object_get_string (extension, "name");
version = katze_object_get_string (extension, "version");
desc = katze_object_get_string (extension, "description");
text = g_strdup_printf ("%s %s\n%s", name, version, desc);
g_free (name);
g_free (version);
g_free (desc);
g_object_set (renderer, "text", text, NULL);
g_free (text);
}
static void
midori_extensions_treeview_row_activated_cb (GtkTreeView* treeview,
GtkTreePath* path,
GtkTreeViewColumn* column,
MidoriExtensions* extensions)
{
GtkToolItem* button_enable;
GtkToolItem* button_disable;
GtkTreeModel* model;
GtkTreeIter iter;
model = gtk_tree_view_get_model (treeview);
button_enable = gtk_toolbar_get_nth_item (
GTK_TOOLBAR (extensions->toolbar), 1);
button_disable = gtk_toolbar_get_nth_item (
GTK_TOOLBAR (extensions->toolbar), 2);
if (gtk_tree_model_get_iter (model, &iter, path))
{
MidoriExtension* extension;
gtk_tree_model_get (model, &iter, 0, &extension, -1);
if (midori_extension_is_active (extension))
midori_extension_deactivate (extension);
else
g_signal_emit_by_name (extension, "activate", extensions->app);
gtk_widget_set_sensitive (GTK_WIDGET (button_enable),
!midori_extension_is_active (extension));
gtk_widget_set_sensitive (GTK_WIDGET (button_disable),
midori_extension_is_active (extension));
}
}
static void
midori_extensions_treeview_cursor_changed_cb (GtkTreeView* treeview,
MidoriExtensions* extensions)
{
GtkTreeModel* model;
GtkTreePath* path;
GtkTreeIter iter;
GtkToolItem* button_enable;
GtkToolItem* button_disable;
gtk_tree_view_get_cursor (treeview, &path, NULL);
model = gtk_tree_view_get_model (treeview);
button_enable = gtk_toolbar_get_nth_item (
GTK_TOOLBAR (extensions->toolbar), 1);
button_disable = gtk_toolbar_get_nth_item (
GTK_TOOLBAR (extensions->toolbar), 2);
if (gtk_tree_model_get_iter (model, &iter, path))
{
MidoriExtension* extension;
if (katze_tree_view_get_selected_iter (treeview, &model, &iter))
{
gtk_tree_model_get (model, &iter, 0, &extension, -1);
gtk_widget_set_sensitive (GTK_WIDGET (button_enable),
!midori_extension_is_active (extension));
gtk_widget_set_sensitive (GTK_WIDGET (button_disable),
midori_extension_is_active (extension));
}
}
return;
}
static void
midori_extensions_init (MidoriExtensions* extensions)
{
/* Create the treeview */
GtkTreeViewColumn* column;
GtkCellRenderer* renderer_text;
GtkCellRenderer* renderer_pixbuf;
GtkListStore* liststore = gtk_list_store_new (1, G_TYPE_OBJECT);
extensions->treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (liststore));
gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (extensions->treeview), FALSE);
column = gtk_tree_view_column_new ();
renderer_pixbuf = gtk_cell_renderer_pixbuf_new ();
gtk_tree_view_column_pack_start (column, renderer_pixbuf, FALSE);
gtk_tree_view_column_set_cell_data_func (column, renderer_pixbuf,
(GtkTreeCellDataFunc)midori_extensions_treeview_render_icon_cb,
extensions->treeview, NULL);
renderer_text = gtk_cell_renderer_text_new ();
gtk_tree_view_column_pack_start (column, renderer_text, FALSE);
gtk_tree_view_column_set_cell_data_func (column, renderer_text,
(GtkTreeCellDataFunc)midori_extensions_treeview_render_text_cb,
extensions->treeview, NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (extensions->treeview), column);
g_object_unref (liststore);
g_signal_connect (extensions->treeview, "row-activated",
G_CALLBACK (midori_extensions_treeview_row_activated_cb),
extensions);
g_signal_connect (extensions->treeview, "cursor-changed",
G_CALLBACK (midori_extensions_treeview_cursor_changed_cb),
extensions);
gtk_widget_show (extensions->treeview);
gtk_box_pack_start (GTK_BOX (extensions), extensions->treeview, TRUE, TRUE, 0);
}
/**
* midori_extensions_new:
*
* Creates a new empty extensions.
*
* Return value: a new #MidoriExtensions
*
* Since: 0.1.2
**/
GtkWidget*
midori_extensions_new (void)
{
MidoriExtensions* extensions = g_object_new (MIDORI_TYPE_EXTENSIONS,
NULL);
return GTK_WIDGET (extensions);
}

Some files were not shown because too many files have changed in this diff Show more