aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.cvsignore14
-rw-r--r--AUTHORS0
-rw-r--r--COPYING340
-rw-r--r--ChangeLog875
-rw-r--r--HACKING16
-rw-r--r--INSTALL182
-rw-r--r--Makefile.am8
-rw-r--r--NEWS0
-rw-r--r--README121
-rw-r--r--TODO17
-rw-r--r--acconfig.h6
-rwxr-xr-xautogen.sh19
-rw-r--r--configure.in171
-rw-r--r--data/.cvsignore5
-rw-r--r--data/GNOME_Epiphany_Automation.server.in20
-rw-r--r--data/GNOME_Epiphany_NautilusView.server.in30
-rw-r--r--data/Makefile.am29
-rw-r--r--data/art/.cvsignore2
-rw-r--r--data/art/Makefile.am7
-rw-r--r--data/art/epiphany-secure.pngbin0 -> 332 bytes
-rw-r--r--data/art/epiphany-unsecure.pngbin0 -> 332 bytes
-rw-r--r--data/epiphany.schemas.in627
-rw-r--r--data/glade/.cvsignore3
-rw-r--r--data/glade/Makefile.am10
-rw-r--r--data/glade/epiphany.glade1582
-rw-r--r--data/glade/prefs-dialog.glade3083
-rw-r--r--data/glade/print.glade1573
-rw-r--r--data/glade/prompts.glade722
-rw-r--r--data/glade/toolbar-editor.glade418
-rw-r--r--data/start_here.html23
-rw-r--r--data/ui/.cvsignore4
-rw-r--r--data/ui/Makefile.am11
-rw-r--r--data/ui/epiphany-ui.xml.in454
-rw-r--r--data/ui/nautilus-epiphany-view.xml.in130
-rw-r--r--embed/.cvsignore6
-rw-r--r--embed/Makefile.am57
-rw-r--r--embed/downloader-view.c1100
-rw-r--r--embed/downloader-view.h100
-rw-r--r--embed/ephy-embed-dialog.c194
-rw-r--r--embed/ephy-embed-dialog.h69
-rw-r--r--embed/ephy-embed-event.c179
-rw-r--r--embed/ephy-embed-event.h100
-rw-r--r--embed/ephy-embed-favicon.c252
-rw-r--r--embed/ephy-embed-favicon.h63
-rw-r--r--embed/ephy-embed-persist.c491
-rw-r--r--embed/ephy-embed-persist.h129
-rw-r--r--embed/ephy-embed-popup-bw.c187
-rw-r--r--embed/ephy-embed-popup-bw.h58
-rw-r--r--embed/ephy-embed-popup-control.c188
-rw-r--r--embed/ephy-embed-popup-control.h61
-rw-r--r--embed/ephy-embed-popup.c623
-rw-r--r--embed/ephy-embed-popup.h73
-rw-r--r--embed/ephy-embed-prefs.h46
-rw-r--r--embed/ephy-embed-shell.c507
-rw-r--r--embed/ephy-embed-shell.h307
-rw-r--r--embed/ephy-embed-types.h47
-rw-r--r--embed/ephy-embed-utils.c321
-rw-r--r--embed/ephy-embed-utils.h50
-rw-r--r--embed/ephy-embed.c608
-rw-r--r--embed/ephy-embed.h443
-rw-r--r--embed/ephy-favicon-cache.c367
-rw-r--r--embed/ephy-favicon-cache.h68
-rw-r--r--embed/ephy-favicon.c280
-rw-r--r--embed/ephy-favicon.h64
-rw-r--r--embed/ephy-history.c644
-rw-r--r--embed/ephy-history.h92
-rwxr-xr-xembed/find-dialog.c431
-rw-r--r--embed/find-dialog.h74
-rw-r--r--embed/mozilla/.cvsignore6
-rw-r--r--embed/mozilla/BaseProtocolContentHandler.cpp104
-rw-r--r--embed/mozilla/BaseProtocolContentHandler.h43
-rw-r--r--embed/mozilla/BaseProtocolHandler.cpp106
-rw-r--r--embed/mozilla/BaseProtocolHandler.h39
-rw-r--r--embed/mozilla/ContentHandler.cpp671
-rw-r--r--embed/mozilla/ContentHandler.h102
-rw-r--r--embed/mozilla/EphyEventListener.cpp114
-rw-r--r--embed/mozilla/EphyEventListener.h46
-rw-r--r--embed/mozilla/EphyWrapper.cpp1384
-rw-r--r--embed/mozilla/EphyWrapper.h147
-rw-r--r--embed/mozilla/EventContext.cpp669
-rw-r--r--embed/mozilla/EventContext.h65
-rw-r--r--embed/mozilla/ExternalProtocolService.cpp176
-rw-r--r--embed/mozilla/ExternalProtocolService.h50
-rw-r--r--embed/mozilla/FilePicker.cpp505
-rw-r--r--embed/mozilla/FilePicker.h94
-rw-r--r--embed/mozilla/FtpProtocolHandler.cpp58
-rw-r--r--embed/mozilla/FtpProtocolHandler.h52
-rw-r--r--embed/mozilla/GlobalHistory.cpp169
-rw-r--r--embed/mozilla/GlobalHistory.h31
-rw-r--r--embed/mozilla/IRCProtocolHandler.cpp58
-rw-r--r--embed/mozilla/IRCProtocolHandler.h43
-rw-r--r--embed/mozilla/MailtoProtocolHandler.cpp64
-rw-r--r--embed/mozilla/MailtoProtocolHandler.h43
-rw-r--r--embed/mozilla/Makefile.am108
-rw-r--r--embed/mozilla/MozRegisterComponents.cpp226
-rw-r--r--embed/mozilla/MozRegisterComponents.h33
-rw-r--r--embed/mozilla/MozillaPrivate.cpp105
-rw-r--r--embed/mozilla/MozillaPrivate.h9
-rw-r--r--embed/mozilla/PrintProgressListener.cpp116
-rw-r--r--embed/mozilla/PrintProgressListener.h38
-rw-r--r--embed/mozilla/PrintingPromptService.cpp129
-rw-r--r--embed/mozilla/PrintingPromptService.h38
-rw-r--r--embed/mozilla/ProgressListener.cpp718
-rw-r--r--embed/mozilla/ProgressListener.h139
-rw-r--r--embed/mozilla/PromptService.cpp769
-rw-r--r--embed/mozilla/PromptService.h39
-rw-r--r--embed/mozilla/StartHereProtocolHandler.cpp162
-rw-r--r--embed/mozilla/StartHereProtocolHandler.h38
-rw-r--r--embed/mozilla/mozilla-embed-persist.cpp244
-rw-r--r--embed/mozilla/mozilla-embed-persist.h56
-rw-r--r--embed/mozilla/mozilla-embed-shell.cpp1106
-rw-r--r--embed/mozilla/mozilla-embed-shell.h55
-rw-r--r--embed/mozilla/mozilla-embed.cpp1585
-rw-r--r--embed/mozilla/mozilla-embed.h61
-rw-r--r--embed/mozilla/mozilla-i18n.c162
-rw-r--r--embed/mozilla/mozilla-i18n.h60
-rw-r--r--embed/mozilla/mozilla-notifiers.cpp710
-rw-r--r--embed/mozilla/mozilla-notifiers.h30
-rw-r--r--embed/mozilla/mozilla-prefs.cpp185
-rw-r--r--embed/mozilla/mozilla-prefs.h44
-rw-r--r--embed/mozilla/nsUnicharUtils.cpp344
-rw-r--r--embed/mozilla/nsUnicharUtils.h96
-rwxr-xr-xembed/print-dialog.c402
-rw-r--r--embed/print-dialog.h73
-rw-r--r--idl/EphyAutomation.idl27
-rw-r--r--lib/.cvsignore6
-rw-r--r--lib/Makefile.am73
-rw-r--r--lib/eel-gconf-extensions.c556
-rw-r--r--lib/eel-gconf-extensions.h87
-rw-r--r--lib/ephy-autocompletion-source.c85
-rw-r--r--lib/ephy-autocompletion-source.h80
-rw-r--r--lib/ephy-autocompletion.c664
-rw-r--r--lib/ephy-autocompletion.h107
-rw-r--r--lib/ephy-bonobo-extensions.c679
-rw-r--r--lib/ephy-bonobo-extensions.h121
-rw-r--r--lib/ephy-dialog.c943
-rw-r--r--lib/ephy-dialog.h119
-rw-r--r--lib/ephy-dnd.c109
-rw-r--r--lib/ephy-dnd.h67
-rw-r--r--lib/ephy-file-helpers.c326
-rw-r--r--lib/ephy-file-helpers.h48
-rw-r--r--lib/ephy-filesystem-autocompletion.c343
-rw-r--r--lib/ephy-filesystem-autocompletion.h70
-rw-r--r--lib/ephy-glade.c134
-rw-r--r--lib/ephy-glade.h41
-rw-r--r--lib/ephy-gobject-misc.h77
-rw-r--r--lib/ephy-gui.c352
-rw-r--r--lib/ephy-gui.h79
-rw-r--r--lib/ephy-marshal.list16
-rw-r--r--lib/ephy-node-filter.c461
-rw-r--r--lib/ephy-node-filter.h102
-rw-r--r--lib/ephy-node.c1439
-rw-r--r--lib/ephy-node.h144
-rw-r--r--lib/ephy-prefs-utils.c285
-rw-r--r--lib/ephy-prefs-utils.h61
-rw-r--r--lib/ephy-prefs.h58
-rw-r--r--lib/ephy-state.c157
-rw-r--r--lib/ephy-state.h44
-rw-r--r--lib/ephy-stock-icons.c62
-rw-r--r--lib/ephy-stock-icons.h33
-rw-r--r--lib/ephy-string.c446
-rw-r--r--lib/ephy-string.h63
-rw-r--r--lib/ephy-thread-helpers.c35
-rw-r--r--lib/ephy-thread-helpers.h34
-rw-r--r--lib/ephy-types.h35
-rw-r--r--lib/toolbar/.cvsignore6
-rw-r--r--lib/toolbar/Makefile.am41
-rw-r--r--lib/toolbar/ephy-tbi-favicon.c188
-rw-r--r--lib/toolbar/ephy-tbi-favicon.h66
-rw-r--r--lib/toolbar/ephy-tbi-location.c205
-rw-r--r--lib/toolbar/ephy-tbi-location.h66
-rw-r--r--lib/toolbar/ephy-tbi-navigation-history.c342
-rw-r--r--lib/toolbar/ephy-tbi-navigation-history.h81
-rw-r--r--lib/toolbar/ephy-tbi-separator.c179
-rw-r--r--lib/toolbar/ephy-tbi-separator.h68
-rw-r--r--lib/toolbar/ephy-tbi-spinner.c188
-rw-r--r--lib/toolbar/ephy-tbi-spinner.h66
-rw-r--r--lib/toolbar/ephy-tbi-std-toolitem.c467
-rw-r--r--lib/toolbar/ephy-tbi-std-toolitem.h86
-rw-r--r--lib/toolbar/ephy-tbi-zoom.c304
-rw-r--r--lib/toolbar/ephy-tbi-zoom.h66
-rw-r--r--lib/toolbar/ephy-toolbar-bonobo-view.c193
-rw-r--r--lib/toolbar/ephy-toolbar-bonobo-view.h75
-rw-r--r--lib/toolbar/ephy-toolbar-editor.c634
-rw-r--r--lib/toolbar/ephy-toolbar-editor.h80
-rw-r--r--lib/toolbar/ephy-toolbar-item-factory.c158
-rw-r--r--lib/toolbar/ephy-toolbar-item-factory.h31
-rw-r--r--lib/toolbar/ephy-toolbar-item.c142
-rw-r--r--lib/toolbar/ephy-toolbar-item.h91
-rw-r--r--lib/toolbar/ephy-toolbar-tree-model.c784
-rw-r--r--lib/toolbar/ephy-toolbar-tree-model.h74
-rw-r--r--lib/toolbar/ephy-toolbar.c420
-rw-r--r--lib/toolbar/ephy-toolbar.h80
-rw-r--r--lib/widgets/.cvsignore6
-rw-r--r--lib/widgets/Makefile.am30
-rw-r--r--lib/widgets/eggtreemodelfilter.c2560
-rw-r--r--lib/widgets/eggtreemodelfilter.h123
-rw-r--r--lib/widgets/eggtreemultidnd.c415
-rw-r--r--lib/widgets/eggtreemultidnd.h78
-rw-r--r--lib/widgets/ephy-autocompletion-window.c854
-rw-r--r--lib/widgets/ephy-autocompletion-window.h87
-rw-r--r--lib/widgets/ephy-ellipsizing-label.c774
-rw-r--r--lib/widgets/ephy-ellipsizing-label.h71
-rw-r--r--lib/widgets/ephy-location-entry.c700
-rw-r--r--lib/widgets/ephy-location-entry.h74
-rw-r--r--lib/widgets/ephy-notebook.c843
-rw-r--r--lib/widgets/ephy-notebook.h99
-rw-r--r--lib/widgets/ephy-spinner.c897
-rw-r--r--lib/widgets/ephy-spinner.h78
-rw-r--r--lib/widgets/ephy-tree-model-sort.c240
-rw-r--r--lib/widgets/ephy-tree-model-sort.h59
-rw-r--r--po/.cvsignore6
-rw-r--r--po/ChangeLog0
-rw-r--r--po/POTFILES.in45
-rw-r--r--src/.cvsignore6
-rw-r--r--src/Makefile.am101
-rwxr-xr-xsrc/appearance-prefs.c458
-rw-r--r--src/appearance-prefs.h58
-rw-r--r--src/bookmarks/.cvsignore6
-rw-r--r--src/bookmarks/Makefile.am31
-rw-r--r--src/bookmarks/ephy-bookmarks-editor.c534
-rw-r--r--src/bookmarks/ephy-bookmarks-editor.h59
-rw-r--r--src/bookmarks/ephy-bookmarks.c988
-rw-r--r--src/bookmarks/ephy-bookmarks.h108
-rw-r--r--src/bookmarks/ephy-keywords-entry.c286
-rw-r--r--src/bookmarks/ephy-keywords-entry.h68
-rw-r--r--src/bookmarks/ephy-new-bookmark.c340
-rw-r--r--src/bookmarks/ephy-new-bookmark.h65
-rw-r--r--src/bookmarks/ephy-node-view.c531
-rw-r--r--src/bookmarks/ephy-node-view.h82
-rw-r--r--src/bookmarks/ephy-tree-model-node.c702
-rw-r--r--src/bookmarks/ephy-tree-model-node.h81
-rw-r--r--src/ephy-automation.c217
-rw-r--r--src/ephy-automation.h52
-rw-r--r--src/ephy-favorites-menu.c275
-rw-r--r--src/ephy-favorites-menu.h66
-rw-r--r--src/ephy-history-model.c838
-rw-r--r--src/ephy-history-model.h84
-rw-r--r--src/ephy-main.c340
-rw-r--r--src/ephy-nautilus-view.c954
-rw-r--r--src/ephy-nautilus-view.h84
-rw-r--r--src/ephy-shell.c525
-rw-r--r--src/ephy-shell.h101
-rw-r--r--src/ephy-tab.c945
-rw-r--r--src/ephy-tab.h105
-rw-r--r--src/ephy-window.c1428
-rw-r--r--src/ephy-window.h140
-rwxr-xr-xsrc/general-prefs.c484
-rw-r--r--src/general-prefs.h58
-rwxr-xr-xsrc/history-dialog.c478
-rw-r--r--src/history-dialog.h63
-rw-r--r--src/language-editor.c388
-rw-r--r--src/language-editor.h67
-rwxr-xr-xsrc/pdm-dialog.c669
-rw-r--r--src/pdm-dialog.h56
-rw-r--r--src/popup-commands.c222
-rw-r--r--src/popup-commands.h58
-rwxr-xr-xsrc/ppview-toolbar.c388
-rw-r--r--src/ppview-toolbar.h63
-rw-r--r--src/prefs-dialog.c335
-rw-r--r--src/prefs-dialog.h63
-rw-r--r--src/session.c690
-rw-r--r--src/session.h84
-rwxr-xr-xsrc/statusbar.c321
-rw-r--r--src/statusbar.h70
-rwxr-xr-xsrc/toolbar.c982
-rw-r--r--src/toolbar.h88
-rwxr-xr-xsrc/ui-prefs.c232
-rw-r--r--src/ui-prefs.h58
-rw-r--r--src/window-commands.c917
-rw-r--r--src/window-commands.h196
271 files changed, 71076 insertions, 0 deletions
diff --git a/.cvsignore b/.cvsignore
new file mode 100644
index 000000000..98c606041
--- /dev/null
+++ b/.cvsignore
@@ -0,0 +1,14 @@
+*.gz
+stamp-h
+stamp-h.in
+stamp-h1
+.*.swp
+libtool
+ltmain.sh
+intltool*
+configure
+config.*
+aclocal.m4
+Makefile
+Makefile.in
+*.cache
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/AUTHORS
diff --git a/COPYING b/COPYING
new file mode 100644
index 000000000..d60c31a97
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, 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 or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+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 give any other recipients of the Program a copy of this License
+along with the Program.
+
+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 Program or any portion
+of it, thus forming a work based on the Program, 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) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+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 Program, 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 Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) 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; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, 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 executable. However, as a
+special exception, the source code 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.
+
+If distribution of executable or 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 counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program 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.
+
+ 5. 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 Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program 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 to
+this License.
+
+ 7. 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 Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program 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 Program.
+
+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.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program 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.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the 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 Program
+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 Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, 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
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "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 PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. 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 PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), 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 Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. 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 program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 000000000..971d6188a
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,875 @@
+2002-12-30 Marco Pesenti Gritti <marco@it.gnome.org>
+
+ * embed/ephy-favicon-cache.c: (ephy_favicon_cache_dest),
+ (ephy_favicon_cache_insert_from_url),
+ (favicon_download_completed_cb):
+ * lib/ephy-dnd.c: (ephy_dnd_enable_model_drag_source):
+ * lib/ephy-dnd.h:
+ * lib/widgets/eggtreemultidnd.c:
+ (egg_tree_multi_drag_source_drag_data_get),
+ (egg_tree_multi_drag_drag_data_get):
+ * lib/widgets/eggtreemultidnd.h:
+ * lib/widgets/ephy-tree-model-sort.c:
+ (ephy_tree_model_sort_multi_drag_data_delete),
+ (each_url_get_data_binder),
+ (ephy_tree_model_sort_multi_drag_data_get):
+ * src/bookmarks/ephy-bookmarks-editor.c:
+ (ephy_bookmarks_editor_construct):
+ * src/bookmarks/ephy-node-view.c:
+ (ephy_node_view_enable_drag_source):
+ * src/bookmarks/ephy-node-view.h:
+ * src/history-dialog.c: (history_dialog_setup_view):
+
+ Use ephy-dnd for tree model too.
+ Fix favicons.
+
+2002-12-30 Marco Pesenti Gritti <marco@it.gnome.org>
+
+ * data/epiphany.schemas.in:
+ * lib/widgets/eggtreemodelfilter.c:
+ (egg_tree_model_filter_build_level):
+ * lib/widgets/ephy-autocompletion-window.c:
+ (ephy_autocompletion_window_get_dimensions),
+ (ephy_autocompletion_window_show), (hack_tree_view_move_selection),
+ (ephy_autocompletion_window_key_press_hack),
+ (ephy_autocompletion_window_key_press_cb),
+ (ephy_autocompletion_window_hide):
+ * src/bookmarks/ephy-bookmarks.c:
+ (ephy_bookmarks_clean_empty_keywords), (bookmarks_removed_cb):
+ * src/bookmarks/ephy-new-bookmark.c: (build_editing_table),
+ (ephy_new_bookmark_construct):
+ * src/bookmarks/ephy-node-view.c: (ephy_node_view_finalize):
+ * src/history-dialog.c: (history_dialog_finalize):
+
+ Fix some bookmarks crashes.
+ Cycle between the two views in autocompletion when
+ moving with keys.
+
+2002-12-29 Marco Pesenti Gritti <marco@it.gnome.org>
+
+ * TODO:
+ * lib/ephy-dnd.h:
+ * lib/ephy-marshal.c: (ephy_marshal_VOID__POINTER_POINTER):
+ * lib/ephy-marshal.h:
+ * lib/ephy-marshal.list:
+ * lib/widgets/Makefile.am:
+ * src/bookmarks/ephy-bookmarks-editor.c:
+ (ephy_bookmarks_editor_construct):
+ * src/bookmarks/ephy-new-bookmark.c: (ephy_new_bookmark_new):
+ * src/bookmarks/ephy-node-view.c:
+ (ephy_node_view_row_activated_cb), (node_from_sort_iter_cb),
+ (ephy_node_view_construct), (ephy_node_view_add_column),
+ (get_selection), (ephy_node_view_select_node),
+ (ephy_node_view_enable_drag_source):
+ * src/bookmarks/ephy-node-view.h:
+ * src/history-dialog.c: (add_column),
+ (history_view_row_activated_cb), (node_from_sort_iter_cb),
+ (history_dialog_setup_view):
+
+ Implement column sorting / drag and drop for history
+ and bookmarks.
+
+2002-12-29 Marco Pesenti Gritti <marco@it.gnome.org>
+
+ * data/glade/epiphany.glade:
+ * embed/ephy-history.c: (hosts_added_cb), (hosts_removed_cb),
+ (ephy_history_add_host), (ephy_history_add_page),
+ (ephy_history_set_page_title):
+ * embed/ephy-history.h:
+ * src/bookmarks/ephy-node-filter.c:
+ (ephy_node_filter_expression_evaluate):
+ * src/ephy-history-model.c: (get_one_level_path_real),
+ (get_path_real), (ephy_history_model_get_path),
+ (get_property_as_date), (ephy_history_model_get_value),
+ (ephy_history_model_update_node), (root_child_removed_cb),
+ (root_child_added_cb):
+ * src/history-dialog.c: (history_view_row_activated_cb),
+ (history_dialog_setup_view), (get_date_filter),
+ (history_dialog_setup_filter), (history_dialog_init),
+ (history_dialog_new_with_parent):
+
+ Reimplement filtering, fix a few bugs. Please remove
+ ephy-history.xml again, should be the last time, sorry.
+
+2002-12-28 Marco Pesenti Gritti <marco@it.gnome.org>
+
+ * embed/ephy-history.c: (ephy_history_add_page):
+ * src/ephy-history-model.c: (get_one_level_path_real),
+ (get_path_real), (ephy_history_model_get_path),
+ (ephy_history_model_update_node), (root_child_removed_cb),
+ (root_child_added_cb):
+
+ Update the model correctly when the history changes.
+
+2002-12-28 Marco Pesenti Gritti <marco@it.gnome.org>
+
+ * embed/ephy-history.c: (ephy_history_add_host):
+
+ Fix memory corruption. The history now should work
+ better but please kill ephy-history.xml or you could
+ get crashes.
+
+2002-12-28 Marco Pesenti Gritti <marco@it.gnome.org>
+
+ * embed/ephy-history.c: (ephy_history_init),
+ (ephy_history_add_page), (ephy_history_clear),
+ (ephy_history_get_hosts), (ephy_history_get_pages):
+ * embed/ephy-history.h:
+ * src/Makefile.am:
+ * src/ephy-history-model.c: (ephy_history_model_get_type),
+ (ephy_history_model_class_init), (ephy_history_model_init),
+ (ephy_history_model_finalize), (filter_changed_cb),
+ (ephy_history_model_set_property),
+ (ephy_history_model_get_property), (ephy_history_model_new),
+ (ephy_history_model_tree_model_init),
+ (ephy_history_model_get_flags), (ephy_history_model_get_n_columns),
+ (ephy_history_model_get_column_type),
+ (ephy_history_model_get_iter), (ensure_iter), (get_parent_node),
+ (get_path_real), (ephy_history_model_get_path),
+ (ephy_history_model_get_host_value),
+ (ephy_history_model_get_value), (ephy_history_model_iter_next),
+ (ephy_history_model_iter_children),
+ (ephy_history_model_iter_has_child),
+ (ephy_history_model_iter_n_children),
+ (ephy_history_model_iter_nth_child),
+ (ephy_history_model_iter_parent),
+ (ephy_history_model_node_from_iter),
+ (ephy_history_model_iter_from_node),
+ (ephy_history_model_update_node), (root_child_removed_cb),
+ (root_child_added_cb), (root_child_changed_cb),
+ (ephy_history_model_column_get_type):
+ * src/ephy-history-model.h:
+ * src/history-dialog.c: (add_column), (history_dialog_setup_view),
+ (history_dialog_init):
+
+ Implement an history model and use it.
+
+2002-12-27 Marco Pesenti Gritti <marco@it.gnome.org>
+
+ * data/Makefile.am:
+ * embed/Makefile.am:
+ * embed/ephy-embed-favicon.c: (location_changed_cb),
+ (ephy_embed_favicon_set_property):
+ * embed/ephy-embed-shell.c: (ephy_embed_shell_init),
+ (ephy_embed_shell_finalize), (ephy_embed_shell_get_favicon_cache),
+ (impl_get_global_history):
+ * embed/ephy-embed-shell.h:
+ * embed/ephy-favicon-cache.c: (ephy_favicon_cache_set_property),
+ (ephy_favicon_cache_get_property), (ephy_favicon_cache_class_init),
+ (ephy_favicon_cache_init), (ephy_favicon_cache_finalize),
+ (ephy_favicon_cache_new), (ephy_favicon_cache_lookup),
+ (ephy_favicon_cache_lookup_direct), (ephy_favicon_cache_insert),
+ (ephy_favicon_cache_dest):
+ * embed/ephy-favicon-cache.h:
+ * embed/ephy-favicon.c: (cache_changed_cb):
+ * embed/ephy-history.c: (ephy_history_get_type),
+ (ephy_history_autocompletion_source_set_basic_key),
+ (ephy_history_autocompletion_source_foreach),
+ (ephy_history_emit_data_changed),
+ (ephy_history_autocompletion_source_init),
+ (ephy_history_class_init), (ephy_history_load),
+ (ephy_history_save), (hosts_added_cb), (hosts_removed_cb),
+ (pages_added_cb), (pages_removed_cb), (ephy_history_init),
+ (ephy_history_finalize), (ephy_history_new),
+ (ephy_history_add_host), (ephy_history_visited),
+ (ephy_history_get_page_visits), (ephy_history_add_page),
+ (ephy_history_get_page), (ephy_history_is_page_visited),
+ (ephy_history_set_page_title), (ephy_history_clear),
+ (ephy_history_get_root), (ephy_history_get_last_page):
+ * embed/ephy-history.h:
+ * embed/global-history.c:
+ * embed/global-history.h:
+ * embed/mozilla/EphyWrapper.cpp:
+ * embed/mozilla/GlobalHistory.cpp:
+ * lib/Makefile.am:
+ * lib/ephy-node.c: (ephy_node_get_type), (ephy_node_class_init),
+ (int_equal), (int_hash), (ephy_node_init), (ephy_node_finalize),
+ (remove_child), (ephy_node_dispose),
+ (ephy_node_set_object_property), (ephy_node_get_object_property),
+ (ephy_node_new), (ephy_node_get_id), (node_from_id_real),
+ (ephy_node_get_from_id), (ephy_node_ref), (ephy_node_unref),
+ (ephy_node_freeze), (ephy_node_thaw), (child_changed),
+ (real_set_property), (ephy_node_set_property),
+ (ephy_node_get_property), (ephy_node_get_property_string),
+ (ephy_node_get_property_boolean), (ephy_node_get_property_long),
+ (ephy_node_get_property_int), (ephy_node_get_property_double),
+ (ephy_node_get_property_float), (ephy_node_get_property_node),
+ (ephy_node_get_property_time), (save_parent),
+ (ephy_node_save_to_xml), (ephy_node_new_from_xml),
+ (real_add_child), (ephy_node_add_child), (real_remove_child),
+ (ephy_node_remove_child), (ephy_node_has_child),
+ (ephy_node_get_children), (ephy_node_get_n_children),
+ (ephy_node_get_nth_child), (get_child_index_real),
+ (ephy_node_get_child_index), (ephy_node_get_next_child),
+ (ephy_node_get_previous_child), (ephy_node_system_init),
+ (ephy_node_system_shutdown), (ephy_node_new_id),
+ (id_factory_set_to), (write_lock_to_read_lock),
+ (read_lock_to_write_lock), (lock_gdk), (unlock_gdk):
+ * lib/ephy-node.h:
+ * src/bookmarks/Makefile.am:
+ * src/bookmarks/ephy-bookmarks.c: (get_history_item_score),
+ (compute_lower_fav), (add_to_favorites), (history_site_visited_cb),
+ (ephy_setup_history_notifiers), (ephy_bookmarks_init),
+ (ephy_bookmarks_finalize):
+ * src/bookmarks/ephy-node.c:
+ * src/bookmarks/ephy-node.h:
+ * src/ephy-shell.c: (ephy_shell_init), (ephy_shell_finalize),
+ (build_homepage_url), (ephy_shell_get_autocompletion):
+ * src/ephy-shell.h:
+ * src/history-dialog.c: (history_dialog_setup_view),
+ (history_dialog_setup_filter), (history_dialog_init),
+ (history_dialog_set_embedded), (history_dialog_finalize),
+ (history_host_checkbutton_toggled_cb), (history_entry_changed_cb),
+ (history_time_optionmenu_changed_cb),
+ (history_clear_button_clicked_cb):
+
+ Rewrite the history using ephy node.
+ Use the history to store favicons locations.
+
+2002-12-26 Marco Pesenti Gritti <marco@it.gnome.org>
+
+ * embed/ephy-embed-favicon.c: (net_state_cb), (favicon_cb):
+
+ fix some bugs
+
+2002-12-26 Marco Pesenti Gritti <marco@it.gnome.org>
+
+ * TODO:
+ * embed/ephy-embed-favicon.c: (net_state_cb), (favicon_cb),
+ (ephy_embed_favicon_set_property),
+ (ephy_embed_favicon_get_property), (ephy_embed_favicon_get_embed):
+ * embed/ephy-embed.c: (ephy_embed_base_init),
+ (ephy_embed_get_link_tags):
+ * embed/ephy-embed.h:
+ * embed/mozilla/EphyWrapper.cpp:
+ * embed/mozilla/EphyWrapper.h:
+ * embed/mozilla/Makefile.am:
+ * embed/mozilla/mozilla-embed.cpp:
+
+ Make favicons work :)
+
+2002-12-26 Marco Pesenti Gritti <marco@it.gnome.org>
+
+ * configure.in:
+ * embed/find-dialog.c: (find_dialog_go_next),
+ (find_dialog_go_prev):
+ * lib/ephy-autocompletion.c:
+ (ephy_autocompletion_get_matches_sorted_by_score),
+ (ephy_autocompletion_refine_matches),
+ (ephy_autocompletion_update_matches_full),
+ (ephy_autocompletion_sort_by_score):
+ * lib/ephy-autocompletion.h:
+ * lib/widgets/ephy-autocompletion-window.c:
+ (ephy_autocompletion_window_get_dimensions),
+ (ephy_autocompletion_window_fill_store_chunk),
+ (ephy_autocompletion_window_show):
+ * src/popup-commands.c: (popup_cmd_add_bookmark):
+
+ Fix a regression in find dialog.
+ Fix autocompletion flickering
+
+2002-12-25 Marco Pesenti Gritti <marco@it.gnome.org>
+
+ * embed/find-dialog.c: (find_dialog_go_next),
+ (find_dialog_go_prev):
+ * src/bookmarks/ephy-bookmarks.c:
+ (ephy_bookmarks_autocompletion_source_foreach):
+
+ Fix crash on find next.
+ Fix crash on autocompletion.
+
+2002-12-24 Marco Pesenti Gritti <marco@it.gnome.org>
+
+ * src/bookmarks/ephy-bookmarks-editor.c:
+ (keyword_node_selected_cb), (ephy_bookmarks_editor_construct):
+
+ Regression fixed.
+
+2002-12-24 Marco Pesenti Gritti <marco@it.gnome.org>
+
+ * src/bookmarks/Makefile.am:
+ * src/bookmarks/ephy-bookmarks-editor.c: (keywords_changed_cb),
+ (keywords_removed_cb), (ephy_bookmarks_editor_construct):
+ * src/bookmarks/ephy-bookmarks.c: (ephy_bookmarks_add),
+ (ephy_bookmarks_unset_keyword), (diff_keywords),
+ (ephy_bookmarks_update_keywords):
+ * src/bookmarks/ephy-bookmarks.h:
+ * src/window-commands.c: (window_cmd_bookmarks_add_default):
+
+ Implement a small dialog asking title/keywords when adding
+ bookmarks.
+ (Regression: removing a selected keyword doesnt work
+ anymore, will fix)
+
+2002-12-24 Marco Pesenti Gritti <marco@it.gnome.org>
+
+ * data/glade/epiphany.glade:
+ * data/ui/epiphany-ui.xml.in:
+ * embed/mozilla/ContentHandler.cpp:
+ * embed/mozilla/FilePicker.cpp:
+ * embed/mozilla/FilePicker.h:
+ * lib/widgets/Makefile.am:
+ * lib/widgets/ephy-sidebar.c:
+ * lib/widgets/ephy-sidebar.h:
+ * src/ephy-tab.c: (ephy_tab_init), (get_host_name_from_uri):
+ * src/ephy-window.c: (update_layout_toggles), (setup_layout_menus),
+ (ephy_window_init), (save_window_chrome),
+ (translate_default_chrome), (ephy_window_set_chrome),
+ (ephy_window_update_all_controls):
+ * src/ephy-window.h:
+ * src/session.c:
+
+ Drop sidebar and useless bytes progress messages.
+
+2002-12-23 Marco Pesenti Gritti <marco@it.gnome.org>
+
+ * lib/widgets/ephy-autocompletion-window.c:
+ (ephy_autocompletion_window_get_dimensions),
+ (ephy_autocompletion_window_show),
+ (ephy_autocompletion_window_hide):
+ * src/session.c: (do_session_resume), (crashed_resume_dialog),
+ (session_autoresume):
+
+ fix autocompl bugs.
+ Simpler recover dialog.
+
+2002-12-23 Marco Pesenti Gritti <marco@it.gnome.org>
+
+ * lib/widgets/ephy-autocompletion-window.c:
+ (ephy_autocompletion_window_finalize_impl),
+ (ephy_autocompletion_window_init_widgets),
+ (ephy_autocompletion_window_set_autocompletion),
+ (ephy_autocompletion_window_get_dimensions),
+ (ephy_autocompletion_window_fill_store_chunk),
+ (ephy_autocompletion_window_show),
+ (ephy_autocompletion_window_event_after_cb):
+ * lib/widgets/ephy-location-entry.c: (ephy_location_ignore_prefix),
+ (ephy_location_entry_autocompletion_show_alternatives_to),
+ (ephy_location_entry_key_press_event_cb):
+ * src/bookmarks/ephy-bookmarks.c:
+ (ephy_bookmarks_autocompletion_source_foreach):
+
+ Never show an horizontal scrollbar.
+ Put a limit to completions, ever show bookmarks / smart
+ bookmarks matches. Order bookmarks at the bottom of
+ completions.
+ Ignore common used web prefixes (like www)
+
+2002-12-22 Marco Pesenti Gritti <marco@it.gnome.org>
+
+ * lib/ephy-autocompletion.c: (ephy_autocompletion_get_num_matches),
+ (ephy_autocompletion_get_num_action_matches),
+ (ephy_autocompletion_refine_matches),
+ (ephy_autocompletion_update_matches_full_item), (acma_destroy),
+ (acma_append):
+ * lib/ephy-autocompletion.h:
+ * lib/widgets/ephy-autocompletion-window.c:
+ (ephy_autocompletion_window_init),
+ (ephy_autocompletion_window_finalize_impl),
+ (ephy_autocompletion_window_selection_changed_cb),
+ (ephy_autocompletion_window_get_dimensions),
+ (ephy_autocompletion_window_show),
+ (ephy_autocompletion_window_key_press_hack),
+ (ephy_autocompletion_window_key_press_cb),
+ (ephy_autocompletion_window_event_after_cb):
+ * lib/widgets/ephy-location-entry.c: (ephy_location_entry_init),
+ (ephy_location_entry_content_is_text),
+ (ephy_location_entry_activate_cb),
+ (ephy_location_entry_autocompletion_window_url_activated_cb):
+ * src/bookmarks/ephy-bookmarks.c:
+ (ephy_bookmarks_autocompletion_source_foreach),
+ (ephy_bookmarks_save), (ephy_bookmarks_solve_smart_url):
+ * src/ephy-shell.c: (ephy_shell_get_autocompletion):
+ * src/toolbar.c: (toolbar_location_url_activate_cb):
+
+ Complete smart bookmarks "autocompletion".
+
+2002-12-21 Marco Pesenti Gritti <marco@it.gnome.org>
+
+ * lib/ephy-autocompletion.c: (ephy_autocompletion_refine_matches),
+ (ephy_autocompletion_update_matches),
+ (ephy_autocompletion_update_matches_full_item):
+ * lib/ephy-autocompletion.h:
+ * lib/widgets/ephy-autocompletion-window.c:
+ (ephy_autocompletion_window_class_init),
+ (ephy_autocompletion_window_selection_add_selected),
+ (ephy_autocompletion_window_get_dimensions),
+ (ephy_autocompletion_window_fill_store_chunk),
+ (ephy_autocompletion_window_show),
+ (ephy_autocompletion_window_key_press_hack),
+ (ephy_autocompletion_window_event_after_cb):
+ * lib/widgets/ephy-autocompletion-window.h:
+ * lib/widgets/ephy-location-entry.c:
+ (ephy_location_entry_class_init),
+ (ephy_location_entry_activate_cb),
+ (ephy_location_entry_set_autocompletion),
+ (ephy_location_entry_autocompletion_window_url_activated_cb),
+ (ephy_location_entry_list_event_after_cb):
+ * lib/widgets/ephy-location-entry.h:
+ * src/bookmarks/ephy-bookmarks.c: (options_skip_spaces),
+ (options_find_value_end), (options_find_next_option),
+ (smart_url_options_get), (get_smarturl_only),
+ (ephy_bookmarks_solve_smart_url):
+ * src/bookmarks/ephy-bookmarks.h:
+ * src/toolbar.c: (toolbar_location_url_activate_cb),
+ (toolbar_setup_location_entry):
+
+ Hide views when empty, fix sizing to deal with
+ visibility.
+ Make bookmarks open correctly.
+ Add some smart bookmarks solving code.
+
+2002-12-21 Marco Pesenti Gritti <marco@it.gnome.org>
+
+ * data/Makefile.am:
+ * data/epiphany.schemas.in:
+ * embed/mozilla/Makefile.am:
+ * embed/mozilla/MozRegisterComponents.cpp:
+ * embed/mozilla/StartHereProtocolHandler.cpp:
+ * embed/mozilla/StartHereProtocolHandler.h:
+ * lib/ephy-gui.c: (shift_color_component),
+ (ephy_gui_rgb_shift_color), (rgb16_to_rgb),
+ (ephy_gui_gdk_color_to_rgb), (ephy_gui_gdk_rgb_to_color):
+ * lib/ephy-gui.h:
+ * lib/widgets/ephy-autocompletion-window.c:
+ (ephy_autocompletion_window_init_widgets):
+ * src/bookmarks/ephy-bookmarks.c:
+ (ephy_bookmarks_autocompletion_source_foreach):
+ * src/popup-commands.c: (popup_cmd_add_bookmark):
+
+ Use a darker color for the actions part of the
+ autocompletion window.
+ Add a (sucky) start-here: page and use it as
+ default homepage.
+
+2002-12-20 Marco Pesenti Gritti <marco@it.gnome.org>
+
+ * embed/global-history.c: (history_add_url_to_list),
+ (global_history_get_urls_list),
+ (global_history_autocompletion_source_foreach_aux),
+ (global_history_autocompletion_source_foreach):
+ * lib/ephy-autocompletion-source.c:
+ (ephy_autocompletion_source_base_init):
+ * lib/ephy-autocompletion-source.h:
+ * lib/ephy-autocompletion.c:
+ (ephy_autocompletion_get_common_prefix),
+ (ephy_autocompletion_update_matches),
+ (ephy_autocompletion_update_matches_full_item),
+ (ephy_autocompletion_update_matches_full),
+ (ephy_autocompletion_compare_scores_and_alpha),
+ (ephy_autocompletion_sort_by_score):
+ * lib/ephy-autocompletion.h:
+ * lib/ephy-filesystem-autocompletion.c:
+ (ephy_filesystem_autocompletion_autocompletion_source_foreach):
+ * lib/widgets/ephy-autocompletion-window.c:
+ (ephy_autocompletion_window_finalize_impl),
+ (ephy_autocompletion_window_init_widgets),
+ (ephy_autocompletion_window_selection_changed_cb),
+ (ephy_autocompletion_window_selection_add_selected),
+ (ephy_autocompletion_window_get_dimensions),
+ (ephy_autocompletion_window_fill_store_chunk),
+ (ephy_autocompletion_window_show):
+ * src/bookmarks/ephy-bookmarks.c: (ephy_bookmarks_get_type),
+ (ephy_bookmarks_autocompletion_source_set_basic_key),
+ (ephy_bookmarks_autocompletion_source_foreach),
+ (ephy_bookmarks_emit_data_changed),
+ (ephy_bookmarks_autocompletion_source_init),
+ (bookmarks_removed_cb), (ephy_bookmarks_init),
+ (ephy_bookmarks_add):
+ * src/bookmarks/ephy-bookmarks.h:
+ * src/ephy-shell.c: (ephy_shell_get_autocompletion):
+ * src/window-commands.c: (window_cmd_bookmarks_add_default):
+
+ Begin to implement smarter location entry. Now it looks
+ for bookmarks/keywords and show them by title.
+ Urls are showed just as urls (no more title).
+ At the bottom you can select smartbookmarks in a mozilla
+ like way (how do you add smb ? just edit xml for now ;)).
+ It's still incomplete but prolly it's not going to be all
+ the work I thought at beginning.
+
+2002-12-20 Marco Pesenti Gritti <marco@it.gnome.org>
+
+ * src/bookmarks/ephy-bookmarks-editor.c: (diff_keywords),
+ (update_keywords):
+ * src/bookmarks/ephy-bookmarks.c: (ephy_bookmarks_find_keyword):
+ * src/bookmarks/ephy-keywords-entry.c: (try_to_expand_keyword):
+
+ Fix several keywords bugs. Should start to get usable.
+
+2002-12-19 Marco Pesenti Gritti <marco@it.gnome.org>
+
+ * src/bookmarks/ephy-bookmarks-editor.c: (build_editing_table):
+ * src/bookmarks/ephy-bookmarks.c:
+ (ephy_bookmarks_clean_empty_keywords), (keywords_added_cb),
+ (keywords_removed_cb), (bookmarks_removed_cb),
+ (ephy_bookmarks_init), (ephy_bookmarks_finalize),
+ (ephy_bookmarks_find_keyword), (ephy_bookmarks_set_keyword),
+ (ephy_bookmarks_unset_keyword):
+ * src/bookmarks/ephy-keywords-entry.c:
+ (ephy_keywords_entry_class_init), (try_to_expand_keyword),
+ (entry_would_have_inserted_characters),
+ (ephy_keywords_entry_key_press), (ephy_keywords_entry_init):
+ * src/bookmarks/ephy-keywords-entry.h:
+
+ Complete autocompletion implementation.
+ Rewrite keywords removing code. Still bad bugs
+ but getting better.
+
+2002-12-16 Marco Pesenti Gritti <marco@it.gnome.org>
+
+ * configure.in:
+ * src/bookmarks/Makefile.am:
+ * src/bookmarks/ephy-bookmarks-editor.c: (update_keywords),
+ (keywords_changed_cb), (build_editing_table):
+ * src/bookmarks/ephy-bookmarks.c: (keywords_added_cb),
+ (keywords_removed_cb), (partial_match_equal),
+ (ephy_bookmarks_init), (ephy_bookmarks_finalize),
+ (ephy_bookmarks_find_keyword), (ephy_bookmarks_set_keyword),
+ (ephy_bookmarks_unset_keyword):
+ * src/bookmarks/ephy-bookmarks.h:
+ * src/bookmarks/ephy-node-view.c: (ephy_node_view_select_node):
+ * src/bookmarks/ephy-node-view.h:
+
+ Fix some keywords bugs and start working on autocompletion
+
+2002-12-15 Marco Pesenti Gritti <marco@it.gnome.org>
+
+ * src/bookmarks/ephy-bookmarks-editor.c:
+ (ephy_bookmarks_editor_construct):
+ * src/bookmarks/ephy-bookmarks.c: (ephy_bookmarks_save),
+ (add_to_favorites), (history_site_visited_cb),
+ (ephy_bookmarks_finalize):
+ * src/ephy-favorites-menu.c: (ephy_favorites_menu_set_path),
+ (ephy_favorites_menu_verb_cb), (ephy_favorites_menu_rebuild),
+ (ephy_favorites_menu_update):
+ * src/ephy-window.c: (ephy_window_init):
+
+ Make favorites really work
+
+2002-12-15 Marco Pesenti Gritti <marco@it.gnome.org>
+
+ * TODO:
+ * embed/global-history.c: (global_history_get_item):
+ * embed/global-history.h:
+ * src/bookmarks/ephy-bookmarks.c: (ephy_bookmarks_save),
+ (get_history_item_score), (compute_lower_fav),
+ (ephy_bookmarks_update_favorites), (add_to_favorites),
+ (update_favorites_menus), (history_site_visited_cb),
+ (keywords_added_cb), (keywords_removed_cb), (favorites_added_cb),
+ (favorites_removed_cb), (ephy_bookmarks_init),
+ (ephy_bookmarks_finalize), (ephy_bookmarks_get_keyword):
+
+ Complete favorites implementation, still buggy.
+
+2002-12-14 Marco Pesenti Gritti <marco@it.gnome.org>
+
+ * data/ui/epiphany-ui.xml.in:
+ * embed/global-history.c: (global_history_class_init),
+ (global_history_visited):
+ * embed/global-history.h:
+ * src/Makefile.am:
+ * src/bookmarks/ephy-bookmarks.c: (history_site_visited_cb),
+ (ephy_setup_history_notifiers), (bookmarks_added_cb),
+ (bookmarks_removed_cb), (ephy_bookmarks_init),
+ (ephy_bookmarks_finalize), (ephy_bookmarks_get_favorites):
+ * src/bookmarks/ephy-bookmarks.h:
+ * src/ephy-favorites-menu.c: (ephy_favorites_menu_class_init),
+ (ephy_favorites_menu_init), (ephy_favorites_menu_finalize_impl),
+ (ephy_favorites_menu_set_property),
+ (ephy_favorites_menu_get_property), (ephy_favorites_menu_new),
+ (ephy_favorites_menu_set_path), (ephy_favorites_menu_rebuild),
+ (ephy_favorites_menu_update), (ephy_favorites_menu_verb_cb):
+ * src/ephy-favorites-menu.h:
+ * src/ephy-window.c: (ephy_window_init),
+ (update_favorites_control), (ephy_window_update_control):
+ * src/ephy-window.h:
+ * src/window-recent-history-menu.c:
+ * src/window-recent-history-menu.h: some work on favorites,
+ still not working quite well
+
+2002-12-14 Marco Pesenti Gritti <marco@it.gnome.org>
+
+ * src/bookmarks/ephy-bookmarks-editor.c:
+ (ephy_bookmarks_editor_node_selected_cb), (diff_keywords),
+ (update_keywords), (keywords_entry_changed_cb), (bookmarks_filter),
+ (keyword_node_selected_cb), (build_search_box),
+ (ephy_bookmarks_editor_construct):
+ * src/bookmarks/ephy-bookmarks.c: (ephy_bookmarks_save),
+ (ephy_bookmarks_init), (ephy_bookmarks_set_keyword):
+ * src/bookmarks/ephy-node-view.c: (ephy_node_view_set_browse_mode):
+ * src/bookmarks/ephy-node-view.h: complete keyword implementation,
+ still buggy
+
+2002-12-14 Marco Pesenti Gritti <marco@it.gnome.org>
+
+ * src/bookmarks/ephy-bookmarks-editor.c:
+ (ephy_bookmarks_editor_finalize), (update_keywords),
+ (keywords_entry_changed_cb), (search_entry_changed_cb),
+ (build_search_box), (ephy_bookmarks_editor_construct):
+ * src/bookmarks/ephy-bookmarks.c: (ephy_bookmarks_save),
+ (ephy_bookmarks_init), (ephy_bookmarks_finalize),
+ (ephy_bookmarks_add_keyword), (ephy_bookmarks_get_keyword),
+ (ephy_bookmarks_set_keyword), (ephy_bookmarks_get_keywords):
+ * src/bookmarks/ephy-bookmarks.h:
+ * src/bookmarks/ephy-tree-model-node.c:
+ (ephy_tree_model_node_get_column_type),
+ (ephy_tree_model_node_get_value),
+ (ephy_tree_model_node_column_get_type):
+ * src/bookmarks/ephy-tree-model-node.h:
+ * src/ephy-window.c: some work on keywords implementation,
+ still not working
+
+2002-12-13 Marco Pesenti Gritti <marco@it.gnome.org>
+
+ * data/glade/epiphany.glade:
+ * data/glade/prefs-dialog.glade:
+ * data/ui/epiphany-ui.xml.in:
+ * embed/downloader-view.c: (get_selected_row),
+ (download_dialog_abort_cb):
+ * src/Makefile.am:
+ * src/ephy-tab.c: (ephy_tab_location_cb), (ephy_tab_title_cb):
+ * src/ephy-window.c: (ephy_window_init), (ephy_window_finalize),
+ (ephy_window_get_toolbar):
+ * src/ephy-window.h:
+ * src/history-dialog.c: (each_url_get_data_binder):
+ * src/language-editor.c:
+ (language_editor_remove_button_clicked_cb):
+ * src/pdm-dialog.c: (cookies_treeview_selection_changed_cb),
+ (action_treeview_selection_changed_cb),
+ (pdm_dialog_remove_button_clicked_cb), (setup_action),
+ (pdm_dialog_init),
+ (pdm_dialog_cookies_properties_button_clicked_cb):
+ * src/window-commands.c:
+ * src/window-commands.h:
+ * src/window-recent-history.c:
+ * src/window-recent-history.h: some menu rehashing, remove recent
+ history to be replaced by favourites. Fix all tree views.
+
+2002-12-12 Marco Pesenti Gritti <marco@it.gnome.org>
+
+ * embed/find-dialog.c: (impl_show): grab focus on the entry
+
+2002-12-08 Marco Pesenti Gritti <marco@it.gnome.org>
+
+ * src/bookmarks/ephy-bookmarks-editor.c:
+ (ephy_bookmarks_editor_node_selected_cb), (update_prop_from_entry):
+
+ Fix some memory corruption.
+
+2002-12-08 Marco Pesenti Gritti <marco@it.gnome.org>
+
+ * TODO:
+ * src/bookmarks/ephy-bookmarks-editor.c:
+ (ephy_bookmarks_editor_node_selected_cb), (update_prop_from_entry),
+ (title_entry_changed_cb), (keywords_entry_changed_cb),
+ (build_editing_table), (ephy_bookmarks_editor_construct):
+ * src/bookmarks/ephy-bookmarks.h:
+ * src/bookmarks/ephy-node-view.c: (ephy_node_view_class_init),
+ (ephy_node_view_selection_changed_cb), (ephy_node_view_construct):
+ * src/bookmarks/ephy-node-view.h:
+
+ Add ability to edit title and keywords (useless atm).
+
+2002-12-08 Marco Pesenti Gritti <marco@it.gnome.org>
+
+ * Makefile.am:
+ * README:
+ * configure.in:
+ * embed/mozilla/Makefile.am:
+ * lib/Makefile.am:
+ * po/.cvsignore:
+ * po/POTFILES.in:
+
+ Make it pass distcheck.
+
+ * src/ephy-tab.c: (ephy_tab_dom_mouse_down_cb):
+
+ Reintroduce page load on url pasting.
+
+2002-12-08 Marco Pesenti Gritti <marco@it.gnome.org>
+
+ * src/bookmarks/Makefile.am:
+ * src/bookmarks/ephy-bookmarks-editor.c:
+ (ephy_bookmarks_editor_node_activated_cb),
+ (ephy_bookmarks_editor_response_cb),
+ (ephy_bookmarks_editor_construct), (ephy_bookmarks_editor_new):
+ * src/bookmarks/ephy-bookmarks-editor.h:
+ * src/bookmarks/ephy-bookmarks.c: (ephy_bookmarks_save),
+ (ephy_bookmarks_finalize), (ephy_bookmarks_add):
+ * src/bookmarks/ephy-node-view.c:
+ (ephy_node_view_row_activated_cb), (ephy_node_view_construct),
+ (ephy_node_view_new), (ephy_node_view_init), (get_selection),
+ (ephy_node_view_get_selection), (ephy_node_view_remove):
+ * src/bookmarks/ephy-node-view.h:
+ * src/bookmarks/ephy-tree-model-node.c: (ephy_tree_model_node_new):
+ * src/ephy-shell.c: (ephy_shell_finalize):
+ * src/window-commands.c: (window_cmd_bookmarks_edit):
+
+ You can now at least add bookmarks to a list
+
+2002-12-07 Marco Pesenti Gritti <marco@it.gnome.org>
+
+ * embed/mozilla/EphyWrapper.cpp:
+ * embed/mozilla/EphyWrapper.h: remove some unused code,
+ should build with mozilla head again
+
+2002-12-06 Marco Pesenti Gritti <marco@it.gnome.org>
+
+ * src/bookmarks/ephy-bookmarks-editor.c:
+ (ephy_bookmarks_editor_class_init),
+ (ephy_bookmarks_editor_construct), (ephy_bookmarks_editor_new),
+ (ephy_bookmarks_editor_set_property),
+ (ephy_bookmarks_editor_get_property), (ephy_bookmarks_editor_init):
+ * src/bookmarks/ephy-bookmarks.c: (ephy_bookmarks_load),
+ (ephy_bookmarks_init), (ephy_bookmarks_finalize),
+ (ephy_bookmarks_add), (ephy_bookmarks_get_bookmarks):
+ * src/bookmarks/ephy-bookmarks.h:
+ * src/window-commands.c: (window_cmd_bookmarks_edit),
+ (window_cmd_bookmarks_add_default): more bookmarks work
+
+2002-12-05 Bastien Nocera <hadess@hadess.net>
+
+ * src/ephy-main.c: (ephy_main_start): get the Bonobo warning go away and Ephy to
+ just actually work
+
+2002-12-05 Marco Pesenti Gritti <marco@it.gnome.org>
+
+ * embed/mozilla/FilePicker.cpp: actually parent the file picker
+ * src/Makefile.am:
+ * src/bookmarks/ephy-bookmarks-editor.c:
+ (ephy_bookmarks_editor_class_init), (ephy_bookmarks_editor_new),
+ (ephy_bookmarks_editor_construct),
+ (ephy_bookmarks_editor_set_object_property),
+ (ephy_bookmarks_editor_get_object_property),
+ (ephy_bookmarks_editor_init):
+ * src/bookmarks/ephy-bookmarks-editor.h:
+ * src/bookmarks/ephy-node-view.c: (ephy_node_view_set_property),
+ (ephy_node_view_construct), (ephy_node_view_add_column),
+ (ephy_node_view_init):
+ * src/ephy-shell.c: (ephy_shell_init), (ephy_shell_get_bookmarks):
+ * src/ephy-shell.h:
+ * src/window-commands.c: (window_cmd_bookmarks_edit):
+ more useless bookmarks work
+
+2002-12-01 Marco Pesenti Gritti <marco@it.gnome.org>
+
+ * src/bookmarks/Makefile.am:
+ * src/bookmarks/eggtreemodelfilter.c:
+ * src/bookmarks/eggtreemodelfilter.h:
+ * src/bookmarks/ephy-bookmarks-editor.c:
+ * src/bookmarks/ephy-bookmarks-editor.h:
+ * src/bookmarks/ephy-node-view.c:
+ * src/bookmarks/ephy-node-view.h: more bookmarks work
+
+2002-11-30 Marco Pesenti Gritti <marco@it.gnome.org>
+
+ * embed/ephy-embed.h:
+ * embed/find-dialog.c: (find_dialog_go_next),
+ (find_dialog_go_prev), (find_next_button_clicked_cb),
+ (find_prev_button_clicked_cb), (find_entry_activate_cb):
+ * embed/find-dialog.h:
+ * embed/mozilla/EphyWrapper.cpp:
+ * embed/mozilla/EphyWrapper.h:
+ * embed/mozilla/Makefile.am:
+ * embed/mozilla/mozilla-embed.cpp:
+ * src/bookmarks/Makefile.am:
+ * src/bookmarks/ephy-bookmarks.h:
+ * src/bookmarks/ephy-node-filter.c:
+ * src/bookmarks/ephy-node-filter.h:
+ * src/bookmarks/ephy-node.c: (ephy_node_class_init):
+ * src/bookmarks/ephy-tree-model-node.c:
+ * src/bookmarks/ephy-tree-model-node.h:
+ * src/window-commands.c: fix dialog/typeahead find
+ interaction. More infrastucture bookmarks work.
+
+2002-11-29 Marco Pesenti Gritti <marco@it.gnome.org>
+
+ * lib/ephy-string.c:
+ * lib/ephy-string.h: remove no more used helper
+ * src/window-recent-history-menu.c:
+ (ephy_window_recent_history_menu_rebuild): correctly
+ encode xml strings
+
+2002-11-28 Marco Pesenti Gritti <marco@it.gnome.org>
+
+ * configure.in:
+ * lib/Makefile.am:
+ * lib/ephy-string.c: (ephy_string_store_time_in_string),
+ (ephy_string_time_to_string):
+ * lib/ephy-string.h:
+ * src/Makefile.am:
+ * src/bookmarks/Makefile.am:
+ * src/bookmarks/ephy-bookmarks.c:
+ * src/bookmarks/ephy-bookmarks.h:
+ * src/bookmarks/ephy-node.c:
+ * src/bookmarks/ephy-node.h:
+ * src/ephy-shell.c:
+ * src/history-dialog.c: (history_dialog_update_host_item),
+ (history_dialog_update_url_item): some configure cleanups,
+ some bookmarks architecture stuff. Credits to rhythmbox
+ developers.
+
+2002-11-27 Marco Pesenti Gritti <marco@it.gnome.org>
+
+ * data/epiphany.schemas.in:
+ * embed/ephy-embed-event.h:
+ * embed/ephy-embed-persist.c: (ephy_embed_persist_new):
+ * embed/ephy-embed-popup.c: (setup_element_menu),
+ (setup_document_menu):
+ * embed/mozilla/Makefile.am: fix favicons, remove mozilla-config.h
+ and use the old hack. Damn we need a real fix for this.
+
+2002-11-27 Marco Pesenti Gritti <marco@it.gnome.org>
+
+ * data/glade/toolbar-editor.glade:
+ * lib/toolbar/ephy-toolbar-editor.c: (update_arrows_sensitivity),
+ (ephy_tb_editor_treeview_selection_changed_cb),
+ (ephy_tb_editor_setup_treeview): fix arrows sensitivity in the
+ toolbar editor
+
+2002-11-27 Marco Pesenti Gritti <marco@it.gnome.org>
+
+ * README: wrote
+ * src/ephy-shell.c: (ephy_init_services): add the monitor on the
+ right gconf dir
+ * src/history-dialog.c: fix gcon paths
+
+2002-11-27 Marco Pesenti Gritti <marco@it.gnome.org>
+
+ * data/art/epiphany-secure.png:
+ * data/art/epiphany-unsecure.png: resize to 18x18
+ * configure.in:
+ * embed/Makefile.am:
+ * embed/mozilla/Makefile.am:
+ * src/Makefile.am:
+ * lib/Makefile.am:
+ * lib/toolbar/Makefile.am:
+ * lib/widgets/Makefile.am: enable werror
+ * lib/ephy-file-helpers.c: missing includes
+ * lib/widgets/ephy-location-entry.c: disable completion_to by default
+ (ephy_location_entry_key_press_event_cb):
+ * src/statusbar.c: (statusbar_set_security_state): really fix it
+
+2002-11-27 Marco Pesenti Gritti <marco@it.gnome.org>
+
+ * data/GNOME_Epiphany_NautilusView.server.in:
+ * data/epiphany.schemas.in:
+ * data/glade/epiphany.glade:
+ * data/ui/epiphany-ui.xml.in:
+ * data/ui/nautilus-epiphany-view.xml.in:
+ * embed/global-history.c: (history_save):
+ * embed/mozilla/ContentHandler.cpp:
+ * lib/ephy-file-helpers.c: (ephy_ensure_dir_exists):
+ * lib/ephy-file-helpers.h:
+ * src/ephy-shell.c: (ephy_shell_init):
+ * src/history-dialog.c: (history_dialog_set_embedded):
+ * src/pdm-dialog.c: (pdm_dialog_init):
+ * src/session.c: (crashed_resume_dialog):
+ * src/statusbar.c: (statusbar_set_security_state):
+ Fix a few typos, get rid of mime handlers list,
+ reimplement security icon
+
+2002-11-26 Marco Pesenti Gritti <marco@it.gnome.org>
+
+ * Checked in initial codebase.
diff --git a/HACKING b/HACKING
new file mode 100644
index 000000000..430e0ff7b
--- /dev/null
+++ b/HACKING
@@ -0,0 +1,16 @@
+In order to keep the code nice and clean we have a few requirements you'll
+need to stick to in order to get your patch accepted:
+
+- use 8-space tabs for indentation
+- curly brackets are on a new line
+- please compare with NULL or FALSE isntead of using "!"
+- callback functions have a suffix _cb
+
+ Comment blocks are written like this:
+
+/**
+ * bla_bla_cb: This is an example comment block
+ */
+
+Do NOT commit to this module without permission from me
+(marco@it.gnome.org)
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 000000000..b42a17ac4
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,182 @@
+Basic Installation
+==================
+
+ These are generic installation instructions.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, a file
+`config.cache' that saves the results of its tests to speed up
+reconfiguring, and a file `config.log' containing compiler output
+(useful mainly for debugging `configure').
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If at some point `config.cache'
+contains results you don't want to keep, you may remove or edit it.
+
+ The file `configure.in' is used to create `configure' by a program
+called `autoconf'. You only need `configure.in' if you want to change
+it or regenerate `configure' using a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system. If you're
+ using `csh' on an old version of System V, you might need to type
+ `sh ./configure' instead to prevent `csh' from trying to execute
+ `configure' itself.
+
+ Running `configure' takes awhile. While running, it prints some
+ messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Optionally, type `make check' to run any self-tests that come with
+ the package.
+
+ 4. Type `make install' to install the programs and any data files and
+ documentation.
+
+ 5. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'. To also remove the
+ files that `configure' created (so you can compile the package for
+ a different kind of computer), type `make distclean'. There is
+ also a `make maintainer-clean' target, but that is intended mainly
+ for the package's developers. If you use it, you may have to get
+ all sorts of other programs in order to regenerate files that came
+ with the distribution.
+
+Compilers and Options
+=====================
+
+ Some systems require unusual options for compilation or linking that
+the `configure' script does not know about. You can give `configure'
+initial values for variables by setting them in the environment. Using
+a Bourne-compatible shell, you can do that on the command line like
+this:
+ CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
+
+Or on systems that have the `env' program, you can do it like this:
+ env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
+
+Compiling For Multiple Architectures
+====================================
+
+ You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+ If you have to use a `make' that does not supports the `VPATH'
+variable, you have to compile the package for one architecture at a time
+in the source code directory. After you have installed the package for
+one architecture, use `make distclean' before reconfiguring for another
+architecture.
+
+Installation Names
+==================
+
+ By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc. You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+ In addition, if you use an unusual directory layout you can give
+options like `--bindir=PATH' to specify different values for particular
+kinds of files. Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+ Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+ There may be some features `configure' can not figure out
+automatically, but needs to determine by the type of host the package
+will run on. Usually `configure' can figure that out, but if it prints
+a message saying it can not guess the host type, give it the
+`--host=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name with three fields:
+ CPU-COMPANY-SYSTEM
+
+See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the host type.
+
+ If you are building compiler tools for cross-compiling, you can also
+use the `--target=TYPE' option to select the type of system they will
+produce code for and the `--build=TYPE' option to select the type of
+system on which you are compiling the package.
+
+Sharing Defaults
+================
+
+ If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Operation Controls
+==================
+
+ `configure' recognizes the following options to control how it
+operates.
+
+`--cache-file=FILE'
+ Use and save the results of the tests in FILE instead of
+ `./config.cache'. Set FILE to `/dev/null' to disable caching, for
+ debugging `configure'.
+
+`--help'
+ Print a summary of the options to `configure', and exit.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made. To
+ suppress all normal output, redirect it to `/dev/null' (any error
+ messages will still be shown).
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`--version'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`configure' also accepts some other, not widely useful, options.
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 000000000..068ec8e39
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,8 @@
+## Process this file with automake to produce Makefile.in
+
+SUBDIRS = lib embed src data po
+
+EXTRA_DIST = \
+ intltool-merge.in \
+ intltool-update.in \
+ intltool-extract.in
diff --git a/NEWS b/NEWS
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/NEWS
diff --git a/README b/README
new file mode 100644
index 000000000..467e18dc0
--- /dev/null
+++ b/README
@@ -0,0 +1,121 @@
+Epiphany is a GNOME web browser based on the mozilla
+rendering engine.
+The name meaning:
+"An intuitive grasp of reality through
+something (as an event) usually simple and striking"
+
+MANIFESTO
+
+A web browser is more than an application, it is a way of thinking, it is
+a way of seeing the world. Epiphany's principles are simplicity and standards
+compliance.
+
+Simplicity:
+
+While Mozilla has an excellent rendering engine, its default
+XUL-based interface is considered to be overcrowded and bloated. Furthermore,
+on slower processors even trivial tasks such as pulling down a menu is less
+than responsive.
+
+Epiphany aims to utilize the simplest interface possible for a browser. Keep
+in mind that simple does not necessarily mean less powerful. We believe
+the commonly used browsers of today are too big, buggy, and bloated. Epiphany
+addresses simplicity with a small browser designed for the web -- not mail,
+newsgroups, file management, instant messenging or coffee making. The UNIX
+philosophy is to design small tools that do one thing, and do it well.
+
+Epiphany also address simplicity with modularity to make a light and powerful
+application. If something can be implemented using external applications
+or components, we use it rather than wasting resources in the web browser.
+Integration will be achived with CORBA, Bonobo, and the ever popular
+command line.
+
+Mail will be handled with your favorite e-mail application (Evolution, pine,
+mutt, balsa, pronto, whatever).
+
+Standards compliance:
+
+The introduction of non-standard features in browsers could make it difficult
+or impossible to use alternative products like Epiphany if developers embrace
+them. Alternative (standards complying) browsers could not be able to
+fully access web sites making use of these features. The success of
+non-standard features can ultimately lead to forcing one browser, on
+one platform to dominate the market.
+
+Standards compliance ensures the freedom of choice. Epiphany aims to achieve
+this.
+
+USER INTERFACE LINES
+
+- HIG compliance
+
+Epiphany is going to follow version 1.0 of the gnome
+user guidelines. Unless there are very seriuos reasons to make an
+exception not following it will be considered a bug.
+"I follow the HIG only when I like it" is not a legitimate approach.
+Any areas where we diverge from the HIG will communicated
+to the HIG team for future consideration.
+
+- Gnome integration
+
+Epiphany's main goal is to be integrated with the gnome desktop.
+We dont aim to make epiphany usable outside Gnome. If someone will like
+to use it anyway, it's just a plus. Ex: Making people happy that
+don't have control center installed is not a good reason
+to have mime configuration in epiphany itself.
+
+- Simple design
+
+Feature bloat and user interface clutter is evil :)
+
+- Preferences
+
+We will follow the new gnome policy about preferences.
+I think Havoc Pennington already explained it a lot
+better than I could ever do.
+http://www106.pair.com/rhp/free-software-ui.html
+
+- User target
+
+We target non-technical users by design.
+This happens to be 90% of the user population.
+(Technical details should not exposed in the interface)
+We target web users, we dont directly target web developers.
+A few geek-oriented feautures can be kept as
+long as they are non-obtrusive.
+
+REQUIREMENTS
+
+You will need a complete installation of Gnome 2.2 desktop.
+Mozilla API is not stable. I'll be keeping in sync epiphany cvs
+head with mozilla cvs head.
+The required mozilla version will be specified in the
+release notes.
+
+HOW TO HELP
+
+You can report new bugs on http://epiphany.mozdev.org/bugs.html.
+Feel free to send patches.
+
+About new feautures I'll just quote Metacity FAQ.
+
+Q: Will you add my feature?
+
+A: If it makes sense to turn on unconditionally,
+ or is genuinely a harmless preference that I would not
+ be embarrassed to put in a simple, uncluttered, user-friendly
+ configuration dialog.
+
+ If the only rationale for your feature is that other
+ [browsers] have it, or that you are personally used to it, or something
+ like that, then I will not be impressed. [Epiphany] is firmly in the
+ "choose good defaults" camp rather than the "offer 6 equally broken
+ ways to do it, and let the user pick one" camp.
+
+ Don't let this discourage patches and fixes - I love those. ;-)
+ Just be prepared to hear the above objections if your patch
+ adds some crack-ridden configuration option.
+
+CONTACTS
+
+Marco Pesenti Gritti <marco@it.gnome.org>
diff --git a/TODO b/TODO
new file mode 100644
index 000000000..fb0f92c9d
--- /dev/null
+++ b/TODO
@@ -0,0 +1,17 @@
+To do:
+
+- favicons doesnt work anymore
+- ephy-dnd.c we still need it ?
+- implement phoenix like popup blocking
+- urls like www.gnome.org and gnome.org should use same folder in history
+- history scoring for autocompletion
+
+Done:
+
+* simpler crash recover
+* open url on middle click
+* tree views are borked, maybe the new api doesnt return a list of rows
+* dont autocomplete on www.
+* simplify/clean autocompletion entry code
+* favicons should not be fetched on load end
+* open bookmarks, close galeon -> crash
diff --git a/acconfig.h b/acconfig.h
new file mode 100644
index 000000000..ee45fadb9
--- /dev/null
+++ b/acconfig.h
@@ -0,0 +1,6 @@
+#undef ENABLE_NLS
+#undef HAVE_CATGETS
+#undef HAVE_GETTEXT
+#undef GETTEXT_PACKAGE
+#undef HAVE_LC_MESSAGES
+#undef NAUTILUS_PREFIX
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 000000000..4eeaa4ed9
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,19 @@
+#!/bin/sh
+# Run this to generate all the initial makefiles, etc.
+
+srcdir=`dirname $0`
+test -z "$srcdir" && srcdir=.
+
+PKG_NAME="epiphany"
+
+(test -f $srcdir/configure.in) || {
+ echo -n "**Error**: Directory "\`$srcdir\'" does not look like the"
+ echo " top-level $PKG_NAME directory"
+ exit 1
+}
+
+which gnome-autogen.sh || {
+ echo "You need to install gnome-common from the GNOME CVS"
+ exit 1
+}
+USE_GNOME2_MACROS=1 . gnome-autogen.sh
diff --git a/configure.in b/configure.in
new file mode 100644
index 000000000..34bfb362b
--- /dev/null
+++ b/configure.in
@@ -0,0 +1,171 @@
+dnl Process this file with autoconf to produce a configure script.
+
+AC_INIT(configure.in)
+AC_PREREQ(2.50)
+
+GCONF_REQUIRED=1.0.4
+GDK_PIXBUF_REQUIRED=0.13.0
+GLIB_REQUIRED=1.2.9
+LIBGLADE_REQUIRED=0.13
+GNOME_LIBS_REQUIRED=1.2.11
+GNOME_REQUIRED=1.2.8
+GNOME_VFS_REQUIRED=1.0.1
+GTK_REQUIRED=1.2.9
+LIBXML_REQUIRED=1.8.14
+OAF_REQUIRED=0.6.5
+ORBIT_REQUIRED=0.5.7
+MOZILLA_REQUIRED=1.1
+SCROLLKEEPER_REQUIRED=0.1.4
+
+AC_SUBST(SCROLLKEEPER_REQUIRED)
+AC_SUBST(GNOME_VFS_REQUIRED)
+AC_SUBST(LIBXML_REQUIRED)
+AC_SUBST(ORBIT_REQUIRED)
+AC_SUBST(LIBGLADE_REQUIRED)
+AC_SUBST(GNOME_LIBS_REQUIRED)
+AC_SUBST(MOZILLA_REQUIRED)
+
+AC_ENABLE_SHARED(yes)
+AC_ENABLE_STATIC(no)
+
+AM_INIT_AUTOMAKE(epiphany, 0.4.1)
+AM_CONFIG_HEADER(config.h)
+
+AM_PROG_LIBTOOL
+
+AC_ISC_POSIX
+AC_PROG_CC
+AC_PROG_CXX
+AM_PROG_CC_STDC
+AC_HEADER_STDC
+AC_PROG_INTLTOOL
+AC_PATH_PROG(GLIB_GENMARSHAL, glib-genmarshal)
+
+GNOME_COMPILE_WARNINGS(error)
+
+dnl ******************************
+dnl Nautilus View checking
+dnl ******************************
+
+build_nautilus_view=no
+AC_ARG_ENABLE(nautilus-view, [ --enable-nautilus-view (auto,yes,no)
+ Enable Nautilus View Galeon Component])
+
+AC_MSG_CHECKING(if NautilusView Galeon component is wanted)
+if test "x$enable_nautilus_view" = "x" ; then
+ enable_nautilus_view=auto
+fi
+if test "x$enable_nautilus_view" = "xauto"; then
+ temptest=`pkg-config --cflags libnautilus 2> /dev/null`
+ if test "x$temptest" = "x" ; then
+ enable_nautilus_view=no
+ else
+ enable_nautilus_view=yes
+ fi
+fi
+if test "x$enable_nautilus_view" = "xyes"; then
+ dnl AC_DEFINE(ENABLE_NAUTILUS_VIEW)
+ nautilusview_pkgs=libnautilus
+fi
+AC_MSG_RESULT($enable_nautilus_view)
+AM_CONDITIONAL(ENABLE_NAUTILUS_VIEW, test "x$enable_nautilus_view" = "xyes")
+
+dnl See if nautilus is installed in other prefix than epiphany so that we can load
+dnl nautilus throbbers even then.
+dnl Maybe FIXME: make this check not require libnautilus.pc
+dnl
+nautilus_prefix=`pkg-config --variable=prefix libnautilus 2> /dev/null`
+if test "x${nautilus_prefix}" != "x"; then
+ if test "x${prefix}" = "xNONE"; then
+ epiphany_prefix="${ac_default_prefix}"
+ else
+ epiphany_prefix="${prefix}"
+ fi
+
+ dnl We already search for nautilus throbbers in epiphany prefix, don't add the
+ dnl same directory or we'd show the throbbers twice.
+ if test "x${nautilus_prefix}" != "x${epiphany_prefix}"; then
+ AC_DEFINE_UNQUOTED(NAUTILUS_PREFIX, "${nautilus_prefix}")
+ fi
+fi
+
+PKG_CHECK_MODULES(EPIPHANY_DEPENDENCY, gtk+-2.0 libxml-2.0 libgnomeui-2.0 libglade-2.0 bonobo-activation-2.0 ORBit-2.0 libglade-2.0 gnome-vfs-2.0 gnome-vfs-module-2.0 gconf-2.0 $nautilusview_pkgs)
+AC_SUBST(EPIPHANY_DEPENDENCY_CFLAGS)
+AC_SUBST(EPIPHANY_DEPENDENCY_LIBS)
+
+ORBIT_IDL="`$PKG_CONFIG --variable=orbit_idl ORBit-2.0`"
+AC_SUBST(ORBIT_IDL)
+
+LIBBONOBO_IDL="`$PKG_CONFIG --variable=idldir libbonobo-2.0`"
+AC_SUBST(LIBBONOBO_IDL)
+
+BONOBO_ACTIVATION_IDL="`$PKG_CONFIG --variable=idldir bonobo-activation-2.0`"
+AC_SUBST(BONOBO_ACTIVATION_IDL)
+
+PKG_CHECK_MODULES(MOZILLA_COMPONENT, mozilla-gtkmozembed)
+dnl AC_DEFINE(ENABLE_MOZILLA_EMBED)
+AC_SUBST(MOZILLA_COMPONENT_CFLAGS)
+AC_SUBST(MOZILLA_COMPONENT_LIBS)
+
+MOZILLA_INCLUDE_ROOT="`$PKG_CONFIG --variable=includedir mozilla-gtkmozembed`"
+AC_SUBST(MOZILLA_INCLUDE_ROOT)
+
+MOZILLA_HOME="`$PKG_CONFIG --variable=libdir mozilla-gtkmozembed`"
+AC_SUBST(MOZILLA_HOME)
+
+dnl whether to build with DEBUG defined
+AC_ARG_WITH(mozilla-debug,
+ [ --with-mozilla-debug Use a debug mozilla build],
+ CXXFLAGS="-DDEBUG $CXXFLAGS",)
+
+AC_ARG_ENABLE(cpp-rtti,
+ [ --enable-cpp-rtti Enable C++ RTTI (for cvs gcc)],,
+ enable_cpp_rtti=no)
+
+if test "x$enable_cpp_rtti" = "xno"; then
+ CXXFLAGS="-fno-rtti $CXXFLAGS"
+fi
+
+dnl Specify the gconf configuration source,
+dnl default to xml::$(sysconfdir)/gconf/gconf.xml.defaults
+
+AC_PATH_PROG(GCONFTOOL, gconftool-2, no)
+
+if test x"$GCONFTOOL" = xno; then
+ AC_MSG_ERROR([gconftool-2 executable not found in your path - should be installed with GConf])
+fi
+
+AM_GCONF_SOURCE_2
+
+dnl *******************************
+dnl Internationalization
+dnl *******************************
+dnl Add the languages which your application supports here.
+
+ALL_LINGUAS=""
+GETTEXT_PACKAGE=epiphany-2.0
+AC_SUBST(GETTEXT_PACKAGE)
+AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE,"$GETTEXT_PACKAGE")
+AM_GLIB_GNU_GETTEXT
+
+dnl uninstalled share dir to search data
+AC_DEFINE_UNQUOTED(SHARE_UNINSTALLED_DIR,"`pwd`/data",[path to source data dir])
+
+AC_OUTPUT([
+Makefile
+data/Makefile
+data/glade/Makefile
+data/art/Makefile
+data/ui/Makefile
+data/GNOME_Epiphany_NautilusView.server
+data/epiphany.schemas
+data/GNOME_Epiphany_Automation.server
+lib/Makefile
+lib/widgets/Makefile
+lib/toolbar/Makefile
+embed/Makefile
+embed/mozilla/Makefile
+src/Makefile
+src/bookmarks/Makefile
+po/Makefile.in
+])
diff --git a/data/.cvsignore b/data/.cvsignore
new file mode 100644
index 000000000..1f6558686
--- /dev/null
+++ b/data/.cvsignore
@@ -0,0 +1,5 @@
+GNOME_Epiphany_Automation.server
+GNOME_Epiphany_NautilusView.server
+Makefile
+Makefile.in
+epiphany.schemas
diff --git a/data/GNOME_Epiphany_Automation.server.in b/data/GNOME_Epiphany_Automation.server.in
new file mode 100644
index 000000000..05b831039
--- /dev/null
+++ b/data/GNOME_Epiphany_Automation.server.in
@@ -0,0 +1,20 @@
+<oaf_info>
+
+<oaf_server iid="OAFIID:GNOME_Epiphany_Automation_Factory" type="exe" location="epiphany">
+ <oaf_attribute name="repo_ids" type="stringv">
+ <item value="IDL:GNOME/ObjectFactory:1.0"/>
+ </oaf_attribute>
+ <oaf_attribute name="name" type="string" value="Epiphany automation"/>
+ <oaf_attribute name="description" type="string" value="Epiphany automation factory"/>
+</oaf_server>
+
+<oaf_server iid="OAFIID:GNOME_Epiphany_Automation" type="factory" location="OAFIID:GNOME_Epiphany_Automation_Factory">
+ <oaf_attribute name="repo_ids" type="stringv">
+ <item value="IDL:Bonobo/Unknown:1.0"/>
+ <item value="IDL:GNOME/EpiphanyAutomation:1.0"/>
+ </oaf_attribute>
+ <oaf_attribute name="name" type="string" _value="Epiphany automation"/>
+ <oaf_attribute name="description" type="string" value="Epiphany automation"/>
+</oaf_server>
+
+</oaf_info>
diff --git a/data/GNOME_Epiphany_NautilusView.server.in b/data/GNOME_Epiphany_NautilusView.server.in
new file mode 100644
index 000000000..8af14019b
--- /dev/null
+++ b/data/GNOME_Epiphany_NautilusView.server.in
@@ -0,0 +1,30 @@
+<oaf_info>
+
+<oaf_server iid="OAFIID:GNOME_Epiphany_NautilusViewFactory" type="exe" location="epiphany --nautilus-view">
+ <oaf_attribute name="repo_ids" type="stringv">
+ <item value="IDL:GNOME/ObjectFactory:1.0"/>
+ </oaf_attribute>
+ <oaf_attribute name="name" type="string" _value="Epiphany Nautilus view factory"/>
+ <oaf_attribute name="description" type="string" _value="Epiphany content view component's factory"/>
+</oaf_server>
+
+<oaf_server iid="OAFIID:GNOME_Epiphany_NautilusView" type="factory" location="OAFIID:GNOME_Epiphany_NautilusViewFactory">
+ <oaf_attribute name="repo_ids" type="stringv">
+ <item value="IDL:Bonobo/Unknown:1.0"/>
+ <item value="IDL:Bonobo/Control:1.0"/>
+ <item value="IDL:Nautilus/View:1.0"/>
+ </oaf_attribute>
+ <oaf_attribute name="name" type="string" _value="Epiphany Nautilus view"/>
+ <oaf_attribute name="description" type="string" _value="Epiphany content view component"/>
+ <oaf_attribute name="bonobo:supported_mime_types" type="stringv">
+ <item value="text/html"/>
+ <item value="text/xml"/>
+ <item value="x-directory/webdav"/>
+ <item value="x-directory/webdav-prefer-directory"/>
+ </oaf_attribute>
+ <oaf_attribute name="nautilus:view_as_name" type="string" _value="Web Page (Epiphany)"/>
+ <oaf_attribute name="nautilus:view_as_label" type="string" _value="View as Web Page (Epiphany)"/>
+ <oaf_attribute name="nautilus:viewer_label" type="string" _value="Web Page Viewer (Epiphany)"/>
+</oaf_server>
+
+</oaf_info>
diff --git a/data/Makefile.am b/data/Makefile.am
new file mode 100644
index 000000000..60b11c546
--- /dev/null
+++ b/data/Makefile.am
@@ -0,0 +1,29 @@
+SUBDIRS = ui art glade
+
+@INTLTOOL_SERVER_RULE@
+@INTLTOOL_DESKTOP_RULE@
+
+server_in_files = GNOME_Epiphany_Automation.server.in GNOME_Epiphany_NautilusView.server.in
+server_DATA = GNOME_Epiphany_Automation.server GNOME_Epiphany_NautilusView.server
+serverdir = $(libdir)/bonobo/servers
+
+schemadir = $(sysconfdir)/gconf/schemas
+schema_DATA = epiphany.schemas
+
+startheredir = $(pkgdatadir)
+starthere_DATA = start_here.html
+
+EXTRA_DIST = $(glade_DATA)
+
+install-data-local:
+ if test -z "$(DESTDIR)" ; then \
+ for p in $(schema_DATA) ; do \
+ GCONF_CONFIG_SOURCE=$(GCONF_SCHEMA_CONFIG_SOURCE) $(GCONFTOOL) --makefile-install-rule $(top_builddir)/data/$$p; \
+ done \
+ fi
+
+CLEANFILES = GNOME_Epiphany_Automation.server
+
+EXTRA_DIST = $(server_in_files) \
+ $(schema_DATA) \
+ $(starthere_DATA)
diff --git a/data/art/.cvsignore b/data/art/.cvsignore
new file mode 100644
index 000000000..282522db0
--- /dev/null
+++ b/data/art/.cvsignore
@@ -0,0 +1,2 @@
+Makefile
+Makefile.in
diff --git a/data/art/Makefile.am b/data/art/Makefile.am
new file mode 100644
index 000000000..f4f5c3b5f
--- /dev/null
+++ b/data/art/Makefile.am
@@ -0,0 +1,7 @@
+art_DATA = \
+ epiphany-secure.png \
+ epiphany-unsecure.png
+
+artdir = $(pkgdatadir)/art
+
+EXTRA_DIST = $(art_DATA)
diff --git a/data/art/epiphany-secure.png b/data/art/epiphany-secure.png
new file mode 100644
index 000000000..cbfc2d2b1
--- /dev/null
+++ b/data/art/epiphany-secure.png
Binary files differ
diff --git a/data/art/epiphany-unsecure.png b/data/art/epiphany-unsecure.png
new file mode 100644
index 000000000..5ee7106d9
--- /dev/null
+++ b/data/art/epiphany-unsecure.png
Binary files differ
diff --git a/data/epiphany.schemas.in b/data/epiphany.schemas.in
new file mode 100644
index 000000000..7450fefc7
--- /dev/null
+++ b/data/epiphany.schemas.in
@@ -0,0 +1,627 @@
+<gconfschemafile>
+ <schemalist>
+ <schema>
+ <key>/schemas/apps/epiphany/general/start_page</key>
+ <applyto>/apps/epiphany/general/start_page</applyto>
+ <owner>epiphany</owner>
+ <type>string</type>
+ <default>start-here:</default>
+ <locale name="C">
+ <short>Home page</short>
+ <long>URL for the user's home page. Displayed on start up
+ and when a new window or tab is created </long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/epiphany/general/newpage_type</key>
+ <applyto>/apps/epiphany/general/newpage_type</applyto>
+ <owner>epiphany</owner>
+ <type>int</type>
+ <default>0</default>
+ <locale name="C">
+ <short>New page type</short>
+ <long>Type of page to show when opening a new window or tab. Possible
+ values are: 0 (home page), 1 (last page), 2 (blank)</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/epiphany/find/match_case</key>
+ <applyto>/apps/epiphany/find/match_case</applyto>
+ <owner>epiphany</owner>
+ <type>bool</type>
+ <default>0</default>
+ <locale name="C">
+ <short>Match case for find in page</short>
+ <long>Match case for find in page.</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/epiphany/find/autowrap</key>
+ <applyto>/apps/epiphany/find/autowrap</applyto>
+ <owner>epiphany</owner>
+ <type>bool</type>
+ <default>1</default>
+ <locale name="C">
+ <short>Autowrap for find in page</short>
+ <long>For find in page, whether to start again at the beginning after
+ reaching the end of the page</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/epiphany/filtering/allow_popups</key>
+ <applyto>/apps/epiphany/filtering/allow_popups</applyto>
+ <owner>epiphany</owner>
+ <type>bool</type>
+ <default>true</default>
+ <locale name="C">
+ <short>Allow popups</short>
+ <long>Allow sites to open new windows using JavaScript (if JavaScript
+ is enabled).</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/epiphany/rendering/use_own_colors</key>
+ <applyto>/apps/epiphany/rendering/use_own_colors</applyto>
+ <owner>epiphany</owner>
+ <type>bool</type>
+ <default>false</default>
+ <locale name="C">
+ <short>Use own colors</short>
+ <long>Use your own colors instead of the colors the page
+ requests.</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/epiphany/rendering/use_own_fonts</key>
+ <applyto>/apps/epiphany/rendering/use_own_fonts</applyto>
+ <owner>epiphany</owner>
+ <type>bool</type>
+ <default>false</default>
+ <locale name="C">
+ <short>Use own fonts</short>
+ <long>Use your own fonts instead of the fonts the page
+ requests.</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/epiphany/rendering/background_color</key>
+ <applyto>/apps/epiphany/rendering/background_color</applyto>
+ <owner>epiphany</owner>
+ <type>string</type>
+ <default>#FFFFFF</default>
+ <locale name="C">
+ <short>Default page background color</short>
+ <long>Default page background color in #RRGGBB hex format.</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/epiphany/rendering/text_color</key>
+ <applyto>/apps/epiphany/rendering/text_color</applyto>
+ <owner>epiphany</owner>
+ <type>string</type>
+ <default>#000000</default>
+ <locale name="C">
+ <short>Default page text color</short>
+ <long>Default page text color in #RRGGBB hex format.</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/epiphany/rendering/visited_link_color</key>
+ <applyto>/apps/epiphany/rendering/visited_link_color</applyto>
+ <owner>epiphany</owner>
+ <type>string</type>
+ <default>#FF0000</default>
+ <locale name="C">
+ <short>Default visited link color</short>
+ <long>Default color for visited links in #RRGGBB hex format.</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/epiphany/rendering/unvisited_link_color</key>
+ <applyto>/apps/epiphany/rendering/unvisited_link_color</applyto>
+ <owner>epiphany</owner>
+ <type>string</type>
+ <default>#0000FF</default>
+ <locale name="C">
+ <short>Default unvisited link color</short>
+ <long>Default color for unvisited links in #RRGGBB hex format.</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/epiphany/rendering/underline_links</key>
+ <applyto>/apps/epiphany/rendering/underline_links</applyto>
+ <owner>epiphany</owner>
+ <type>bool</type>
+ <default>true</default>
+ <locale name="C">
+ <short>Underline links</short>
+ <long>Underline links.</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/epiphany/interface/open_in_tab</key>
+ <applyto>/apps/epiphany/interface/open_in_tab</applyto>
+ <owner>epiphany</owner>
+ <type>bool</type>
+ <default>false</default>
+ <locale name="C">
+ <short>Use tabs</short>
+ <long>Open in tabs by default.</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/epiphany/interface/popups_in_tab</key>
+ <applyto>/apps/epiphany/interface/popups_in_tab</applyto>
+ <owner>epiphany</owner>
+ <type>bool</type>
+ <default>false</default>
+ <locale name="C">
+ <short>Open popups in tabs</short>
+ <long>Open popups in tabs instead of new windows.</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/epiphany/interface/jumpto_tab</key>
+ <applyto>/apps/epiphany/interface/jumpto_tab</applyto>
+ <owner>epiphany</owner>
+ <type>bool</type>
+ <default>false</default>
+ <locale name="C">
+ <short>Jump to new tabs</short>
+ <long>Jump to new tabs.</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/epiphany/interface/show_toolbars_in_fullscreen</key>
+ <applyto>/apps/epiphany/interface/show_toolbars_in_fullscreen</applyto>
+ <owner>epiphany</owner>
+ <type>bool</type>
+ <default>1</default>
+ <locale name="C">
+ <short>Show toolbars in full screen mode</short>
+ <long>Show toolbars in full screen mode.</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/epiphany/interface/show_statusbar_in_fullscreen</key>
+ <applyto>/apps/epiphany/interface/show_statusbar_in_fullscreen</applyto>
+ <owner>epiphany</owner>
+ <type>bool</type>
+ <default>0</default>
+ <locale name="C">
+ <short>Show statusbar in full screen mode</short>
+ <long>Show statusbar in full screen mode.</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/epiphany/interface/show_sidebar_in_fullscreen</key>
+ <applyto>/apps/epiphany/interface/show_sidebar_in_fullscreen</applyto>
+ <owner>epiphany</owner>
+ <type>bool</type>
+ <default>0</default>
+ <locale name="C">
+ <short>Show sidebar in full screen mode</short>
+ <long>Show sidebar in full screen mode.</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/epiphany/interface/show_sidebar</key>
+ <applyto>/apps/epiphany/interface/show_sidebar</applyto>
+ <owner>epiphany</owner>
+ <type>bool</type>
+ <default>0</default>
+ <locale name="C">
+ <short>Show sidebar by default</short>
+ <long>Show sidebar by default.</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/epiphany/interface/sidebar_size</key>
+ <applyto>/apps/epiphany/interface/sidebar_size</applyto>
+ <owner>epiphany</owner>
+ <type>int</type>
+ <default>100</default>
+ <locale name="C">
+ <short>Default sidebar size</short>
+ <long>Default sidebar size.</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/epiphany/interface/sidebar_page</key>
+ <applyto>/apps/epiphany/interface/sidebar_page</applyto>
+ <owner>epiphany</owner>
+ <type>string</type>
+ <default>history</default>
+ <locale name="C">
+ <short>Default sidebar page</short>
+ <long>Default sidebar page.</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/epiphany/interface/show_toolbars</key>
+ <applyto>/apps/epiphany/interface/show_toolbars</applyto>
+ <owner>epiphany</owner>
+ <type>bool</type>
+ <default>1</default>
+ <locale name="C">
+ <short>Show toolbars by default</short>
+ <long>Show toolbars by default.</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/epiphany/interface/show_statusbar</key>
+ <applyto>/apps/epiphany/interface/show_statusbar</applyto>
+ <owner>epiphany</owner>
+ <type>bool</type>
+ <default>1</default>
+ <locale name="C">
+ <short>Show statusbar by default</short>
+ <long>Show statusbar by default.</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/epiphany/filtering/image_loading_type</key>
+ <applyto>/apps/epiphany/filtering/image_loading_type</applyto>
+ <owner>epiphany</owner>
+ <type>int</type>
+ <default>0</default>
+ <locale name="C">
+ <short>When to load images</short>
+ <long>When to load images. Possible values are 0 (always), 1 (from
+ current server only), 2 (never)</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/epiphany/filtering/animate_type</key>
+ <applyto>/apps/epiphany/filtering/animate_type</applyto>
+ <owner>epiphany</owner>
+ <type>int</type>
+ <default>0</default>
+ <locale name="C">
+ <short>Image animation type</short>
+ <long>Image animation type. Possible values are 0 (continuously), 1
+ (once through), 2 (never)</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/epiphany/rendering/default_charset</key>
+ <applyto>/apps/epiphany/rendering/default_charset</applyto>
+ <owner>epiphany</owner>
+ <type>string</type>
+ <default>Western (ISO-8859-1)</default>
+ <locale name="C">
+ <short>Default charset</short>
+ <long>Default charset.</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/epiphany/rendering/default_font</key>
+ <applyto>/apps/epiphany/rendering/default_font</applyto>
+ <owner>epiphany</owner>
+ <type>int</type>
+ <default>0</default>
+ <locale name="C">
+ <short>Default font type</short>
+ <long>Default font type. Possible values are 0 (serif), 1
+ (sans-serif)</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/epiphany/interface/spinner_theme</key>
+ <applyto>/apps/epiphany/interface/spinner_theme</applyto>
+ <owner>epiphany</owner>
+ <type>string</type>
+ <default>gnome</default>
+ <locale name="C">
+ <short>Default spinner theme</short>
+ <long>Default spinner theme</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/epiphany/interface/toolbar_setup</key>
+ <applyto>/apps/epiphany/interface/toolbar_setup</applyto>
+ <owner>epiphany</owner>
+ <type>string</type>
+ <default>back=std_toolitem(item=back);back_history=navigation_history(direction=back);forward=std_toolitem(item=forward);forward_history=navigation_history(direction=forward);stop=std_toolitem(item=stop);reload=std_toolitem(item=reload);home_separator=separator;home=std_toolitem(item=home);favicons_separator=separator;favicon=favicon;location=location;spinner=spinner;</default>
+ <locale name="C">
+ <short>Toolbar setup</short>
+ <long>The list of controls that will be present in the toolbar. You should edit
+ this setting with the toolbar editor unless you know what you are doing.</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/epiphany/downloader/keep_open</key>
+ <applyto>/apps/epiphany/downloader/keep_open</applyto>
+ <owner>epiphany</owner>
+ <type>bool</type>
+ <default>true</default>
+ <locale name="C">
+ <short>Keep downloader open after download finished</short>
+ <long>Keep downloader open after all downloads have finished.</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/epiphany/filtering/java_enabled</key>
+ <applyto>/apps/epiphany/filtering/java_enabled</applyto>
+ <owner>epiphany</owner>
+ <type>bool</type>
+ <default>1</default>
+ <locale name="C">
+ <short>Allow Java</short>
+ <long>Allow Java.</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/epiphany/filtering/javascript_enabled</key>
+ <applyto>/apps/epiphany/filtering/javascript_enabled</applyto>
+ <owner>epiphany</owner>
+ <type>bool</type>
+ <default>1</default>
+ <locale name="C">
+ <short>Allow JavaScript</short>
+ <long>Allow JavaScript.</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/epiphany/network/no_proxies_for</key>
+ <applyto>/apps/epiphany/network/no_proxies_for</applyto>
+ <owner>epiphany</owner>
+ <type>string</type>
+ <default></default>
+ <locale name="C">
+ <short>No proxy for</short>
+ <long>List of domains for wherefore not to use the proxy, comma
+ delimited</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/epiphany/network/disk_cache_size</key>
+ <applyto>/apps/epiphany/network/disk_cache_size</applyto>
+ <owner>epiphany</owner>
+ <type>int</type>
+ <default>50000</default>
+ <locale name="C">
+ <short>Size of disk cache</short>
+ <long>Size of disk cache, in KB.</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/epiphany/network/mem_cache_size</key>
+ <applyto>/apps/epiphany/network/mem_cache_size</applyto>
+ <owner>epiphany</owner>
+ <type>int</type>
+ <default>4096</default>
+ <locale name="C">
+ <short>Size of memory cache</short>
+ <long>Size of memory cache, in KB.</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/epiphany/network/cache_compare</key>
+ <applyto>/apps/epiphany/network/cache_compare</applyto>
+ <owner>epiphany</owner>
+ <type>int</type>
+ <default>3</default>
+ <locale name="C">
+ <short>When to compare cached copy</short>
+ <long>When to compare cached copy to web copy. Possible values are 0
+ (once per session), 1 (every time), 2 (never), 3 (automatic).</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/epiphany/rendering/lang</key>
+ <applyto>/apps/epiphany/rendering/lang</applyto>
+ <owner>epiphany</owner>
+ <type>list</type>
+ <list_type>string</list_type>
+ <default>[en]</default>
+ <locale name="C">
+ <short>Languages</short>
+ <long>Preferred languages, two letter codes.</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/epiphany/filterin/passwords_save</key>
+ <applyto>/apps/epiphany/filtering/passwords_save</applyto>
+ <owner>epiphany</owner>
+ <type>bool</type>
+ <default>true</default>
+ <locale name="C">
+ <short>Save passwords</short>
+ <long>Save passwords.</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/epiphany/history/expire</key>
+ <applyto>/apps/epiphany/history/expire</applyto>
+ <owner>epiphany</owner>
+ <type>int</type>
+ <default>30</default>
+ <locale name="C">
+ <short>Expire history</short>
+ <long>Expire history after how many days.</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/epiphany/history/search_time</key>
+ <applyto>/apps/epiphany/history/search_time</applyto>
+ <owner>epiphany</owner>
+ <type>int</type>
+ <default>1</default>
+ <locale name="C">
+ <short>History search time</short>
+ <long>Show only history entries from a particular time. Possible
+ values are 0 (all items), 1 (today), 2 (yesterday), 3 (two days ago), 4
+ (this week), 5 (this month).</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/epiphany/print/top_margin</key>
+ <applyto>/apps/epiphany/print/top_margin</applyto>
+ <owner>epiphany</owner>
+ <type>float</type>
+ <default>0.5</default>
+ <locale name="C">
+ <short>Printing top margin</short>
+ <long>Printing top margin (in inches).</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/epiphany/print/bottom_margin</key>
+ <applyto>/apps/epiphany/print/bottom_margin</applyto>
+ <owner>epiphany</owner>
+ <type>float</type>
+ <default>0.5</default>
+ <locale name="C">
+ <short>Printing bottom margin</short>
+ <long>Printing bottom margin (in inches).</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/epiphany/print/left_margin</key>
+ <applyto>/apps/epiphany/print/left_margin</applyto>
+ <owner>epiphany</owner>
+ <type>float</type>
+ <default>0.5</default>
+ <locale name="C">
+ <short>Printing left margin</short>
+ <long>Printing left margin (in inches).</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/epiphany/print/right_margin</key>
+ <applyto>/apps/epiphany/print/right_margin</applyto>
+ <owner>epiphany</owner>
+ <type>float</type>
+ <default>0.5</default>
+ <locale name="C">
+ <short>Printing right margin</short>
+ <long>Printing right margin (in inches).</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/epiphany/print/page_title_toggle</key>
+ <applyto>/apps/epiphany/print/page_title_toggle</applyto>
+ <owner>epiphany</owner>
+ <type>bool</type>
+ <default>true</default>
+ <locale name="C">
+ <short>Whether to print the page title in the header.</short>
+ <long>Whether to print the page title in the header.</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/epiphany/print/page_url_toggle</key>
+ <applyto>/apps/epiphany/print/page_url_toggle</applyto>
+ <owner>epiphany</owner>
+ <type>bool</type>
+ <default>true</default>
+ <locale name="C">
+ <short>Whether to print the page URL in the header</short>
+ <long>Whether to print the page URL in the header</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/epiphany/print/date_toggle</key>
+ <applyto>/apps/epiphany/print/date_toggle</applyto>
+ <owner>epiphany</owner>
+ <type>bool</type>
+ <default>true</default>
+ <locale name="C">
+ <short>Whether to print the date in the footer.</short>
+ <long>Whether to print the date in the footer.</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/epiphany/print/page_numbers_toggle</key>
+ <applyto>/apps/epiphany/print/page_numbers_toggle</applyto>
+ <owner>epiphany</owner>
+ <type>bool</type>
+ <default>true</default>
+ <locale name="C">
+ <short>Whether to print the page numbers (x of total) in the footer.</short>
+ <long>Whether to print the page numbers (x of total) in the footer.</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/epiphany/print/printer</key>
+ <applyto>/apps/epiphany/print/printer</applyto>
+ <owner>epiphany</owner>
+ <type>string</type>
+ <default>lpr</default>
+ <locale name="C">
+ <short>Printer name</short>
+ <long>Printer name.</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/epiphany/print/file</key>
+ <applyto>/apps/epiphany/print/file</applyto>
+ <owner>epiphany</owner>
+ <type>string</type>
+ <locale name="C">
+ <short>Filename to print to</short>
+ <long>Filename to print to.</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/epiphany/print/printon</key>
+ <applyto>/apps/epiphany/print/printon</applyto>
+ <owner>epiphany</owner>
+ <type>int</type>
+ <default>0</default>
+ <locale name="C">
+ <short>Print range</short>
+ <long>Print range: 0 (all pages), 1 (specific range).</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/epiphany/print/paper</key>
+ <applyto>/apps/epiphany/print/paper</applyto>
+ <owner>epiphany</owner>
+ <type>int</type>
+ <default>0</default>
+ <locale name="C">
+ <short>Paper type</short>
+ <long>Paper type: 0 (Letter), 1 (Legal), 2 (Executive), 3 (A4).</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/epiphany/directories/opendir</key>
+ <applyto>/apps/epiphany/directories/opendir</applyto>
+ <owner>epiphany</owner>
+ <type>string</type>
+ <default>~</default>
+ <locale name="C">
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/epiphany/directories/savedir</key>
+ <applyto>/apps/epiphany/directories/savedir</applyto>
+ <owner>epiphany</owner>
+ <type>string</type>
+ <default>~</default>
+ <locale name="C">
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/epiphany/directories/saveimagedir</key>
+ <applyto>/apps/epiphany/directories/saveimagedir</applyto>
+ <owner>epiphany</owner>
+ <type>string</type>
+ <default>~</default>
+ <locale name="C">
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/epiphany/rendering/autodetect_charset</key>
+ <applyto>/apps/epiphany/rendering/autodetect_charset</applyto>
+ <owner>epiphany</owner>
+ <type>int</type>
+ <default>0</default>
+ <locale name="C">
+ </locale>
+ </schema>
+ </schemalist>
+</gconfschemafile>
+
diff --git a/data/glade/.cvsignore b/data/glade/.cvsignore
new file mode 100644
index 000000000..06ac86832
--- /dev/null
+++ b/data/glade/.cvsignore
@@ -0,0 +1,3 @@
+Makefile
+Makefile.in
+*.gladep
diff --git a/data/glade/Makefile.am b/data/glade/Makefile.am
new file mode 100644
index 000000000..1013895d5
--- /dev/null
+++ b/data/glade/Makefile.am
@@ -0,0 +1,10 @@
+glade_DATA = \
+ epiphany.glade \
+ prompts.glade \
+ toolbar-editor.glade \
+ prefs-dialog.glade \
+ print.glade
+
+gladedir = $(pkgdatadir)/glade
+
+EXTRA_DIST = $(glade_DATA)
diff --git a/data/glade/epiphany.glade b/data/glade/epiphany.glade
new file mode 100644
index 000000000..520d9217e
--- /dev/null
+++ b/data/glade/epiphany.glade
@@ -0,0 +1,1582 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
+
+<glade-interface>
+<requires lib="gnome"/>
+
+<widget class="GtkDialog" id="history_dialog">
+ <property name="border_width">6</property>
+ <property name="height_request">400</property>
+ <property name="title" translatable="yes">History</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="has_separator">False</property>
+
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="history_dialog_b">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area2">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+ <child>
+ <widget class="GtkButton" id="history_clear_button">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="response_id">0</property>
+ <signal name="clicked" handler="history_clear_button_clicked_cb"/>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment8">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">0</property>
+ <property name="yscale">0</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox86">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">2</property>
+
+ <child>
+ <widget class="GtkImage" id="image6">
+ <property name="visible">True</property>
+ <property name="stock">gtk-clear</property>
+ <property name="icon_size">4</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label1223">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">C_lear</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="history_ok_button">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-close</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="response_id">-7</property>
+ <signal name="clicked" handler="history_ok_button_clicked_cb"/>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox98">
+ <property name="border_width">6</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">5</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox41">
+ <property name="border_width">6</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label224">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Find:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">history_entry</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="history_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="has_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char" translatable="yes">*</property>
+ <property name="activates_default">False</property>
+ <signal name="changed" handler="history_entry_changed_cb" last_modification_time="Sun, 27 Oct 2002 13:43:51 GMT"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label225">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Time:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">1</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">history_time_optionmenu</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkOptionMenu" id="history_time_optionmenu">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="history">0</property>
+ <signal name="changed" handler="history_time_optionmenu_changed_cb" last_modification_time="Wed, 01 May 2002 11:40:31 GMT"/>
+
+ <child internal-child="menu">
+ <widget class="GtkMenu" id="convertwidget1">
+ <property name="visible">True</property>
+
+ <child>
+ <widget class="GtkMenuItem" id="convertwidget2">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Ever</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="convertwidget3">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Today</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="convertwidget4">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Last two days</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="convertwidget5">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Last three days</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="convertwidget6">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Week</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="convertwidget7">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Month</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow1136">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <widget class="GtkTreeView" id="history_treeview">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="headers_visible">True</property>
+ <property name="rules_hint">False</property>
+ <property name="reorderable">False</property>
+ <property name="enable_search">True</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+<widget class="GtkDialog" id="find_dialog">
+ <property name="border_width">6</property>
+ <property name="title" translatable="yes">Find text...</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="has_separator">False</property>
+
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox4">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area4">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+ <child>
+ <widget class="GtkButton" id="BClose">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-close</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="response_id">0</property>
+ <signal name="clicked" handler="find_close_button_clicked_cb"/>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="back_button">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="response_id">0</property>
+ <signal name="clicked" handler="find_prev_button_clicked_cb"/>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment7">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">0</property>
+ <property name="yscale">0</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox85">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">2</property>
+
+ <child>
+ <widget class="GtkImage" id="image5">
+ <property name="visible">True</property>
+ <property name="stock">gtk-go-back</property>
+ <property name="icon_size">4</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label1222">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Previous</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="forward_button">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="response_id">0</property>
+ <signal name="clicked" handler="find_next_button_clicked_cb"/>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment6">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">0</property>
+ <property name="yscale">0</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox84">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">2</property>
+
+ <child>
+ <widget class="GtkImage" id="image4">
+ <property name="visible">True</property>
+ <property name="stock">gtk-go-forward</property>
+ <property name="icon_size">4</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label1221">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Next</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox131">
+ <property name="border_width">6</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox109">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox72">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label63">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Find text in the document:&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">7.45058e-09</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GnomeEntry" id="find_gnome_entry">
+ <property name="visible">True</property>
+ <property name="history_id">FindEntry</property>
+ <property name="max_saved">10</property>
+
+ <child internal-child="entry">
+ <widget class="GtkEntry" id="find_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="has_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char" translatable="yes">*</property>
+ <property name="activates_default">False</property>
+ <signal name="activate" handler="find_entry_activate_cb"/>
+ <signal name="changed" handler="find_entry_changed_cb"/>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="case_check">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">_Match upper/lower case</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="find_check_toggled_cb" last_modification_time="Wed, 03 Apr 2002 12:46:24 GMT"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="wrap_check">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Automatically _wrap around</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="find_check_toggled_cb" last_modification_time="Wed, 03 Apr 2002 12:47:04 GMT"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">2</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+<widget class="GtkWindow" id="download_manager_dialog">
+ <property name="border_width">12</property>
+ <property name="title" translatable="yes">Downloading</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">False</property>
+ <signal name="delete_event" handler="download_dialog_delete_cb"/>
+
+ <child>
+ <widget class="GtkVBox" id="vbox106">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">12</property>
+
+ <child>
+ <widget class="GtkHButtonBox" id="hbuttonbox10">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+ <property name="spacing">8</property>
+
+ <child>
+ <widget class="GtkButton" id="open_button">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-open</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <signal name="clicked" handler="download_dialog_open_cb" last_modification_time="Tue, 04 Jun 2002 18:01:15 GMT"/>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="pause_button">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">_Pause</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <signal name="clicked" handler="download_dialog_pause_cb" last_modification_time="Sat, 01 Jun 2002 23:54:37 GMT"/>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="resume_button">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">_Resume</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <signal name="clicked" handler="download_dialog_resume_cb" last_modification_time="Sun, 02 Jun 2002 00:08:23 GMT"/>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="abort_button">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-stop</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <signal name="clicked" handler="download_dialog_abort_cb" last_modification_time="Sat, 01 Jun 2002 23:54:50 GMT"/>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox107">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow1134">
+ <property name="height_request">100</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <widget class="GtkTreeView" id="clist">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="headers_visible">True</property>
+ <property name="rules_hint">False</property>
+ <property name="reorderable">False</property>
+ <property name="enable_search">True</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox82">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkCheckButton" id="keep_open_check">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">_Keep the dialog open</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkToggleButton" id="details_togglebutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <signal name="toggled" handler="download_dialog_details_cb" last_modification_time="Sat, 01 Jun 2002 23:52:31 GMT"/>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment5">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">0</property>
+ <property name="yscale">0</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox83">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">2</property>
+
+ <child>
+ <widget class="GtkImage" id="image3">
+ <property name="visible">True</property>
+ <property name="stock">gtk-dialog-info</property>
+ <property name="icon_size">4</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label1220">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Download _details...</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHSeparator" id="details_separator">
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="details_frame">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkTable" id="details_table">
+ <property name="visible">True</property>
+ <property name="n_rows">6</property>
+ <property name="n_columns">2</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label1142">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Location:&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_RIGHT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label1143">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;File:&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_RIGHT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label1211">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Status:&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label1212">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Time Elapsed:&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label1213">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Time Remaining:&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="details_elapsed">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes"></property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="details_remaining">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes"></property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="details_status">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes"></property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkProgressBar" id="details_progress">
+ <property name="visible">True</property>
+ <property name="orientation">GTK_PROGRESS_LEFT_TO_RIGHT</property>
+ <property name="fraction">0</property>
+ <property name="pulse_step">0.1</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">5</property>
+ <property name="bottom_attach">6</property>
+ <property name="y_options">fill</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+<widget class="GtkDialog" id="pdm_dialog">
+ <property name="border_width">7</property>
+ <property name="width_request">400</property>
+ <property name="height_request">300</property>
+ <property name="title" translatable="yes">Personal data manager</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="has_separator">False</property>
+
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox27">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area27">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+ <child>
+ <widget class="GtkButton" id="closebutton1">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-close</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="response_id">-7</property>
+ <signal name="clicked" handler="pdm_dialog_close_button_clicked_cb" last_modification_time="Mon, 17 Jun 2002 11:00:39 GMT"/>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkNotebook" id="notebook3">
+ <property name="border_width">5</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="show_tabs">True</property>
+ <property name="show_border">True</property>
+ <property name="tab_pos">GTK_POS_TOP</property>
+ <property name="scrollable">False</property>
+ <property name="enable_popup">False</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox87">
+ <property name="border_width">12</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow1139">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <widget class="GtkTreeView" id="cookies_treeview">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="headers_visible">True</property>
+ <property name="rules_hint">False</property>
+ <property name="reorderable">False</property>
+ <property name="enable_search">True</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVButtonBox" id="vbuttonbox1">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_START</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkButton" id="cookies_remove_button">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-remove</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="cookies_properties_button">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-properties</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <signal name="clicked" handler="pdm_dialog_cookies_properties_button_clicked_cb" last_modification_time="Thu, 20 Jun 2002 08:12:23 GMT"/>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="tab_expand">False</property>
+ <property name="tab_fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label1227">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Cookies</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="type">tab</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox88">
+ <property name="border_width">6</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow1140">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <widget class="GtkTreeView" id="passwords_treeview">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="headers_visible">True</property>
+ <property name="rules_hint">False</property>
+ <property name="reorderable">False</property>
+ <property name="enable_search">True</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVButtonBox" id="vbuttonbox2">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_START</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkButton" id="passwords_remove_button">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-remove</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="tab_expand">False</property>
+ <property name="tab_fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label1228">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Passwords</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="type">tab</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+<widget class="GtkDialog" id="mime_ask_action_dialog">
+ <property name="border_width">6</property>
+ <property name="title" translatable="yes">Choose the file type action</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="resizable">False</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="has_separator">False</property>
+
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox28">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">12</property>
+
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area28">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+ <child>
+ <widget class="GtkButton" id="mime_ask_dialog_save">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-save</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="response_id">0</property>
+ <signal name="clicked" handler="mime_ask_dialog_save_clicked_cb" last_modification_time="Sun, 01 Sep 2002 13:39:41 GMT"/>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="mime_ask_dialog_cancel">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-cancel</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="response_id">-6</property>
+ <signal name="clicked" handler="mime_ask_dialog_cancel_clicked_cb" last_modification_time="Sun, 01 Sep 2002 13:08:43 GMT"/>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="mime_ask_dialog_open">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-open</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="response_id">0</property>
+ <signal name="clicked" handler="mime_ask_dialog_open_clicked_cb" last_modification_time="Sun, 01 Sep 2002 13:09:36 GMT"/>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox135">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox95">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">5</property>
+
+ <child>
+ <widget class="GtkImage" id="image8">
+ <property name="visible">True</property>
+ <property name="stock">gtk-dialog-question</property>
+ <property name="icon_size">6</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox136">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">5</property>
+
+ <child>
+ <widget class="GtkLabel" id="label1231">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;span weight=&quot;bold&quot; size=&quot;larger&quot;&gt;What do you want to do with this file?
+&lt;/span&gt;
+It's not possible to view this file type directly in the browser:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">True</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox93">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">12</property>
+
+ <child>
+ <widget class="GtkLabel" id="label1235">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes"> </property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkImage" id="mime_ask_action_icon">
+ <property name="visible">True</property>
+ <property name="stock">gtk-justify-center</property>
+ <property name="icon_size">4</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="mime_ask_action_description">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">DYNAMIC</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="mime_ask_dialog_choice_label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">You can open it with another application or save it on disk.</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">True</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+</glade-interface>
diff --git a/data/glade/prefs-dialog.glade b/data/glade/prefs-dialog.glade
new file mode 100644
index 000000000..4042ddbcc
--- /dev/null
+++ b/data/glade/prefs-dialog.glade
@@ -0,0 +1,3083 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
+
+<glade-interface>
+<requires lib="gnome"/>
+
+<widget class="GtkWindow" id="general_page_dialog">
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">window1</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">False</property>
+
+ <child>
+ <widget class="GtkVBox" id="general_page_box">
+ <property name="border_width">12</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">18</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox152">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label1238">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Home page&lt;/b&gt;</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">homepage_entry</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox136">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkLabel" id="label1239">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes"> </property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox154">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox138">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">12</property>
+
+ <child>
+ <widget class="GtkLabel" id="label1243">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Location:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">homepage_entry</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="homepage_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char" translatable="yes">*</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHButtonBox" id="hbuttonbox12">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkButton" id="button1">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Set to _Current Page</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <signal name="clicked" handler="prefs_homepage_current_button_clicked_cb"/>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="button9">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Set to _Blank Page</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <signal name="clicked" handler="prefs_homepage_blank_button_clicked_cb" last_modification_time="Tue, 14 May 2002 10:37:08 GMT"/>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox153">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label1240">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;On New Page&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox137">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkLabel" id="label1241">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes"> </property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox155">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkRadioButton" id="new_page_show_homepage">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Show hom_e page</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkRadioButton" id="radiobutton32">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Show la_st page</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">new_page_show_homepage</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkRadioButton" id="radiobutton33">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Show blan_k page</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">new_page_show_homepage</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox156">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkLabel" id="label1242">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Language&lt;/b&gt;</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkTable" id="table85">
+ <property name="border_width">12</property>
+ <property name="visible">True</property>
+ <property name="n_rows">3</property>
+ <property name="n_columns">3</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+
+ <child>
+ <widget class="GtkLabel" id="label1205">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Autodetec_t encoding:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">1</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">autocharset_optionmenu</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label1206">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Default encoding:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">default_charset_optionmenu</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label1208">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Lan_guage:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">language_optionmenu</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkOptionMenu" id="language_optionmenu">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="history">-1</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkOptionMenu" id="default_charset_optionmenu">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="history">-1</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkOptionMenu" id="autocharset_optionmenu">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="history">0</property>
+
+ <child internal-child="menu">
+ <widget class="GtkMenu" id="menu6">
+ <property name="visible">True</property>
+
+ <child>
+ <widget class="GtkMenuItem" id="menuitem39">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Off</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="menuitem40">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Chinese</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="menuitem41">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">East asian</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="menuitem42">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Japanese</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="menuitem43">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Korean</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="menuitem44">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Russian</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="menuitem45">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Simplified Chinese</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="menuitem46">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Traditional Chinese</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="menuitem47">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Ukrainian</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkImage" id="image3">
+ <property name="visible">True</property>
+ <property name="stock">gtk-select-font</property>
+ <property name="icon_size">6</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options">fill</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHButtonBox" id="hbuttonbox10">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_DEFAULT_STYLE</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkButton" id="language_more_button">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">_More...</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <signal name="clicked" handler="prefs_language_more_button_clicked_cb" last_modification_time="Tue, 14 May 2002 11:07:13 GMT"/>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">fill</property>
+ <property name="y_options">fill</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+<widget class="GtkWindow" id="appearance_page_dialog">
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">window2</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">False</property>
+
+ <child>
+ <widget class="GtkVBox" id="appearance_page_box">
+ <property name="border_width">12</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">18</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox157">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label1244">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Fonts&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox139">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkLabel" id="label1245">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes"> </property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkTable" id="table70">
+ <property name="visible">True</property>
+ <property name="n_rows">7</property>
+ <property name="n_columns">4</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+
+ <child>
+ <widget class="GtkLabel" id="label1132">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Siz_e:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">fixed_size_spinbutton</property>
+ </widget>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkSpinButton" id="fixed_size_spinbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="climb_rate">1</property>
+ <property name="digits">0</property>
+ <property name="numeric">False</property>
+ <property name="update_policy">GTK_UPDATE_ALWAYS</property>
+ <property name="snap_to_ticks">False</property>
+ <property name="wrap">False</property>
+ <property name="adjustment">1 0 100 1 10 10</property>
+ </widget>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="right_attach">4</property>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ <property name="x_options"></property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label1131">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Si_ze:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">variable_size_spinbutton</property>
+ </widget>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkSpinButton" id="variable_size_spinbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="climb_rate">1</property>
+ <property name="digits">0</property>
+ <property name="numeric">False</property>
+ <property name="update_policy">GTK_UPDATE_ALWAYS</property>
+ <property name="snap_to_ticks">False</property>
+ <property name="wrap">False</property>
+ <property name="adjustment">0 0 100 1 10 10</property>
+ </widget>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="right_attach">4</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label1133">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Proportional:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">proportional_optionmenu</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label1134">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Serif:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">combo-entry1</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label1135">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">S_ans serif:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">combo-entry2</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label1138">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Monospace:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">combo-entry5</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label1121">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Language encoding:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">optionmenu2</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkOptionMenu" id="optionmenu2">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="history">0</property>
+ <signal name="changed" handler="fonts_language_optionmenu_changed_cb" last_modification_time="Fri, 17 May 2002 10:44:00 GMT"/>
+
+ <child internal-child="menu">
+ <widget class="GtkMenu" id="menu2">
+ <property name="visible">True</property>
+
+ <child>
+ <widget class="GtkMenuItem" id="menuitem18">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Western</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="menuitem19">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Central European</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="menuitem20">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Japanese</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="menuitem21">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Traditional Chinese</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="menuitem22">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Simplified Chinese</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="menuitem23">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Korean</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="menuitem24">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Cyrillic</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="menuitem25">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Baltic</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="menuitem26">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Greek</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="menuitem27">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Turkish</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="menuitem28">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Unicode</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="menuitem29">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Thai</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="menuitem30">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Hebrew</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="menuitem31">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Arabic</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkOptionMenu" id="proportional_optionmenu">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="history">0</property>
+
+ <child>
+ <widget class="GtkMenu" id="menu3">
+
+ <child>
+ <widget class="GtkMenuItem" id="serif1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Serif</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="sans_serif1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Sans Serif</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox133">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">5</property>
+
+ <child>
+ <widget class="GtkCheckButton" id="use_fonts_checkbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Always us_e these fonts</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label1217">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Min_imum font size:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">min_size_spinbutton</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkSpinButton" id="min_size_spinbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="climb_rate">1</property>
+ <property name="digits">0</property>
+ <property name="numeric">False</property>
+ <property name="update_policy">GTK_UPDATE_ALWAYS</property>
+ <property name="snap_to_ticks">False</property>
+ <property name="wrap">False</property>
+ <property name="adjustment">0 0 100 1 10 10</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">4</property>
+ <property name="top_attach">6</property>
+ <property name="bottom_attach">7</property>
+ <property name="x_options">fill</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCombo" id="serif_combo">
+ <property name="visible">True</property>
+ <property name="value_in_list">False</property>
+ <property name="allow_empty">True</property>
+ <property name="case_sensitive">False</property>
+ <property name="enable_arrow_keys">True</property>
+ <property name="enable_arrows_always">False</property>
+
+ <child internal-child="entry">
+ <widget class="GtkEntry" id="combo-entry1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">False</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char" translatable="yes">*</property>
+ <property name="activates_default">False</property>
+ </widget>
+ </child>
+
+ <child internal-child="list">
+ <widget class="GtkList" id="combo-list1">
+ <property name="visible">True</property>
+ <property name="selection_mode">GTK_SELECTION_BROWSE</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCombo" id="sansserif_combo">
+ <property name="visible">True</property>
+ <property name="value_in_list">False</property>
+ <property name="allow_empty">True</property>
+ <property name="case_sensitive">False</property>
+ <property name="enable_arrow_keys">True</property>
+ <property name="enable_arrows_always">False</property>
+
+ <child internal-child="entry">
+ <widget class="GtkEntry" id="combo-entry2">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">False</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char" translatable="yes">*</property>
+ <property name="activates_default">False</property>
+ </widget>
+ </child>
+
+ <child internal-child="list">
+ <widget class="GtkList" id="combo-list2">
+ <property name="visible">True</property>
+ <property name="selection_mode">GTK_SELECTION_BROWSE</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCombo" id="monospace_combo">
+ <property name="visible">True</property>
+ <property name="value_in_list">False</property>
+ <property name="allow_empty">True</property>
+ <property name="case_sensitive">False</property>
+ <property name="enable_arrow_keys">True</property>
+ <property name="enable_arrows_always">False</property>
+
+ <child internal-child="entry">
+ <widget class="GtkEntry" id="combo-entry5">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">False</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char" translatable="yes">*</property>
+ <property name="activates_default">False</property>
+ </widget>
+ </child>
+
+ <child internal-child="list">
+ <widget class="GtkList" id="combo-list5">
+ <property name="visible">True</property>
+ <property name="selection_mode">GTK_SELECTION_BROWSE</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label1275">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes"> </property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">5</property>
+ <property name="bottom_attach">6</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox162">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox158">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label1246">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Colors&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox140">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkLabel" id="label1247">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes"> </property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox174">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox163">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GnomeColorPicker" id="background_cpick">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="dither">True</property>
+ <property name="use_alpha">False</property>
+ <property name="title" translatable="yes">Pick the background color</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label1250">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Background</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">1</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox165">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GnomeColorPicker" id="text_cpick">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="dither">True</property>
+ <property name="use_alpha">False</property>
+ <property name="title" translatable="yes">Pick the text color</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label1251">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Text</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="use_syscolors_checkbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Use s_ystem colors</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="use_colors_checkbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Al_ways use these colors</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox176">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label1280">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Links&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox166">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkLabel" id="label1281">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes"> </property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox177">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox167">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GnomeColorPicker" id="unvisited_cpick">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="dither">True</property>
+ <property name="use_alpha">False</property>
+ <property name="title" translatable="yes">Pick the unvisited link color</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label1249">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Unvisited link</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">1</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox168">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GnomeColorPicker" id="visited_cpick">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="dither">True</property>
+ <property name="use_alpha">False</property>
+ <property name="title" translatable="yes">Pick the visited link color</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label1248">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Visited link</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+<widget class="GtkWindow" id="ui_page_dialog">
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">window1</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">False</property>
+
+ <child>
+ <widget class="GtkVBox" id="ui_page_box">
+ <property name="border_width">12</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">18</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox159">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label1252">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Tabs&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox145">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkLabel" id="label1253">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes"> </property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox160">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkCheckButton" id="open_in_tabs_checkbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">_Open in tabs by default</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="jump_to_checkbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">_Jump to new tabs automatically</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="popups_checkbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Open _popups in tabs</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox161">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label1254">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Spinner&lt;/b&gt;</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox146">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkLabel" id="label1255">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes"> </property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow1131">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <widget class="GnomeIconList" id="spinners_iconlist">
+ <property name="height_request">160</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="selection_mode">GTK_SELECTION_SINGLE</property>
+ <property name="icon_width">78</property>
+ <property name="row_spacing">4</property>
+ <property name="column_spacing">2</property>
+ <property name="text_spacing">2</property>
+ <property name="text_editable">False</property>
+ <property name="text_static">False</property>
+ <signal name="select_icon" handler="spinners_iconlist_select_icon_cb" last_modification_time="Sat, 18 May 2002 10:07:15 GMT"/>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+<widget class="GtkWindow" id="network_page_dialog">
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">window1</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">False</property>
+
+ <child>
+ <widget class="GtkVBox" id="network_page_box">
+ <property name="border_width">12</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">18</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox162">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label1256">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Caches&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox147">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkLabel" id="label1257">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes"> </property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox178">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">12</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox179">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label1282">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Compare page:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkRadioButton" id="cache_compare_radiobutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Once per _session</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkRadioButton" id="radiobutton54">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">E_very time</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">cache_compare_radiobutton</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkRadioButton" id="radiobutton55">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">_Never</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">cache_compare_radiobutton</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkRadioButton" id="radiobutton56">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">_Automatically</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">cache_compare_radiobutton</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkTable" id="table77">
+ <property name="visible">True</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">4</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+
+ <child>
+ <widget class="GtkLabel" id="label1167">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">kB</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options"></property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label1168">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">kB</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options"></property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label1170">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Dis_k cache:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">disk_cache_spin</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label1171">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Memor_y cache:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">memory_cache_spin</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkSpinButton" id="memory_cache_spin">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="climb_rate">1</property>
+ <property name="digits">0</property>
+ <property name="numeric">False</property>
+ <property name="update_policy">GTK_UPDATE_ALWAYS</property>
+ <property name="snap_to_ticks">False</property>
+ <property name="wrap">False</property>
+ <property name="adjustment">1 0 1e+06 1000 10 10</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkSpinButton" id="disk_cache_spin">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="climb_rate">1</property>
+ <property name="digits">0</property>
+ <property name="numeric">False</property>
+ <property name="update_policy">GTK_UPDATE_ALWAYS</property>
+ <property name="snap_to_ticks">False</property>
+ <property name="wrap">False</property>
+ <property name="adjustment">1 0 1e+06 1000 10 10</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="button6">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Clear _Memory Cache</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <signal name="clicked" handler="prefs_clear_memory_cache_button_clicked_cb"/>
+ </widget>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="right_attach">4</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options"></property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="button5">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Clear _Disk Cache</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <signal name="clicked" handler="prefs_clear_disk_cache_button_clicked_cb"/>
+ </widget>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="right_attach">4</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+<widget class="GtkWindow" id="filtering_page_dialog">
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">window2</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">False</property>
+
+ <child>
+ <widget class="GtkVBox" id="filtering_page_box">
+ <property name="border_width">12</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">18</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox165">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label1261">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Cookies&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox150">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkLabel" id="label1264">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes"> </property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox168">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkRadioButton" id="cookies_radiobutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">_Always accept</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkRadioButton" id="radiobutton51">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Accept _from current server only</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">cookies_radiobutton</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkRadioButton" id="radiobutton52">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">_Never accept</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">cookies_radiobutton</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="warn_cookie_checkbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">_Warn before accepting a cookie</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="session_cookie_checkbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Coo_kies expire at the end of the session</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox164">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label1260">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Images&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox149">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkLabel" id="label1263">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes"> </property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox167">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkRadioButton" id="images_radiobutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">_Always load</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkRadioButton" id="radiobutton48">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">_Load from current server only</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">images_radiobutton</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkRadioButton" id="radiobutton49">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">_Never load</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">images_radiobutton</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox166">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label1262">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Others&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox151">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkLabel" id="label1265">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes"> </property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkTable" id="table90">
+ <property name="visible">True</property>
+ <property name="n_rows">3</property>
+ <property name="n_columns">2</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">6</property>
+
+ <child>
+ <widget class="GtkCheckButton" id="allow_java_checkbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Allow _Java (requires plugin)</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="allow_js_checkbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Allow Java_Script</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="allow_popups_checkbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Allow _popups</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="allow_statusbar_checkbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Allow statusbar _messages</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="remember_passwords_checkbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">_Remember passwords</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+<widget class="GtkDialog" id="languages_dialog">
+ <property name="border_width">6</property>
+ <property name="height_request">300</property>
+ <property name="title" translatable="yes">Languages editor</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="has_separator">False</property>
+
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox1">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area1">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+ <child>
+ <widget class="GtkButton" id="add_button">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-add</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="response_id">0</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="remove_button">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-remove</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="response_id">0</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="button12">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-close</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="response_id">-7</property>
+ <signal name="clicked" handler="language_editor_close_button_cb" last_modification_time="Thu, 16 May 2002 18:58:11 GMT"/>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox146">
+ <property name="border_width">6</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox132">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label1216">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Language</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkOptionMenu" id="languages_optionmenu">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="history">-1</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow1130">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <widget class="GtkTreeView" id="languages_treeview">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="headers_visible">True</property>
+ <property name="rules_hint">False</property>
+ <property name="reorderable">False</property>
+ <property name="enable_search">True</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+</glade-interface>
diff --git a/data/glade/print.glade b/data/glade/print.glade
new file mode 100644
index 000000000..66a55bef0
--- /dev/null
+++ b/data/glade/print.glade
@@ -0,0 +1,1573 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
+
+<glade-interface>
+<requires lib="gnome"/>
+
+<widget class="GtkDialog" id="print_dialog">
+ <property name="border_width">7</property>
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">Print</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="has_separator">False</property>
+
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox8">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area8">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+ <child>
+ <widget class="GtkButton" id="preview_button">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-print-preview</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="response_id">50</property>
+ <signal name="clicked" handler="print_preview_button_cb"/>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="cancel_button">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-cancel</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="response_id">-6</property>
+ <signal name="clicked" handler="print_cancel_button_cb"/>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="print_button">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-print</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="response_id">-5</property>
+ <signal name="clicked" handler="print_ok_button_cb"/>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkNotebook" id="print_notebook">
+ <property name="border_width">5</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="show_tabs">True</property>
+ <property name="show_border">True</property>
+ <property name="tab_pos">GTK_POS_TOP</property>
+ <property name="scrollable">False</property>
+ <property name="tab_hborder">2</property>
+ <property name="tab_vborder">2</property>
+ <property name="enable_popup">False</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox127">
+ <property name="border_width">12</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">18</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox128">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label251">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Printer&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox70">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkLabel" id="label252">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes"> </property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkTable" id="table47">
+ <property name="visible">True</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">2</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+
+ <child>
+ <widget class="GtkRadioButton" id="printer_radiobutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">_Printer</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkRadioButton" id="file_radiobutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">_File</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">printer_radiobutton</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="printer_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes">lpr</property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char" translatable="yes">*</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GnomeFileEntry" id="fileentry1">
+ <property name="visible">True</property>
+ <property name="max_saved">10</property>
+ <property name="browse_dialog_title" translatable="yes">Choose a file to print to</property>
+ <property name="directory_entry">False</property>
+ <property name="modal">False</property>
+
+ <child internal-child="entry">
+ <widget class="GtkEntry" id="file_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char" translatable="yes">*</property>
+ <property name="activates_default">False</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox129">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label253">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Pages range&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox71">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkLabel" id="label254">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes"> </property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkTable" id="table49">
+ <property name="visible">True</property>
+ <property name="n_rows">3</property>
+ <property name="n_columns">2</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">6</property>
+
+ <child>
+ <widget class="GtkRadioButton" id="all_pages_radiobutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">_All pages</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkRadioButton" id="pages_radiobutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Pa_ges</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">all_pages_radiobutton</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox49">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">5</property>
+
+ <child>
+ <widget class="GtkLabel" id="label241">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">from:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkSpinButton" id="from_spinbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="climb_rate">1</property>
+ <property name="digits">0</property>
+ <property name="numeric">False</property>
+ <property name="update_policy">GTK_UPDATE_ALWAYS</property>
+ <property name="snap_to_ticks">False</property>
+ <property name="wrap">False</property>
+ <property name="adjustment">1 0 100 1 10 10</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label242">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">to:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkSpinButton" id="to_spinbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="climb_rate">1</property>
+ <property name="digits">0</property>
+ <property name="numeric">False</property>
+ <property name="update_policy">GTK_UPDATE_ALWAYS</property>
+ <property name="snap_to_ticks">False</property>
+ <property name="wrap">False</property>
+ <property name="adjustment">1 0 100 1 10 10</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="y_options">fill</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkRadioButton" id="radiobutton1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">_Selection</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">all_pages_radiobutton</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="tab_expand">False</property>
+ <property name="tab_fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label249">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">General</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="type">tab</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox131">
+ <property name="border_width">12</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">18</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox132">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label257">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Size&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox73">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkLabel" id="label259">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes"> </property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox84">
+ <property name="visible">True</property>
+ <property name="homogeneous">True</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkRadioButton" id="letter_radiobutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">_Letter (8.5&quot; x 11&quot;)</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkRadioButton" id="legal_radiobutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">L_egal (8.5&quot; x 14&quot;)</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">letter_radiobutton</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkRadioButton" id="executive_radiobutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">E_xecutive (7.25&quot; x 10.5&quot;)</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">letter_radiobutton</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkRadioButton" id="A4_radiobutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">A_4 (8.27&quot; x 11.69&quot;)</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">True</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">letter_radiobutton</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkImage" id="image1">
+ <property name="visible">True</property>
+ <property name="stock">gtk-dnd</property>
+ <property name="icon_size">6</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox133">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label258">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Orientation&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox74">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkLabel" id="label260">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes"> </property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox135">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkRadioButton" id="orient_p_radiobutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">P_ortrait</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkRadioButton" id="orient_l_radiobutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Lan_dscape</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">orient_p_radiobutton</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="tab_expand">False</property>
+ <property name="tab_fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label250">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Paper Details</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="type">tab</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox144">
+ <property name="border_width">12</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">18</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox84">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">18</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox137">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label261">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Margins (inches)&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox78">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkLabel" id="label271">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes"> </property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkTable" id="table48">
+ <property name="visible">True</property>
+ <property name="n_rows">4</property>
+ <property name="n_columns">2</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label238">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Bottom</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">bottom_spinbutton</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label239">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Le_ft</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">left_spinbutton</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label240">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Right</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">right_spinbutton</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label237">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Top</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">top_spinbutton</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkSpinButton" id="bottom_spinbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="climb_rate">0.1</property>
+ <property name="digits">1</property>
+ <property name="numeric">True</property>
+ <property name="update_policy">GTK_UPDATE_ALWAYS</property>
+ <property name="snap_to_ticks">False</property>
+ <property name="wrap">False</property>
+ <property name="adjustment">0.6 0 100 0.1 10 10</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkSpinButton" id="left_spinbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="climb_rate">0.1</property>
+ <property name="digits">1</property>
+ <property name="numeric">True</property>
+ <property name="update_policy">GTK_UPDATE_ALWAYS</property>
+ <property name="snap_to_ticks">False</property>
+ <property name="wrap">False</property>
+ <property name="adjustment">0.5 0 100 0.1 10 10</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkSpinButton" id="top_spinbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="climb_rate">0.1</property>
+ <property name="digits">1</property>
+ <property name="numeric">True</property>
+ <property name="update_policy">GTK_UPDATE_ALWAYS</property>
+ <property name="snap_to_ticks">False</property>
+ <property name="wrap">False</property>
+ <property name="adjustment">0.3 0 100 0.1 10 10</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkSpinButton" id="right_spinbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="climb_rate">0.1</property>
+ <property name="digits">1</property>
+ <property name="numeric">True</property>
+ <property name="update_policy">GTK_UPDATE_ALWAYS</property>
+ <property name="snap_to_ticks">False</property>
+ <property name="wrap">False</property>
+ <property name="adjustment">0.5 0 100 0.1 10 10</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox141">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label272">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Colors&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox80">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkLabel" id="label273">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes"> </property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox142">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkRadioButton" id="print_color_radiobutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">_Color</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkRadioButton" id="print_grayscale_radiobutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">G_rayscale</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">print_color_radiobutton</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkImage" id="image2">
+ <property name="visible">True</property>
+ <property name="stock">gtk-select-color</property>
+ <property name="icon_size">6</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox85">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox140">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label269">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Footers&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox77">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkLabel" id="label270">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes"> </property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox125">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkCheckButton" id="print_page_numbers_checkbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Page nu_mbers</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="print_date_checkbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">_Date</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox138">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label267">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Headers&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox76">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkLabel" id="label268">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes"> </property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox124">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkCheckButton" id="print_page_title_checkbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">P_age Title</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="print_page_url_checkbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Page _URL</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="tab_expand">False</property>
+ <property name="tab_fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label276">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Appearance</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="type">tab</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+</glade-interface>
diff --git a/data/glade/prompts.glade b/data/glade/prompts.glade
new file mode 100644
index 000000000..e13a51e70
--- /dev/null
+++ b/data/glade/prompts.glade
@@ -0,0 +1,722 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
+
+<glade-interface>
+
+<widget class="GtkDialog" id="prompt_user_pass_dialog">
+ <property name="border_width">6</property>
+ <property name="title" translatable="yes"></property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="default_width">350</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="has_separator">False</property>
+
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox9">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">8</property>
+
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area9">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+ <child>
+ <widget class="GtkButton" id="button51">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-cancel</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="response_id">-6</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="button49">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-ok</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="response_id">-5</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkTable" id="table60">
+ <property name="border_width">6</property>
+ <property name="visible">True</property>
+ <property name="n_rows">4</property>
+ <property name="n_columns">3</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+
+ <child>
+ <widget class="GtkCheckButton" id="check_button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">DYNAMIC</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="password_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">False</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char" translatable="yes">*</property>
+ <property name="activates_default">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="username_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="has_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char" translatable="yes">*</property>
+ <property name="activates_default">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label1029">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Password</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">1</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label1028">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Username</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">1</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">DYNAMIC</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_FILL</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkImage" id="pixmap">
+ <property name="visible">True</property>
+ <property name="stock">gtk-dialog-question</property>
+ <property name="icon_size">6</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">fill</property>
+ <property name="y_options">fill</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+<widget class="GtkDialog" id="prompt_dialog">
+ <property name="border_width">6</property>
+ <property name="title" translatable="yes"></property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="default_width">350</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="has_separator">False</property>
+
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox11">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">8</property>
+
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area11">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+ <child>
+ <widget class="GtkButton" id="button57">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-cancel</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="response_id">-6</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="button55">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-ok</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="response_id">-5</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkTable" id="table55">
+ <property name="border_width">6</property>
+ <property name="visible">True</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">3</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+
+ <child>
+ <widget class="GtkEntry" id="entry">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="has_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char" translatable="yes">*</property>
+ <property name="activates_default">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="y_options">fill</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">DYNAMIC</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">1</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="check_button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">DYNAMIC</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options">expand</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkImage" id="pixmap">
+ <property name="visible">True</property>
+ <property name="stock">gtk-dialog-question</property>
+ <property name="icon_size">6</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options">fill</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+<widget class="GtkDialog" id="prompt_pass_dialog">
+ <property name="border_width">6</property>
+ <property name="title" translatable="yes"></property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="default_width">350</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="has_separator">False</property>
+
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox12">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">8</property>
+
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area12">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+ <child>
+ <widget class="GtkButton" id="button60">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-cancel</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="response_id">-6</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="button58">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-ok</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="response_id">-5</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">DYNAMIC</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_FILL</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkTable" id="table56">
+ <property name="border_width">6</property>
+ <property name="visible">True</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">3</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+
+ <child>
+ <widget class="GtkLabel" id="label1026">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Password</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">1</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="check_button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">DYNAMIC</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options">expand</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkImage" id="pixmap">
+ <property name="visible">True</property>
+ <property name="stock">gtk-dialog-question</property>
+ <property name="icon_size">6</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options">fill</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="password_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="has_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">False</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char" translatable="yes">*</property>
+ <property name="activates_default">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="y_options">fill</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+<widget class="GtkDialog" id="select_dialog">
+ <property name="border_width">6</property>
+ <property name="title" translatable="yes"></property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="has_separator">False</property>
+
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox16">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">8</property>
+
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area16">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+ <child>
+ <widget class="GtkButton" id="button70">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-cancel</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="response_id">-6</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="button71">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-ok</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="response_id">-5</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkTable" id="table63">
+ <property name="border_width">6</property>
+ <property name="visible">True</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">2</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+
+ <child>
+ <widget class="GtkLabel" id="label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">DYNAMIC</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_FILL</property>
+ <property name="wrap">True</property>
+ <property name="selectable">False</property>
+ <property name="xalign">7.45058e-09</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="y_options">fill</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkImage" id="pixmap">
+ <property name="visible">True</property>
+ <property name="stock">gtk-dialog-question</property>
+ <property name="icon_size">6</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options">shrink|fill</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_NONE</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <widget class="GtkTreeView" id="treeview">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="headers_visible">True</property>
+ <property name="rules_hint">False</property>
+ <property name="reorderable">False</property>
+ <property name="enable_search">True</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+</glade-interface>
diff --git a/data/glade/toolbar-editor.glade b/data/glade/toolbar-editor.glade
new file mode 100644
index 000000000..b5c4704d3
--- /dev/null
+++ b/data/glade/toolbar-editor.glade
@@ -0,0 +1,418 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
+
+<glade-interface>
+
+<widget class="GtkDialog" id="toolbar-editor-dialog">
+ <property name="border_width">6</property>
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">Toolbar Editor</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="has_separator">False</property>
+
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox1">
+ <property name="width_request">450</property>
+ <property name="height_request">350</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area1">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+ <child>
+ <widget class="GtkButton" id="toolbar-editor-revert-button">
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="response_id">0</property>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment1">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">0</property>
+ <property name="yscale">0</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox2">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">2</property>
+
+ <child>
+ <widget class="GtkImage" id="image1">
+ <property name="visible">True</property>
+ <property name="stock">gtk-revert-to-saved</property>
+ <property name="icon_size">4</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label4">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Reset to defaults</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="toolbar-editor-undo-button">
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-undo</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="response_id">0</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="toolbar-editor-close-button">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-close</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="response_id">0</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox1">
+ <property name="border_width">6</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox5">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label5">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;_Available Controls&lt;/b&gt;</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow4">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <widget class="GtkTreeView" id="toolbar-editor-available-view">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="headers_visible">False</property>
+ <property name="rules_hint">False</property>
+ <property name="reorderable">False</property>
+ <property name="enable_search">True</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox4">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <placeholder/>
+ </child>
+
+ <child>
+ <widget class="GtkTable" id="table1">
+ <property name="visible">True</property>
+ <property name="n_rows">3</property>
+ <property name="n_columns">3</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">0</property>
+ <property name="column_spacing">0</property>
+
+ <child>
+ <widget class="GtkButton" id="toolbar-editor-up-button">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NONE</property>
+
+ <child>
+ <widget class="GtkArrow" id="arrow2">
+ <property name="visible">True</property>
+ <property name="arrow_type">GTK_ARROW_UP</property>
+ <property name="shadow_type">GTK_SHADOW_OUT</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options"></property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="toolbar-editor-right-button">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NONE</property>
+
+ <child>
+ <widget class="GtkArrow" id="arrow1">
+ <property name="visible">True</property>
+ <property name="arrow_type">GTK_ARROW_RIGHT</property>
+ <property name="shadow_type">GTK_SHADOW_OUT</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options"></property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="toolbar-editor-down-button">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NONE</property>
+
+ <child>
+ <widget class="GtkArrow" id="arrow4">
+ <property name="visible">True</property>
+ <property name="arrow_type">GTK_ARROW_DOWN</property>
+ <property name="shadow_type">GTK_SHADOW_OUT</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options"></property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="toolbar-editor-left-button">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NONE</property>
+
+ <child>
+ <widget class="GtkArrow" id="arrow3">
+ <property name="visible">True</property>
+ <property name="arrow_type">GTK_ARROW_LEFT</property>
+ <property name="shadow_type">GTK_SHADOW_OUT</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options"></property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">4</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox6">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label6">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Cu_rrent Controls&lt;/b&gt;</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow5">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <widget class="GtkTreeView" id="toolbar-editor-current-view">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="headers_visible">False</property>
+ <property name="rules_hint">False</property>
+ <property name="reorderable">False</property>
+ <property name="enable_search">True</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+</glade-interface>
diff --git a/data/start_here.html b/data/start_here.html
new file mode 100644
index 000000000..73a0e908e
--- /dev/null
+++ b/data/start_here.html
@@ -0,0 +1,23 @@
+<html>
+<head>
+</head>
+<body>
+<h1>Welcome ...</h1>
+<h2>Smart Bookmarks</h2>
+<p>
+Right click the icon and choose "Add Bookmark" from the menu list.
+</p>
+<dl>
+<li>
+<a type="text/smartbookmark" href="http://www.google.com/" rel="http://www.google.com/search?q=%s" title="Search the web - Google">
+Search the web - Google
+</a>
+</li>
+<li>
+<a type="text/smartbookmark" href="http://images.google.com/" rel="http://images.google.com/images?q=%s" title="Search images - Google">
+Search images - Google
+</a>
+</li>
+</ol>
+</body>
+</html>
diff --git a/data/ui/.cvsignore b/data/ui/.cvsignore
new file mode 100644
index 000000000..765506f45
--- /dev/null
+++ b/data/ui/.cvsignore
@@ -0,0 +1,4 @@
+Makefile
+Makefile.in
+epiphany-ui.xml
+nautilus-epiphany-view.xml
diff --git a/data/ui/Makefile.am b/data/ui/Makefile.am
new file mode 100644
index 000000000..658ebf3f1
--- /dev/null
+++ b/data/ui/Makefile.am
@@ -0,0 +1,11 @@
+uixmldir = $(datadir)/gnome-2.0/ui
+uixml_in_files = epiphany-ui.xml.in \
+ nautilus-epiphany-view.xml.in
+
+uixml_DATA = $(uixml_in_files:.xml.in=.xml)
+
+@INTLTOOL_XML_RULE@
+
+EXTRA_DIST = $(uixml_in_files)
+
+CLEANFILES = $(uixml_DATA)
diff --git a/data/ui/epiphany-ui.xml.in b/data/ui/epiphany-ui.xml.in
new file mode 100644
index 000000000..cb966a4e4
--- /dev/null
+++ b/data/ui/epiphany-ui.xml.in
@@ -0,0 +1,454 @@
+<Root>
+
+<commands>
+ <cmd name="FileOpen" _label="Open"
+ _tip="Open a file" pixtype="stock" pixname="gtk-open" accel="*Control*O"/>
+
+ <cmd name="FileSaveAs" _label="Save As"
+ _tip="Save the current file with a different name"
+ pixtype="stock" pixname="gtk-save-as"
+ accel="*Shift**Control*S"/>
+
+ <cmd name="FilePrint" _label="Print"
+ _tip="Print the current file" pixtype="stock" pixname="gtk-print"
+ accel="*Control*P"/>
+
+ <cmd name="FileCloseTab" _tip="Close the current tab"
+ pixtype="stock" pixname="gtk-close"/>
+
+ <cmd name="FileCloseWindow" _tip="Close the current window"/>
+
+ <cmd name="EditCut" _label="Cut" _tip="Cut the selection"
+ pixtype="stock" pixname="gtk-cut"/>
+
+ <cmd name="EditCopy" _label="Copy"
+ _tip="Copy the selection" pixtype="stock" pixname="gtk-copy"/>
+
+ <cmd name="EditPaste" _label="Paste"
+ _tip="Paste the clipboard" pixtype="stock" pixname="gtk-paste"/>
+
+ <cmd name="EditSelectAll" _label="Select All" _tip="Select the entire document"
+ accel="*Control*A"/>
+
+ <cmd name="EditFind" _label="Find" _tip="Search for a string"
+ pixtype="stock" pixname="gtk-find" accel="*Control*F"/>
+
+ <cmd name="Zoom In" _label="Zoom In"
+ _tip="Show the contents in more detail"/>
+ <cmd name="Zoom Out" _label="Zoom Out"
+ _tip="Show the contents in less detail"/>
+ <cmd name="Zoom Normal" _label="Normal Size"
+ _tip="Show the contents at the normal size"/>
+
+ <cmd name="SettingsPreferences" _label="Preferences" _tip="Configure the application"
+ pixtype="stock" pixname="gtk-preferences"/>
+
+ <cmd name="SettingsToolbarEditor" _label="Toolbar" _tip="Edit the main toolbar"/>
+
+ <cmd name="HelpContents" _label="Contents" _tip="Open the Epiphany manual"
+ accel="F1"/>
+
+ <cmd name="About" _label="About..." _tip="About this application"
+ pixtype="stock" pixname="About"/>
+
+ <cmd name="BookmarksAddDefault" _label="Add bookmark"
+ _tip="Add a bookmark to the default folder"/>
+
+ <cmd name="BookmarksEdit" _label="Edit bookmarks"
+ _tip="Open a bookmarks editor"/>
+
+ <cmd name="GoBack" _label="_Back"
+ sensitive="0"/>
+
+ <cmd name="GoUp" _label="_Up"
+ sensitive="0"/>
+
+ <cmd name="GoHome" _label="_Home"/>
+
+ <cmd name="GoMyportal" _label="_My portal"/>
+
+ <cmd name="GoForward" _label="_Forward"
+ sensitive="0"/>
+
+ <cmd name="GoStop" _label="_Stop"
+ sensitive="0"
+ _tip="Stop current data transfer"/>
+
+ <cmd name="GoReload" _label="_Reload"
+ _tip="Display the latest content of the current page"/>
+
+ <cmd name="GoGo" _label="_Go"
+ _tip="Load the URL in the location entry"/>
+
+ <cmd name="EPOpenInNewWindow" _label="Open in New Window"/>
+
+ <cmd name="EPOpenInNewTab" _label="Open in New Tab"/>
+
+ <cmd name="EPCopyLinkLocation" _label="Copy Link Location"/>
+
+ <cmd name="EPCopyEmail" _label="Copy Email Address"/>
+
+ <cmd name="EPDownloadLink" _label="Download Link"/>
+
+ <cmd name="EPAddBookmark" _label="Add Bookmark"/>
+
+ <cmd name="EPOpenImage" _label="Open Image"/>
+
+ <cmd name="EPOpenImageInNewWindow" _label="Open Image in New Window"/>
+
+ <cmd name="EPOpenImageInNewTab" _label="Open Image in New Tab"/>
+
+ <cmd name="EPSaveImageAs" _label="Save Image As..."/>
+
+ <cmd name="EPSetImageAsBackground" _label="Use Image as Background"/>
+
+ <cmd name="EPCopyImageLocation" _label="Copy Image Location"/>
+
+ <cmd name="DPCopyLocation" _label="Copy Page location"/>
+
+ <cmd name="DPOpenFrame" _label="Open Frame"/>
+
+ <cmd name="DPOpenFrameInNewWindow" _label="Open Frame in New Window"/>
+
+ <cmd name="DPOpenFrameInNewTab" _label="Open Frame in New Tab"/>
+
+ <cmd name="DPReloadFrame" _label="Reload Frame"/>
+
+ <cmd name="DPAddFrameBookmark" _label="Add Bookmark for Frame"/>
+
+ <cmd name="DPSavePageAs" _label="Save Page As..."/>
+
+ <cmd name="DPSaveBackgroundAs" _label="Save Background As..."/>
+
+ <cmd name="DPAddPageBookmark" verb="Add Bookmark"/>
+
+ <cmd name="PPVGotoFirst" _label="First"/>
+
+ <cmd name="PPVGotoLast" _label="Last"/>
+
+ <cmd name="PPVGoBack" _label="Previous"/>
+
+ <cmd name="PPVGoForward" _label="Next"/>
+
+</commands>
+
+<keybindings>
+ <accel name="*Control*S" verb="FileSaveAs"/>
+</keybindings>
+
+<menu>
+
+<submenu name="File" _label="_File">
+
+ <menuitem name="FileNewWindow" verb=""
+ _label="_New Window"
+ pixtype="stock" pixname="gtk-new"
+ accel="*Control*n"/>
+
+ <menuitem name="FileNewTab" verb="" _label="New _Tab" accel="*Control*t"/>
+
+ <menuitem name="FileOpen" verb="" _label="_Open..."/>
+
+ <separator/>
+
+ <menuitem name="FileSaveAs" verb="" _label="Save _As..."/>
+
+ <separator/>
+
+ <menuitem name="FilePrint" verb="" _label="_Print..."/>
+ <menuitem name="FileSendTo" verb=""
+ pixtype="stock" pixname="epiphany-send-link"
+ _label="S_end To..."/>
+
+ <separator/>
+
+ <menuitem name="BookmarksAddDefault" verb="" _label="_Add Bookmark"
+ _tip="Add a bookmark for the current location to the default folder"
+ pixtype="stock" pixname="gtk-add" accel="*Control*d"/>
+
+ <separator/>
+
+ <menuitem name="FileCloseTab" verb="" _label="_Close Tab" accel="*Control*W"/>
+
+ <menuitem name="FileCloseWindow" verb="" _label="Close _Window" accel="*Shift**Control*W"/>
+
+</submenu>
+
+<submenu name="Edit" _label="_Edit">
+
+ <menuitem name="EditCut" verb="" _label="Cu_t" accel="*Control*X"/>
+
+ <menuitem name="EditCopy" verb="" _label="_Copy" accel="*Control*c"/>
+
+ <menuitem name="EditPaste" verb="" _label="_Paste" accel="*Control*v"/>
+
+ <separator/>
+
+ <menuitem name="EditSelectAll" verb="" _label="Select _All"/>
+
+ <separator/>
+
+ <menuitem name="EditFind" verb="" _label="_Find..."/>
+ <menuitem name="EditFindNext" verb=""
+ accel="*Control*G" _label="Find Ne_xt"/>
+ <menuitem name="EditFindPrev" verb=""
+ accel="*Shift**Control*G" _label="Find Pre_vious"/>
+
+ <separator/>
+
+ <menuitem name="PDM" verb="ToolsPDM" _label="P_ersonal Data"/>
+
+ <menuitem name="EditToolbar"
+ _label="T_oolbar"
+ verb="SettingsToolbarEditor"/>
+
+ <menuitem name="EditPrefs"
+ _label="P_references"
+ _tip="Edit Ephy preferences"
+ pixtype="stock" pixname="gtk-preferences"
+ verb="EditPrefs"/>
+</submenu>
+
+<submenu name="View" _label="_View">
+
+ <menuitem name="GoStop"
+ pixtype="stock" pixname="gtk-stop"
+ verb="" accel="Escape"/>
+
+ <menuitem name="GoReload"
+ pixtype="stock" pixname="gtk-refresh"
+ verb="" accel="*Control*R"/>
+
+ <separator/>
+
+ <menuitem name="View Toolbar" id="View Toolbar" type="toggle"
+ _label="_Toolbar" verb="" accel="*Shift**Control*T"/>
+
+ <menuitem name="View Statusbar" id="View Statusbar"
+ type="toggle" _label="St_atusbar" verb=""/>
+
+ <menuitem name="View Fullscreen" id="View Fullscreen"
+ type="toggle" _label="_Fullscreen" verb="" accel="F11"/>
+
+ <separator/>
+
+ <menuitem name="Zoom In"
+ _label="Zoom _In" accel="*Control*plus"
+ pixtype="stock" pixname="zoom-in"
+ verb="Zoom In"/>
+
+ <menuitem name="Zoom Out"
+ _label="Zoom _Out" accel="*Control*minus"
+ pixtype="stock" pixname="zoom-out"
+ verb="Zoom Out"/>
+
+ <menuitem name="Zoom Normal"
+ _label="_Normal Size"
+ pixtype="stock" pixname="zoom-100"
+ verb="Zoom Normal"/>
+
+ <separator/>
+
+ <placeholder name="EncodingMenuPlaceholder"/>
+
+ <menuitem name="Page Source"
+ _label="_Page Source"
+ verb="ViewPageSource"/>
+
+</submenu>
+
+<submenu name="Go" _label="_Go">
+ <menuitem name="GoBack"
+ pixtype="stock" pixname="gtk-go-back"
+ verb="" accel="*Alt*Left"/>
+
+ <menuitem name="GoForward"
+ pixtype="stock" pixname="gtk-go-forward"
+ verb="" accel="*Alt*Right"/>
+
+ <menuitem name="GoUp"
+ pixtype="stock" pixname="gtk-go-up"
+ verb="" accel="*Alt*Up"/>
+
+ <separator/>
+
+ <menuitem name="GoHome"
+ pixtype="stock" pixname="gtk-home"
+ verb="" accel="*Alt*Home"/>
+
+ <menuitem name="GoLocation" _label="_Location..."
+ verb="" accel="*Ctrl*l"/>
+
+ <separator/>
+
+ <menuitem name="History" verb="ToolsHistory"
+ _label="_History" accel="*Control*H"/>
+
+ <menuitem name="BookmarksEdit" verb="" _label="_Bookmarks"
+ accel="*Control*b"/>
+
+ <placeholder name="Favorites" delimit="top"/>
+</submenu>
+
+<submenu name="Tabs" _label="_Tabs">
+ <menuitem name="Previous Tab" verb="TabsPrevious" _label="_Previous Tab"
+ accel="*Control*Page_Up"/>
+ <menuitem name="Next Tab" verb="TabsNext" _label="_Next Tab"
+ accel="*Control*Page_Down"/>
+ <separator/>
+ <menuitem name="Tab Left" verb="TabsMoveLeft" _label="Move Tab _Left"
+ accel="*Shift**Control*Page_Up"/>
+ <menuitem name="Tab Right" verb="TabsMoveRight" _label="Move Tab _Right"
+ accel="*Shift**Control*Page_Down"/>
+ <menuitem name="Move Tab to New Window" verb="TabsDetach" _label="_Detach Tab"
+ accel="*Shift**Control*m"/>
+</submenu>
+
+<submenu name="Help" _label="_Help">
+
+ <menuitem name="HelpContents" verb=""
+ pixtype="stock" pixname="gtk-help"
+ _label="_Contents"/>
+
+ <menuitem name="About" verb="" _label="_About"/>
+
+</submenu>
+
+</menu>
+
+<popups>
+
+ <popup name="EphyEmbedInputPopup">
+ <menuitem name="EditCut"
+ pixtype="stock" pixname="gtk-cut"
+ verb=""/>
+ <menuitem name="EditCopy"
+ pixtype="stock" pixname="gtk-copy"
+ verb=""/>
+ <menuitem name="EditPaste"
+ pixtype="stock" pixname="gtk-paste"
+ verb=""/>
+ </popup>
+
+ <popup name="EphyEmbedDocumentPopup">
+ <placeholder name="NavigationItems">
+ <menuitem name="GoBack"
+ pixtype="stock" pixname="gtk-go-back"
+ verb=""/>
+
+ <menuitem name="GoForward"
+ pixtype="stock" pixname="gtk-go-forward"
+ verb=""/>
+
+ <menuitem name="GoReload"
+ pixtype="stock" pixname="gtk-refresh"
+ verb=""/>
+
+ <separator/>
+ </placeholder>
+
+ <menuitem name="DPSavePageAs"
+ pixtype="stock" pixname="gtk-save"
+ verb=""/>
+
+ <menuitem name="DPSaveBackgroundAs" verb=""/>
+
+ <menuitem name="DPViewSource" _label="Page Source"
+ verb="ViewPageSource"/>
+
+ <menuitem name="DPAddPageBookmark"
+ verb=""/>
+
+ <menuitem name="DPCopyLocation"
+ pixtype="stock" pixname="gtk-copy"
+ verb=""/>
+
+ <placeholder name="FrameItems">
+ <separator/>
+ <menuitem name="DPOpenFrame" verb=""/>
+ <menuitem name="DPOpenFrameInNewWindow" verb=""/>
+ <menuitem name="DPOpenFrameInNewTab" verb=""/>
+ <menuitem name="DPReloadFrame" verb=""/>
+ <menuitem name="DPAddFrameBookmark" verb=""/>
+ </placeholder>
+ </popup>
+
+ <popup name="EphyEmbedElementPopup">
+ <placeholder name="LinkItems">
+ <menuitem name="EPOpenInNewWindow"
+ pixtype="stock" pixname="gtk-open"
+ verb=""/>
+
+ <menuitem name="EPOpenInNewTab" verb=""/>
+
+ <menuitem name="EPCopyLinkLocation"
+ pixtype="stock" pixname="gtk-copy"
+ verb=""/>
+
+ <menuitem name="EPDownloadLink" verb=""/>
+
+ <menuitem name="EPAddBookmark"
+ pixtype="stock" pixname="gtk-add"
+ verb=""/>
+ </placeholder>
+ <placeholder name="EmailLinkItems">
+ <menuitem name="EPCopyEmail"
+ pixtype="stock" pixname="gtk-copy"
+ verb=""/>
+ </placeholder>
+ <placeholder name="BetweenElements1">
+ <separator/>
+ </placeholder>
+
+ <placeholder name="ImageItems">
+ <menuitem name="EPOpenImage"
+ pixtype="stock" pixname="gtk-open"
+ verb=""/>
+
+ <menuitem name="EPOpenImageInNewWindow" verb=""/>
+ <menuitem name="EPOpenImageInNewTab" verb=""/>
+
+ <menuitem name="EPSaveImageAs"
+ pixtype="stock" pixname="gtk-save"
+ verb=""/>
+
+ <menuitem name="EPSetImageAsBackground" verb=""/>
+
+ <menuitem name="EPCopyImageLocation"
+ pixtype="stock" pixname="gtk-copy"
+ verb=""/>
+ </placeholder>
+ </popup>
+</popups>
+
+<dockitem name="Toolbar" behavior="exclusive" config="0">
+</dockitem>
+
+<dockitem name="PrintPreview" behavior="exclusive">
+ <toolitem name="PPVGotoFirst"
+ pixtype="stock" pixname="gtk-goto-first"
+ verb="PPVGotoFirst"/>
+ <toolitem name="PPVGoBack"
+ pixtype="stock" pixname="gtk-go-back"
+ verb="PPVGoBack"/>
+ <toolitem name="PPVGoForward"
+ pixtype="stock" pixname="gtk-go-forward"
+ priority="1"
+ verb="PPVGoForward"/>
+ <toolitem name="PPVGotoLast"
+ pixtype="stock" pixname="gtk-goto-last"
+ verb="PPVGotoLast"/>
+ <toolitem name="Close" _label="Close"
+ pixtype="stock" pixname="gtk-close"
+ priority="1"
+ verb="PPVClose"/>
+</dockitem>
+
+<status resize_grip="0">
+ <item name="main"/>
+ <control name="SecurityIconWrapper"/>
+ <control name="ProgressWrapper"/>
+</status>
+
+</Root>
+
diff --git a/data/ui/nautilus-epiphany-view.xml.in b/data/ui/nautilus-epiphany-view.xml.in
new file mode 100644
index 000000000..d46e5f9f4
--- /dev/null
+++ b/data/ui/nautilus-epiphany-view.xml.in
@@ -0,0 +1,130 @@
+<Root>
+<commands>
+
+ <cmd name="FilePrint" _label="Print"
+ _tip="Print the Current File" pixtype="stock" pixname="gtk-print"
+ accel="*Control*P"/>
+
+ <cmd name="EditCut" _label="Cut" _tip="Cut the Selection"
+ pixtype="stock" pixname="gtk-cut"/>
+
+ <cmd name="EditCopy" _label="Copy"
+ _tip="Copy the Selection" pixtype="stock" pixname="gtk-copy"/>
+
+ <cmd name="EditPaste" _label="Paste"
+ _tip="Paste the Clipboard" pixtype="stock" pixname="gtk-paste"/>
+
+ <cmd name="EditSelectAll" _label="Select All" _tip="Select the Entire Document"
+ accel="*Control*A"/>
+
+ <cmd name="EditFind" _label="Find" _tip="Search for a String"
+ pixtype="stock" pixname="gtk-find" accel="*Control*F"/>
+
+
+ <cmd name="EPOpenInNewWindow" _label="Open in New Window"
+ pixtype="stock" pixname="gtk-new"/>
+
+ <cmd name="EPCopyLinkLocation" _label="Copy Link Location"
+ pixtype="stock" pixname="gtk-copy"/>
+
+ <cmd name="EPDownloadLink" _label="Download Link"/>
+
+ <cmd name="EPOpenImage" _label="Open Image"
+ pixtype="stock" pixname="gtk-open"/>
+
+ <cmd name="EPOpenImageInNewWindow" _label="Open Image in New Window"/>
+
+ <cmd name="EPSaveImageAs" _label="Save Image As..."
+ pixtype="stock" pixname="gtk-save"/>
+
+ <cmd name="EPSetImageAsBackground" _label="Use Image as Background"/>
+
+ <cmd name="EPCopyImageLocation" _label="Copy Image Location"
+ pixtype="stock" pixname="gtk-copy"/>
+
+ <cmd name="DPCopyLocation" _label="Copy Page Location"
+ pixtype="stock" pixname="gtk-copy"/>
+
+ <cmd name="DPOpenFrame" _label="Open Frame"
+ pixtype="stock" pixname="gtk-open"/>
+
+ <cmd name="DPOpenFrameInNewWindow" _label="Open Frame in New Window"/>
+
+ <cmd name="DPAddFrameBookmark" _label="Add Bookmark for Frame"
+ pixtype="stock" pixname="gtk-add"/>
+
+ <cmd name="DPSavePageAs" _label="Save Page As..."
+ pixtype="stock" pixname="gtk-save"/>
+
+ <cmd name="DPSaveBackgroundAs" _label="Save Background As..."/>
+
+ <cmd name="PPVGotoFirst" _label="First"/>
+
+ <cmd name="PPVGotoLast" _label="Last"/>
+
+ <cmd name="PPVGoBack" _label="Previous"/>
+
+ <cmd name="PPVGoForward" _label="Next"/>
+
+ <cmd name="EPCopyEmail" _label="Copy Email Address"/>
+
+</commands>
+
+<menu>
+ <submenu name="File" _label="_File">
+ <menuitem name="FilePrint" verb="" _label="_Print..."/>
+ </submenu>
+ <submenu name="Edit" _label="_Edit">
+ <menuitem name="EditFind" verb="" _label="_Find..."/>
+ </submenu>
+ <submenu name="View">
+ <placeholder name="Encoding"/>
+ </submenu>
+</menu>
+
+<popups>
+
+ <popup name="EphyEmbedInputPopup">
+ <menuitem name="EditCut" verb=""/>
+ <menuitem name="EditCopy" verb=""/>
+ <menuitem name="EditPaste" verb=""/>
+ </popup>
+
+ <popup name="EphyEmbedDocumentPopup">
+ <menuitem name="DPSavePageAs" verb=""/>
+ <menuitem name="DPSaveBackgroundAs" verb=""/>
+ <menuitem name="DPCopyLocation" verb=""/>
+ <submenu name="DPOpenWith" _label="Open With"/>
+ <placeholder name="FrameItems">
+ <separator/>
+ <menuitem name="DPOpenFrame" verb=""/>
+ <menuitem name="DPOpenFrameInNewWindow" verb=""/>
+ </placeholder>
+ </popup>
+
+ <popup name="EphyEmbedElementPopup">
+ <placeholder name="LinkItems">
+ <menuitem name="EPOpenInNewWindow" verb=""/>
+ <menuitem name="EPCopyLinkLocation" verb=""/>
+ <menuitem name="EPDownloadLink" verb=""/>
+ </placeholder>
+ <placeholder name="EmailLinkItems">
+ <menuitem name="EPCopyEmail"
+ pixtype="stock" pixname="gtk-copy"
+ verb=""/>
+ </placeholder>
+ <placeholder name="BetweenElements1">
+ <separator/>
+ </placeholder>
+ <placeholder name="ImageItems">
+ <menuitem name="EPOpenImage" verb=""/>
+ <submenu name="EPOpenImageWith" _label="Open Image with"/>
+ <menuitem name="EPOpenImageInNewWindow" verb=""/>
+ <menuitem name="EPSaveImageAs" verb=""/>
+ <menuitem name="EPSetImageAsBackground" verb=""/>
+ <menuitem name="EPCopyImageLocation" verb=""/>
+ </placeholder>
+ </popup>
+</popups>
+
+</Root>
diff --git a/embed/.cvsignore b/embed/.cvsignore
new file mode 100644
index 000000000..20e4cb0c8
--- /dev/null
+++ b/embed/.cvsignore
@@ -0,0 +1,6 @@
+Makefile
+Makefile.in
+*.lo
+.deps
+.libs
+*.la
diff --git a/embed/Makefile.am b/embed/Makefile.am
new file mode 100644
index 000000000..a6f43fb46
--- /dev/null
+++ b/embed/Makefile.am
@@ -0,0 +1,57 @@
+SUBDIRS = mozilla
+
+INCLUDES = \
+ -I$(top_srcdir)/embed/mozilla \
+ -I$(top_srcdir)/lib \
+ -I$(top_srcdir)/lib/widgets \
+ -I$(MOZILLA_INCLUDE_ROOT)/gtkembedmoz \
+ $(WARN_CFLAGS) \
+ $(EPIPHANY_DEPENDENCY_CFLAGS) \
+ -DSHARE_DIR=\"$(pkgdatadir)\" \
+ -DG_DISABLE_DEPRECATED \
+ -DGDK_DISABLE_DEPRECATED \
+ -DGTK_DISABLE_DEPRECATED \
+ -DGDK_PIXBUF_DISABLE_DEPRECATED \
+ -DGNOME_DISABLE_DEPRECATED
+
+noinst_LTLIBRARIES = libephyembed.la
+
+libephyembed_la_SOURCES = \
+ ephy-embed-types.h \
+ downloader-view.c \
+ downloader-view.h \
+ ephy-history.c \
+ ephy-history.h \
+ ephy-embed.c \
+ ephy-embed.h \
+ ephy-embed-shell.c \
+ ephy-embed-shell.h \
+ ephy-embed-persist.c \
+ ephy-embed-persist.h \
+ ephy-embed-popup.c \
+ ephy-embed-popup.h \
+ ephy-embed-popup-bw.c \
+ ephy-embed-popup-bw.h \
+ ephy-embed-popup-control.c \
+ ephy-embed-popup-control.h \
+ ephy-embed-event.c \
+ ephy-embed-event.h \
+ ephy-embed-utils.c \
+ ephy-embed-utils.h \
+ ephy-embed-dialog.c \
+ ephy-embed-dialog.h \
+ find-dialog.c \
+ find-dialog.h \
+ print-dialog.c \
+ print-dialog.h \
+ ephy-embed-prefs.h \
+ ephy-favicon-cache.c \
+ ephy-favicon-cache.h \
+ ephy-embed-favicon.c \
+ ephy-embed-favicon.h \
+ ephy-favicon.c \
+ ephy-favicon.h
+
+
+libephyembed_la_LIBADD = \
+ $(top_builddir)/embed/mozilla/libephymozillaembed.la
diff --git a/embed/downloader-view.c b/embed/downloader-view.c
new file mode 100644
index 000000000..97e05a613
--- /dev/null
+++ b/embed/downloader-view.c
@@ -0,0 +1,1100 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "downloader-view.h"
+#include "eel-gconf-extensions.h"
+#include "ephy-gui.h"
+#include "ephy-prefs.h"
+#include "ephy-ellipsizing-label.h"
+#include "ephy-embed-utils.h"
+#include "ephy-file-helpers.h"
+
+#include <gtk/gtktreeview.h>
+#include <gtk/gtkliststore.h>
+#include <gtk/gtktreeviewcolumn.h>
+#include <libgnome/gnome-i18n.h>
+#include <libgnomeui/gnome-dialog-util.h>
+#include <libgnomeui/gnome-dialog.h>
+#include <gtk/gtkprogressbar.h>
+#include <libgnomevfs/gnome-vfs-mime-handlers.h>
+
+enum
+{
+ DOWNLOAD_REMOVE,
+ DOWNLOAD_PAUSE,
+ DOWNLOAD_RESUME,
+ LAST_SIGNAL
+};
+
+enum
+{
+ COL_PERCENT,
+ COL_FILENAME,
+ COL_SIZE,
+ COL_REMAINING,
+ COL_PERSIST_OBJECT
+};
+
+struct DownloaderViewPrivate
+{
+ GHashTable *details_hash;
+ GtkTreeModel *model;
+ gboolean show_details;
+
+ /* Widgets */
+ GtkWidget *treeview;
+ GtkWidget *details_file;
+ GtkWidget *details_location;
+ GtkWidget *details_status;
+ GtkWidget *details_elapsed;
+ GtkWidget *details_remaining;
+ GtkWidget *details_progress;
+ GtkWidget *details_button;
+ GtkWidget *keep_open_check;
+ GtkWidget *pause_button;
+ GtkWidget *resume_button;
+ GtkWidget *abort_button;
+ GtkWidget *open_button;
+};
+
+typedef struct
+{
+ glong elapsed;
+ glong remaining;
+ gfloat speed;
+ gint size_total;
+ gint size_done;
+ gfloat progress;
+ gboolean can_pause;
+ gchar *filename;
+ gchar *source;
+ gchar *dest;
+ DownloadStatus status;
+
+ GtkTreeRowReference *ref;
+} DownloadDetails;
+
+typedef struct
+{
+ gboolean can_resume;
+ gboolean can_pause;
+ gboolean can_abort;
+ gboolean can_open;
+ DownloaderViewPrivate *priv;
+} ControlsInfo;
+
+enum
+{
+ PROP_TREEVIEW,
+ PROP_KEEP_OPEN,
+ PROP_DETAILS_FRAME,
+ PROP_DETAILS_SEPARATOR,
+ PROP_DETAILS_TABLE,
+ PROP_DETAILS_STATUS,
+ PROP_DETAILS_ELAPSED,
+ PROP_DETAILS_REMAINING,
+ PROP_DETAILS_PROGRESS,
+ PROP_PAUSE_BUTTON,
+ PROP_RESUME_BUTTON,
+ PROP_ABORT_BUTTON,
+ PROP_OPEN_BUTTON,
+ PROP_DETAILS_BUTTON
+};
+
+static const
+EphyDialogProperty properties [] =
+{
+ { PROP_TREEVIEW, "clist", NULL, PT_NORMAL, NULL },
+ { PROP_KEEP_OPEN, "keep_open_check", CONF_DOWNLOADING_KEEP_OPEN, PT_NORMAL, NULL },
+ { PROP_DETAILS_FRAME, "details_frame", NULL, PT_NORMAL, NULL },
+ { PROP_DETAILS_SEPARATOR, "details_separator", NULL, PT_NORMAL, NULL },
+ { PROP_DETAILS_TABLE, "details_table", NULL, PT_NORMAL, NULL },
+ { PROP_DETAILS_STATUS, "details_status", NULL, PT_NORMAL, NULL },
+ { PROP_DETAILS_ELAPSED, "details_elapsed", NULL, PT_NORMAL, NULL },
+ { PROP_DETAILS_REMAINING, "details_remaining", NULL, PT_NORMAL, NULL },
+ { PROP_DETAILS_PROGRESS, "details_progress", NULL, PT_NORMAL, NULL },
+ { PROP_PAUSE_BUTTON, "pause_button", NULL, PT_NORMAL, NULL },
+ { PROP_RESUME_BUTTON, "resume_button", NULL, PT_NORMAL, NULL },
+ { PROP_ABORT_BUTTON, "abort_button", NULL, PT_NORMAL, NULL },
+ { PROP_OPEN_BUTTON, "open_button", NULL, PT_NORMAL, NULL },
+ { PROP_DETAILS_BUTTON, "details_togglebutton", CONF_DOWNLOADING_SHOW_DETAILS, PT_NORMAL, NULL },
+
+ { -1, NULL, NULL }
+};
+
+static void
+downloader_view_build_ui (DownloaderView *dv);
+static void
+downloader_view_class_init (DownloaderViewClass *klass);
+static void
+downloader_view_finalize (GObject *object);
+static void
+downloader_view_init (DownloaderView *dv);
+
+/* Callbacks */
+void
+download_dialog_resume_cb (GtkButton *button, DownloaderView *dv);
+void
+download_dialog_pause_cb (GtkButton *button, DownloaderView *dv);
+void
+download_dialog_abort_cb (GtkButton *button, DownloaderView *dv);
+static void
+downloader_treeview_selection_changed_cb (GtkTreeSelection *selection,
+ DownloaderView *dv);
+gboolean
+download_dialog_delete_cb (GtkWidget *window, GdkEventAny *event,
+ DownloaderView *dv);
+void
+download_dialog_details_cb (GtkToggleButton *button,
+ DownloaderView *dv);
+void
+download_dialog_open_cb (GtkWidget *button,
+ DownloaderView *dv);
+
+static GObjectClass *parent_class = NULL;
+static guint downloader_view_signals[LAST_SIGNAL] = { 0 };
+
+GType
+downloader_view_get_type (void)
+{
+ static GType downloader_view_type = 0;
+
+ if (downloader_view_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (DownloaderViewClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) downloader_view_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (DownloaderView),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) downloader_view_init
+ };
+
+ downloader_view_type = g_type_register_static (EPHY_DIALOG_TYPE,
+ "DownloaderView",
+ &our_info, 0);
+ }
+
+ return downloader_view_type;
+}
+
+static void
+format_time (gchar *buffer, glong time)
+{
+ gint secs, hours, mins;
+
+ secs = (gint)(time + .5);
+ hours = secs / 3600;
+ secs -= hours * 3600;
+ mins = secs / 60;
+ secs -= mins * 60;
+
+ if (hours)
+ {
+ sprintf (buffer, "%u:%02u.%02u", hours, mins, secs);
+ }
+ else
+ {
+ sprintf (buffer, "%02u.%02u", mins, secs);
+ }
+}
+
+static void
+downloader_view_class_init (DownloaderViewClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ EphyDialogClass *ephy_dialog_class;
+
+ parent_class = g_type_class_peek_parent (klass);
+ ephy_dialog_class = EPHY_DIALOG_CLASS (klass);
+
+ object_class->finalize = downloader_view_finalize;
+
+ /* init signals */
+ downloader_view_signals[DOWNLOAD_REMOVE] =
+ g_signal_new ("download_remove",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (DownloaderViewClass, download_remove),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+ downloader_view_signals[DOWNLOAD_PAUSE] =
+ g_signal_new ("download_pause",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (DownloaderViewClass, download_pause),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+ downloader_view_signals[DOWNLOAD_RESUME] =
+ g_signal_new ("download_resume",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (DownloaderViewClass, download_resume),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+
+}
+
+static void
+destroy_details_cb (DownloadDetails *details)
+{
+ g_free (details->filename);
+ g_free (details->source);
+ g_free (details->dest);
+ g_free (details);
+}
+
+static void
+downloader_view_init (DownloaderView *dv)
+{
+ dv->priv = g_new0 (DownloaderViewPrivate, 1);
+ dv->priv->details_hash = g_hash_table_new_full (g_direct_hash,
+ g_direct_equal,
+ NULL,
+ (GDestroyNotify)destroy_details_cb);
+
+ downloader_view_build_ui (dv);
+}
+
+static void
+downloader_view_finalize (GObject *object)
+{
+ DownloaderView *dv;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (IS_DOWNLOADER_VIEW (object));
+
+ dv = DOWNLOADER_VIEW (object);
+
+ g_return_if_fail (dv->priv != NULL);
+
+ g_hash_table_destroy (dv->priv->details_hash);
+
+ g_free (dv->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+DownloaderView *
+downloader_view_new (void)
+{
+ return DOWNLOADER_VIEW (g_object_new
+ (DOWNLOADER_VIEW_TYPE, NULL));
+}
+
+static void
+controls_info_foreach (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ ControlsInfo *info)
+{
+ DownloadDetails *details;
+ GValue val = {0, };
+ gpointer persist_object;
+
+ gtk_tree_model_get_value (model, iter, COL_PERSIST_OBJECT, &val);
+ persist_object = g_value_get_pointer (&val);
+
+ details = g_hash_table_lookup (info->priv->details_hash,
+ persist_object);
+
+ info->can_pause |= details->can_pause;
+ info->can_resume |= (details->status == DOWNLOAD_STATUS_PAUSED);
+ info->can_abort |= (details->status != DOWNLOAD_STATUS_COMPLETED);
+ info->can_open |= (details->status == DOWNLOAD_STATUS_COMPLETED);
+}
+
+static void
+downloader_view_update_controls (DownloaderViewPrivate *priv)
+{
+ GtkTreeSelection *selection;
+ ControlsInfo *info;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(priv->treeview));
+
+ info = g_new0 (ControlsInfo, 1);
+ info->priv = priv;
+
+ /* initial conditions */
+ info->can_pause = info->can_resume = info->can_abort
+ = info->can_open = FALSE;
+
+ if (selection)
+ {
+ gtk_tree_selection_selected_foreach
+ (selection,
+ (GtkTreeSelectionForeachFunc)controls_info_foreach,
+ info);
+ }
+
+ /* setup buttons */
+ gtk_widget_set_sensitive (priv->pause_button, info->can_pause);
+ gtk_widget_set_sensitive (priv->resume_button, info->can_resume);
+ gtk_widget_set_sensitive (priv->abort_button, info->can_abort);
+ gtk_widget_set_sensitive (priv->open_button, info->can_open);
+
+ g_free (info);
+}
+
+static void
+downloader_view_update_details (DownloaderViewPrivate *priv,
+ DownloadDetails *details)
+{
+ gchar buffer[50];
+
+ ephy_ellipsizing_label_set_text
+ (EPHY_ELLIPSIZING_LABEL (priv->details_location),
+ details->source);
+ ephy_ellipsizing_label_set_text
+ (EPHY_ELLIPSIZING_LABEL (priv->details_file),
+ details->filename);
+
+ if (details->size_total >= 10000)
+ {
+ sprintf (buffer, _("%.1f of %.1f MB"),
+ details->size_done / 1024.0,
+ details->size_total / 1024.0);
+ }
+ else if (details->size_total > 0)
+ {
+ sprintf (buffer, _("%d of %d KB"),
+ details->size_done,
+ details->size_total);
+ }
+ else
+ {
+ sprintf (buffer, _("%d KB"),
+ details->size_done);
+ }
+
+ if (details->speed > 0)
+ {
+ sprintf (buffer, "%s at %.1f KB/s", buffer, details->speed);
+ }
+ gtk_label_set_text (GTK_LABEL (priv->details_status),
+ buffer);
+
+ format_time (buffer, details->elapsed/1000000);
+ gtk_label_set_text (GTK_LABEL (priv->details_elapsed),
+ buffer);
+
+ format_time (buffer, details->remaining);
+ gtk_label_set_text (GTK_LABEL (priv->details_remaining),
+ buffer);
+
+ if (details->progress >= 0)
+ {
+ gtk_progress_bar_set_fraction
+ (GTK_PROGRESS_BAR (priv->details_progress),
+ details->progress);
+ }
+ else
+ {
+ gtk_progress_bar_pulse
+ (GTK_PROGRESS_BAR (priv->details_progress));
+ }
+}
+
+static gboolean
+get_selected_row (DownloaderViewPrivate *priv, GtkTreeIter *iter)
+{
+ GList *l;
+ GtkTreePath *node;
+ GtkTreeSelection *selection;
+ GtkTreeModel *model;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(priv->treeview));
+ l = gtk_tree_selection_get_selected_rows (selection, &model);
+
+ if (l == NULL) return FALSE;
+
+ node = l->data;
+ gtk_tree_model_get_iter (model, iter, node);
+
+ g_list_foreach (l, (GFunc)gtk_tree_path_free, NULL);
+ g_list_free (l);
+
+ return TRUE;
+}
+
+static void
+downloader_view_set_download_info (DownloaderViewPrivate *priv,
+ DownloadDetails *details,
+ GtkTreeIter *iter)
+{
+ gchar buffer[50];
+ GtkTreePath *path;
+ GtkTreePath *selected_path = NULL;
+ GtkTreeIter selected_iter;
+ GtkTreeSelection *selection;
+
+ selection = gtk_tree_view_get_selection
+ (GTK_TREE_VIEW(priv->treeview));
+
+ if (get_selected_row (priv, &selected_iter))
+ {
+ selected_path = gtk_tree_model_get_path
+ (priv->model, &selected_iter);
+ }
+
+ path = gtk_tree_row_reference_get_path (details->ref);
+
+ gtk_list_store_set (GTK_LIST_STORE (priv->model),
+ iter,
+ COL_FILENAME, details->filename,
+ -1);
+
+ /* Progress */
+ if (details->status == DOWNLOAD_STATUS_COMPLETED)
+ details->progress = 1;
+ sprintf (buffer, "%.1f%%",
+ details->progress > 0 ?
+ details->progress * 100.0 :
+ 0);
+ gtk_list_store_set (GTK_LIST_STORE (priv->model),
+ iter,
+ COL_PERCENT, buffer,
+ -1);
+
+ /* Total */
+ if (details->size_total >= 10000)
+ {
+ sprintf (buffer, "%.2f MB", details->size_total / 1024.0);
+ }
+ else if (details->size_total > 0)
+ {
+ sprintf (buffer, "%d KB", details->size_total);
+ }
+ else
+ {
+ sprintf (buffer, _("Unknown"));
+ }
+
+ gtk_list_store_set (GTK_LIST_STORE (priv->model),
+ iter,
+ COL_SIZE, buffer,
+ -1);
+
+ /* Remaining */
+ if (details->remaining >= 0)
+ {
+ format_time (buffer, details->remaining);
+ }
+ else
+ {
+ sprintf (buffer, _("Unknown"));
+ }
+ gtk_list_store_set (GTK_LIST_STORE (priv->model),
+ iter,
+ COL_REMAINING, buffer,
+ -1);
+
+ if (gtk_tree_path_compare (path, selected_path) == 0)
+ {
+ downloader_view_update_details (priv, details);
+ }
+}
+
+static void
+ensure_selected_row (DownloaderView *dv)
+{
+ GtkTreeIter iter;
+ GtkTreeSelection *selection;
+
+ g_return_if_fail (IS_DOWNLOADER_VIEW(dv));
+
+ selection = gtk_tree_view_get_selection
+ (GTK_TREE_VIEW(dv->priv->treeview));
+ if (get_selected_row (dv->priv, &iter))
+ {
+ /* there is already a selection */
+ return;
+ }
+
+ if (gtk_tree_model_get_iter_first (dv->priv->model, &iter))
+ {
+ gtk_tree_selection_select_iter (selection, &iter);
+ }
+}
+
+void
+downloader_view_add_download (DownloaderView *dv,
+ gchar *filename,
+ gchar *source,
+ gchar *dest,
+ gpointer persist_object)
+{
+ GtkTreeIter iter;
+ DownloadDetails *details;
+ GtkTreeSelection *selection;
+
+ details = g_new0 (DownloadDetails, 1);
+ details->filename = g_strdup (filename);
+ details->source = g_strdup (source);
+ details->dest = g_strdup (dest);
+ details->elapsed = -1;
+ details->remaining = -1;
+ details->speed = -1;
+ details->size_total = -1;
+ details->size_done = -1;
+ details->progress = -1;
+ dv->priv->show_details = FALSE;
+
+ g_hash_table_insert (dv->priv->details_hash,
+ persist_object,
+ details);
+
+ gtk_list_store_append (GTK_LIST_STORE (dv->priv->model),
+ &iter);
+
+ details->ref = gtk_tree_row_reference_new
+ (GTK_TREE_MODEL (dv->priv->model),
+ gtk_tree_model_get_path
+ (GTK_TREE_MODEL (dv->priv->model), &iter));
+
+ gtk_list_store_set (GTK_LIST_STORE (dv->priv->model),
+ &iter,
+ COL_PERSIST_OBJECT, persist_object,
+ -1);
+
+ selection = gtk_tree_view_get_selection
+ (GTK_TREE_VIEW(dv->priv->treeview));
+ gtk_tree_selection_unselect_all (selection);
+ gtk_tree_selection_select_iter (selection, &iter);
+
+ downloader_view_set_download_info (dv->priv, details, &iter);
+
+ ephy_dialog_show (EPHY_DIALOG(dv));
+}
+
+void
+downloader_view_remove_download (DownloaderView *dv,
+ gpointer persist_object)
+{
+ DownloadDetails *details;
+ GtkTreeIter iter;
+ GValue keep_open = {0, };
+
+ details = g_hash_table_lookup (dv->priv->details_hash,
+ persist_object);
+ g_return_if_fail (details);
+
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (dv->priv->model),
+ &iter,
+ gtk_tree_row_reference_get_path (details->ref));
+
+ gtk_list_store_remove (GTK_LIST_STORE (dv->priv->model), &iter);
+
+ g_hash_table_remove (dv->priv->details_hash,
+ persist_object);
+
+ ephy_dialog_get_value (EPHY_DIALOG(dv), PROP_KEEP_OPEN, &keep_open);
+
+ if (!g_value_get_boolean (&keep_open) &&
+ g_hash_table_size (dv->priv->details_hash) == 0)
+ {
+ g_object_unref (dv);
+ }
+ else
+ {
+ ensure_selected_row (dv);
+ }
+}
+
+void
+downloader_view_set_download_progress (DownloaderView *dv,
+ glong elapsed,
+ glong remaining,
+ gfloat speed,
+ gint size_total,
+ gint size_done,
+ gfloat progress,
+ gboolean can_pause,
+ gpointer persist_object)
+{
+ DownloadDetails *details;
+ GtkTreeIter iter;
+
+ details = g_hash_table_lookup (dv->priv->details_hash,
+ persist_object);
+ g_return_if_fail (details);
+
+ details->elapsed = elapsed;
+ details->remaining = remaining;
+ details->speed = speed;
+ details->size_total = size_total;
+ details->size_done = size_done;
+ details->can_pause = can_pause;
+ details->progress = progress;
+
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (dv->priv->model),
+ &iter,
+ gtk_tree_row_reference_get_path (details->ref));
+
+ downloader_view_set_download_info (dv->priv, details, &iter);
+}
+
+void
+downloader_view_set_download_status (DownloaderView *dv,
+ DownloadStatus status,
+ gpointer persist_object)
+{
+ DownloadDetails *details;
+ GtkTreeIter iter;
+ GValue keep_open = {0, };
+
+ details = g_hash_table_lookup (dv->priv->details_hash,
+ persist_object);
+ g_return_if_fail (details);
+
+ details->status = status;
+
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (dv->priv->model),
+ &iter,
+ gtk_tree_row_reference_get_path (details->ref));
+
+ downloader_view_set_download_info (dv->priv, details, &iter);
+ downloader_view_update_controls (dv->priv);
+
+ ephy_dialog_get_value (EPHY_DIALOG(dv), PROP_KEEP_OPEN, &keep_open);
+
+ if (status == DOWNLOAD_STATUS_COMPLETED &&
+ !g_value_get_boolean (&keep_open))
+ {
+ downloader_view_remove_download (dv, persist_object);
+ }
+}
+
+static void
+downloader_view_build_ui (DownloaderView *dv)
+{
+ DownloaderViewPrivate *priv = dv->priv;
+ GtkListStore *liststore;
+ GtkTreeViewColumn *column;
+ GtkCellRenderer *renderer;
+ GtkTreeSelection *selection;
+ GtkWidget *details_table;
+ EphyDialog *d = EPHY_DIALOG (dv);
+
+ ephy_dialog_construct (d,
+ properties,
+ "epiphany.glade",
+ "download_manager_dialog");
+
+ /* lookup needed widgets */
+ priv->treeview = ephy_dialog_get_control (d, PROP_TREEVIEW);
+ priv->details_status = ephy_dialog_get_control (d, PROP_DETAILS_STATUS);
+ priv->details_elapsed = ephy_dialog_get_control (d, PROP_DETAILS_ELAPSED);
+ priv->details_remaining = ephy_dialog_get_control (d, PROP_DETAILS_REMAINING);
+ priv->details_progress = ephy_dialog_get_control (d, PROP_DETAILS_PROGRESS);
+ priv->keep_open_check = ephy_dialog_get_control (d, PROP_KEEP_OPEN);
+ priv->details_button = ephy_dialog_get_control (d, PROP_DETAILS_BUTTON);
+ priv->pause_button = ephy_dialog_get_control (d, PROP_PAUSE_BUTTON);
+ priv->resume_button = ephy_dialog_get_control (d, PROP_RESUME_BUTTON);
+ priv->abort_button = ephy_dialog_get_control (d, PROP_ABORT_BUTTON);
+ priv->open_button = ephy_dialog_get_control (d, PROP_OPEN_BUTTON);
+ details_table = ephy_dialog_get_control (d, PROP_DETAILS_TABLE);
+
+ /* create file and location details labels */
+ priv->details_location = ephy_ellipsizing_label_new ("");
+ priv->details_file = ephy_ellipsizing_label_new ("");
+ gtk_table_attach_defaults (GTK_TABLE(details_table), priv->details_location,
+ 1, 2, 0, 1);
+ gtk_table_attach_defaults (GTK_TABLE(details_table), priv->details_file,
+ 1, 2, 1, 2);
+ gtk_misc_set_alignment (GTK_MISC(priv->details_location), 0, 0);
+ gtk_misc_set_alignment (GTK_MISC(priv->details_file), 0, 0);
+ gtk_label_set_selectable (GTK_LABEL(priv->details_location), TRUE);
+ gtk_label_set_selectable (GTK_LABEL(priv->details_file), TRUE);
+ gtk_widget_show (priv->details_location);
+ gtk_widget_show (priv->details_file);
+
+ liststore = gtk_list_store_new (5,
+ G_TYPE_STRING,
+ G_TYPE_STRING,
+ G_TYPE_STRING,
+ G_TYPE_STRING,
+ G_TYPE_POINTER);
+
+ gtk_tree_view_set_model (GTK_TREE_VIEW(priv->treeview),
+ GTK_TREE_MODEL (liststore));
+ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(priv->treeview),
+ TRUE);
+
+ renderer = gtk_cell_renderer_text_new ();
+
+ gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(priv->treeview),
+ 0, _("%"),
+ renderer,
+ "text", 0,
+ NULL);
+ column = gtk_tree_view_get_column (GTK_TREE_VIEW(priv->treeview), 0);
+ gtk_tree_view_column_set_resizable (column, TRUE);
+ gtk_tree_view_column_set_reorderable (column, TRUE);
+ gtk_tree_view_column_set_sort_column_id (column, COL_PERCENT);
+
+ gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(priv->treeview),
+ COL_FILENAME, _("Filename"),
+ renderer,
+ "text", COL_FILENAME,
+ NULL);
+ column = gtk_tree_view_get_column (GTK_TREE_VIEW(priv->treeview),
+ COL_FILENAME);
+ gtk_tree_view_column_set_resizable (column, TRUE);
+ gtk_tree_view_column_set_reorderable (column, TRUE);
+ gtk_tree_view_column_set_sort_column_id (column, COL_FILENAME);
+
+ gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(priv->treeview),
+ COL_SIZE, _("Size"),
+ renderer,
+ "text", COL_SIZE,
+ NULL);
+ column = gtk_tree_view_get_column (GTK_TREE_VIEW(priv->treeview),
+ COL_SIZE);
+ gtk_tree_view_column_set_resizable (column, TRUE);
+ gtk_tree_view_column_set_reorderable (column, TRUE);
+ gtk_tree_view_column_set_sort_column_id (column, COL_SIZE);
+
+ gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(priv->treeview),
+ COL_REMAINING, _("Remaining"),
+ renderer,
+ "text", COL_REMAINING,
+ NULL);
+ column = gtk_tree_view_get_column (GTK_TREE_VIEW(priv->treeview),
+ COL_REMAINING);
+ gtk_tree_view_column_set_resizable (column, TRUE);
+ gtk_tree_view_column_set_reorderable (column, TRUE);
+ gtk_tree_view_column_set_sort_column_id (column, COL_REMAINING);
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(priv->treeview));
+ gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
+ g_signal_connect (G_OBJECT (selection), "changed",
+ G_CALLBACK (downloader_treeview_selection_changed_cb), dv);
+
+ priv->model = GTK_TREE_MODEL (liststore);
+}
+
+static void
+resume_selection_foreach (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter,
+ DownloaderView *dv)
+{
+ DownloadDetails *details;
+ GValue val = {0, };
+ gpointer *persist_object;
+
+ gtk_tree_model_get_value (model, iter, COL_PERSIST_OBJECT, &val);
+ persist_object = g_value_get_pointer (&val);
+
+ details = g_hash_table_lookup (dv->priv->details_hash,
+ persist_object);
+ g_return_if_fail (details);
+
+ if (details->status == DOWNLOAD_STATUS_COMPLETED) return;
+
+ downloader_view_set_download_status (dv, DOWNLOAD_STATUS_RESUMING, persist_object);
+
+ g_signal_emit (G_OBJECT (dv), downloader_view_signals[DOWNLOAD_RESUME], 0);
+}
+
+void
+download_dialog_resume_cb (GtkButton *button, DownloaderView *dv)
+{
+ GtkTreeSelection *selection;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(dv->priv->treeview));
+
+ gtk_tree_selection_selected_foreach
+ (selection,
+ (GtkTreeSelectionForeachFunc)resume_selection_foreach,
+ (gpointer)dv);
+}
+
+static void
+pause_selection_foreach (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter,
+ DownloaderView *dv)
+{
+ DownloadDetails *details;
+ GValue val = {0, };
+ gpointer *persist_object;
+
+ gtk_tree_model_get_value (model, iter, COL_PERSIST_OBJECT, &val);
+ persist_object = g_value_get_pointer (&val);
+
+ details = g_hash_table_lookup (dv->priv->details_hash,
+ persist_object);
+ g_return_if_fail (details);
+
+ if (details->status == DOWNLOAD_STATUS_COMPLETED) return;
+
+ downloader_view_set_download_status (dv, DOWNLOAD_STATUS_PAUSED, persist_object);
+
+ g_signal_emit (G_OBJECT (dv), downloader_view_signals[DOWNLOAD_PAUSE], 0);
+}
+
+void
+download_dialog_pause_cb (GtkButton *button, DownloaderView *dv)
+{
+ GtkTreeSelection *selection;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(dv->priv->treeview));
+
+ gtk_tree_selection_selected_foreach
+ (selection,
+ (GtkTreeSelectionForeachFunc)pause_selection_foreach,
+ (gpointer)dv);
+}
+
+void
+download_dialog_abort_cb (GtkButton *button, DownloaderView *dv)
+{
+ GList *l, *r = NULL;
+ GtkTreeSelection *selection;
+ GtkTreeModel *model;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(dv->priv->treeview));
+ l = gtk_tree_selection_get_selected_rows (selection, &model);
+ for (;l != NULL; l = l->next)
+ {
+ r = g_list_append (r, gtk_tree_row_reference_new
+ (model, (GtkTreePath *)l->data));
+ }
+
+ for (; r != NULL; r = g_list_next (r))
+ {
+ GtkTreeRowReference *node = r->data;
+ GValue val = {0, };
+ gpointer *persist_object;
+ GtkTreeIter iter;
+ DownloadDetails *details;
+
+ gtk_tree_model_get_iter (model, &iter,
+ gtk_tree_row_reference_get_path (node));
+
+ gtk_tree_model_get_value (model, &iter,
+ COL_PERSIST_OBJECT, &val);
+ persist_object = g_value_get_pointer (&val);
+
+ details = g_hash_table_lookup (dv->priv->details_hash,
+ persist_object);
+ g_return_if_fail (details);
+
+ g_signal_emit (G_OBJECT (dv), downloader_view_signals[DOWNLOAD_REMOVE], 0);
+
+ downloader_view_remove_download (dv, persist_object);
+
+ gtk_tree_row_reference_free (node);
+ }
+
+ l = g_list_first (l);
+ g_list_foreach (l, (GFunc)gtk_tree_path_free, NULL);
+ g_list_free (l);
+ g_list_free (r);
+}
+
+static void
+downloader_treeview_selection_changed_cb (GtkTreeSelection *selection,
+ DownloaderView *dv)
+{
+ GtkTreeIter iter;
+ GValue val = {0, };
+ gpointer *persist_object;
+ DownloadDetails *details = NULL;
+ GtkWidget *details_frame;
+ DownloaderViewPrivate *priv= dv->priv;
+
+ details_frame = ephy_dialog_get_control (EPHY_DIALOG(dv),
+ PROP_DETAILS_FRAME);
+
+ if (get_selected_row (priv, &iter))
+ {
+ gtk_tree_model_get_value (priv->model, &iter, COL_PERSIST_OBJECT, &val);
+ persist_object = g_value_get_pointer (&val);
+
+ details = g_hash_table_lookup (priv->details_hash,
+ persist_object);
+ g_return_if_fail (details);
+
+ gtk_widget_set_sensitive (details_frame, TRUE);
+
+ downloader_view_update_details (priv, details);
+ downloader_view_update_controls (priv);
+ }
+ else
+ {
+ gtk_label_set_text (GTK_LABEL (priv->details_location), "");
+ gtk_label_set_text (GTK_LABEL (priv->details_file), "");
+ gtk_label_set_text (GTK_LABEL (priv->details_status), "");
+ gtk_label_set_text (GTK_LABEL (priv->details_elapsed), "");
+ gtk_label_set_text (GTK_LABEL (priv->details_remaining), "");
+ gtk_progress_bar_set_fraction
+ (GTK_PROGRESS_BAR (priv->details_progress),
+ 0);
+
+ gtk_widget_set_sensitive (details_frame, FALSE);
+ }
+}
+
+static void
+alive_download_foreach (gpointer persist_object,
+ DownloadDetails *details,
+ gboolean *alive)
+{
+ if (details->status != DOWNLOAD_STATUS_COMPLETED)
+ {
+ *alive = TRUE;
+ }
+}
+
+static gboolean
+delete_pending_foreach (gpointer persist_object,
+ DownloadDetails *details,
+ DownloaderView *dv)
+{
+ g_signal_emit (G_OBJECT (dv), downloader_view_signals[DOWNLOAD_REMOVE],
+ 0, persist_object);
+
+ return TRUE;
+}
+
+gboolean
+download_dialog_delete_cb (GtkWidget *window, GdkEventAny *event,
+ DownloaderView *dv)
+{
+ GtkWidget *dialog;
+ gboolean choice;
+ gboolean alive_download = FALSE;
+
+ g_hash_table_foreach (dv->priv->details_hash,
+ (GHFunc)alive_download_foreach,
+ &alive_download);
+
+ if (!alive_download) return FALSE;
+
+ /* build question dialog */
+ dialog = gtk_message_dialog_new (
+ GTK_WINDOW(window),
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_WARNING,
+ GTK_BUTTONS_YES_NO,
+ _("Cancel all pending downloads?"));
+
+ /* run it */
+ choice = gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+
+ /* do the appropriate thing */
+ if (choice == GTK_RESPONSE_YES)
+ {
+ g_hash_table_foreach_remove (dv->priv->details_hash,
+ (GHRFunc)delete_pending_foreach,
+ dv);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+void
+download_dialog_details_cb (GtkToggleButton *button,
+ DownloaderView *dv)
+{
+ GtkWidget *details_frame;
+ GtkWidget *details_separator;
+
+ details_frame = ephy_dialog_get_control (EPHY_DIALOG(dv),
+ PROP_DETAILS_FRAME);
+ details_separator = ephy_dialog_get_control (EPHY_DIALOG(dv),
+ PROP_DETAILS_SEPARATOR);
+
+ if (gtk_toggle_button_get_active (button))
+ {
+ gtk_widget_show (GTK_WIDGET (details_frame));
+ gtk_widget_show (GTK_WIDGET (details_separator));
+ dv->priv->show_details = TRUE;
+ }
+ else
+ {
+ gtk_widget_hide (GTK_WIDGET (details_frame));
+ gtk_widget_hide (GTK_WIDGET (details_separator));
+ dv->priv->show_details = FALSE;
+ }
+
+}
+
+static void
+open_selection_foreach (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter,
+ DownloaderView *dv)
+{
+ DownloadDetails *details;
+ GValue val = {0, };
+ gpointer *persist_object;
+ GnomeVFSMimeApplication *app;
+ char *mime;
+
+ gtk_tree_model_get_value (model, iter, COL_PERSIST_OBJECT, &val);
+ persist_object = g_value_get_pointer (&val);
+
+ details = g_hash_table_lookup (dv->priv->details_hash,
+ persist_object);
+ g_return_if_fail (details);
+
+ if (details->status != DOWNLOAD_STATUS_COMPLETED) return;
+
+ mime = gnome_vfs_get_mime_type (details->dest);
+ g_return_if_fail (mime != NULL);
+
+ app = gnome_vfs_mime_get_default_application (mime);
+ if (app)
+ {
+ ephy_file_launch_application (app->command,
+ details->dest,
+ app->requires_terminal);
+ }
+ else
+ {
+ GtkWidget *parent;
+ parent = gtk_widget_get_toplevel (dv->priv->open_button);
+ ephy_embed_utils_nohandler_dialog_run (parent);
+ }
+
+ g_free(mime);
+}
+
+void
+download_dialog_open_cb (GtkWidget *button,
+ DownloaderView *dv)
+{
+ GtkTreeSelection *selection;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(dv->priv->treeview));
+
+ gtk_tree_selection_selected_foreach
+ (selection,
+ (GtkTreeSelectionForeachFunc)open_selection_foreach,
+ (gpointer)dv);
+}
diff --git a/embed/downloader-view.h b/embed/downloader-view.h
new file mode 100644
index 000000000..a01d5f30d
--- /dev/null
+++ b/embed/downloader-view.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef DOWNLOADER_VIEW_H
+#define DOWNLOADER_VIEW_H
+
+#include "ephy-dialog.h"
+
+#include <glib-object.h>
+#include <glib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct DownloaderView DownloaderView;
+typedef struct DownloaderViewClass DownloaderViewClass;
+
+#define DOWNLOADER_VIEW_TYPE (downloader_view_get_type ())
+#define DOWNLOADER_VIEW(obj) (GTK_CHECK_CAST ((obj), DOWNLOADER_VIEW_TYPE, DownloaderView))
+#define DOWNLOADER_VIEW_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), DOWNLOADER_VIEW, DownloaderViewClass))
+#define IS_DOWNLOADER_VIEW(obj) (GTK_CHECK_TYPE ((obj), DOWNLOADER_VIEW_TYPE))
+#define IS_DOWNLOADER_VIEW_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), DOWNLOADER_VIEW))
+
+typedef struct DownloaderViewPrivate DownloaderViewPrivate;
+
+#define CONF_DOWNLOADING_KEEP_OPEN "/apps/epiphany/downloader/keep_open"
+
+typedef enum
+{
+ DOWNLOAD_STATUS_DOWNLOADING,
+ DOWNLOAD_STATUS_PAUSED,
+ DOWNLOAD_STATUS_RESUMING,
+ DOWNLOAD_STATUS_COMPLETED
+} DownloadStatus;
+
+struct DownloaderView
+{
+ EphyDialog parent;
+ DownloaderViewPrivate *priv;
+};
+
+struct DownloaderViewClass
+{
+ EphyDialogClass parent_class;
+
+ void (*download_remove) (DownloaderView *dv);
+
+ void (*download_pause) (DownloaderView *dv);
+
+ void (*download_resume) (DownloaderView *dv);
+};
+
+GType downloader_view_get_type (void);
+
+DownloaderView *downloader_view_new (void);
+
+void downloader_view_add_download (DownloaderView *dv,
+ gchar *filename,
+ gchar *source,
+ gchar *dest,
+ gpointer persist_object);
+
+void downloader_view_remove_download (DownloaderView *dv,
+ gpointer persist_object);
+
+void downloader_view_set_download_status (DownloaderView *dv,
+ DownloadStatus status,
+ gpointer persist_object);
+
+void downloader_view_set_download_progress (DownloaderView *dv,
+ glong elapsed,
+ glong remaining,
+ gfloat speed,
+ gint size_total,
+ gint size_done,
+ gfloat progress,
+ gboolean can_pause,
+ gpointer persist_object);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/embed/ephy-embed-dialog.c b/embed/ephy-embed-dialog.c
new file mode 100644
index 000000000..cc019253a
--- /dev/null
+++ b/embed/ephy-embed-dialog.c
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "ephy-embed-dialog.h"
+#include "ephy-embed-shell.h"
+
+static void
+ephy_embed_dialog_class_init (EphyEmbedDialogClass *klass);
+static void
+ephy_embed_dialog_init (EphyEmbedDialog *window);
+static void
+ephy_embed_dialog_finalize (GObject *object);
+static void
+ephy_embed_dialog_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void
+ephy_embed_dialog_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+
+enum
+{
+ PROP_0,
+ PROP_EPHY_EMBED
+};
+
+struct EphyEmbedDialogPrivate
+{
+ EphyEmbed *embed;
+};
+
+static GObjectClass *parent_class = NULL;
+
+GType
+ephy_embed_dialog_get_type (void)
+{
+ static GType ephy_embed_dialog_type = 0;
+
+ if (ephy_embed_dialog_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (EphyEmbedDialogClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) ephy_embed_dialog_class_init,
+ NULL,
+ NULL, /* class_data */
+ sizeof (EphyEmbedDialog),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) ephy_embed_dialog_init
+ };
+
+ ephy_embed_dialog_type = g_type_register_static (EPHY_DIALOG_TYPE,
+ "EphyEmbedDialog",
+ &our_info, 0);
+ }
+
+ return ephy_embed_dialog_type;
+}
+
+static void
+ephy_embed_dialog_class_init (EphyEmbedDialogClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = ephy_embed_dialog_finalize;
+ object_class->set_property = ephy_embed_dialog_set_property;
+ object_class->get_property = ephy_embed_dialog_get_property;
+
+ g_object_class_install_property (object_class,
+ PROP_EPHY_EMBED,
+ g_param_spec_object ("EphyEmbed",
+ "EphyEmbed",
+ "Ephy Embed",
+ G_TYPE_OBJECT,
+ G_PARAM_READWRITE));
+}
+
+static void
+ephy_embed_dialog_init (EphyEmbedDialog *dialog)
+{
+ dialog->priv = g_new0 (EphyEmbedDialogPrivate, 1);
+
+ dialog->priv->embed = NULL;
+}
+
+static void
+ephy_embed_dialog_finalize (GObject *object)
+{
+ EphyEmbedDialog *dialog;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (IS_EPHY_EMBED_DIALOG (object));
+
+ dialog = EPHY_EMBED_DIALOG (object);
+
+ g_return_if_fail (dialog->priv != NULL);
+
+ g_free (dialog->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+ephy_embed_dialog_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EphyEmbedDialog *d = EPHY_EMBED_DIALOG (object);
+
+ switch (prop_id)
+ {
+ case PROP_EPHY_EMBED:
+ ephy_embed_dialog_set_embed (d, g_value_get_object (value));
+ break;
+ }
+}
+
+static void
+ephy_embed_dialog_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ EphyEmbedDialog *d = EPHY_EMBED_DIALOG (object);
+
+ switch (prop_id)
+ {
+ case PROP_EPHY_EMBED:
+ g_value_set_object (value, d->priv->embed);
+ break;
+ }
+}
+
+EphyEmbedDialog *
+ephy_embed_dialog_new (EphyEmbed *embed)
+{
+ return EPHY_EMBED_DIALOG (g_object_new (EPHY_EMBED_DIALOG_TYPE,
+ "EphyEmbed", embed,
+ NULL));
+}
+
+EphyEmbedDialog *
+ephy_embed_dialog_new_with_parent (GtkWidget *parent_window,
+ EphyEmbed *embed)
+{
+ return EPHY_EMBED_DIALOG (g_object_new
+ (EPHY_EMBED_DIALOG_TYPE,
+ "ParentWindow", parent_window,
+ "EphyEmbed", embed,
+ NULL));
+}
+
+void
+ephy_embed_dialog_set_embed (EphyEmbedDialog *dialog,
+ EphyEmbed *embed)
+{
+ dialog->priv->embed = embed;
+}
+
+EphyEmbed *
+ephy_embed_dialog_get_embed (EphyEmbedDialog *dialog)
+{
+ if (dialog->priv->embed == NULL)
+ {
+ EphyEmbed *embed;
+ embed = ephy_embed_shell_get_active_embed (embed_shell);
+ ephy_embed_dialog_set_embed (dialog, embed);
+ }
+
+ return dialog->priv->embed;
+}
diff --git a/embed/ephy-embed-dialog.h b/embed/ephy-embed-dialog.h
new file mode 100644
index 000000000..e8b7d3a3e
--- /dev/null
+++ b/embed/ephy-embed-dialog.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EPHY_EMBED_DIALOG_H
+#define EPHY_EMBED_DIALOG_H
+
+#include "ephy-embed.h"
+#include "ephy-dialog.h"
+
+#include <glib-object.h>
+#include <glib.h>
+#include <gtk/gtkwidget.h>
+
+G_BEGIN_DECLS
+
+typedef struct EphyEmbedDialogClass EphyEmbedDialogClass;
+
+#define EPHY_EMBED_DIALOG_TYPE (ephy_embed_dialog_get_type ())
+#define EPHY_EMBED_DIALOG(obj) (GTK_CHECK_CAST ((obj), EPHY_EMBED_DIALOG_TYPE, EphyEmbedDialog))
+#define EPHY_EMBED_DIALOG_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), EPHY_EMBED_DIALOG_TYPE, EphyEmbedDialogClass))
+#define IS_EPHY_EMBED_DIALOG(obj) (GTK_CHECK_TYPE ((obj), EPHY_EMBED_DIALOG_TYPE))
+#define IS_EPHY_EMBED_DIALOG_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), EPHY_EMBED_DIALOG))
+#define EPHY_EMBED_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EPHY_EMBED_DIALOG_TYPE, EphyEmbedDialogClass))
+
+typedef struct EphyEmbedDialog EphyEmbedDialog;
+typedef struct EphyEmbedDialogPrivate EphyEmbedDialogPrivate;
+
+struct EphyEmbedDialog
+{
+ EphyDialog parent;
+ EphyEmbedDialogPrivate *priv;
+};
+
+struct EphyEmbedDialogClass
+{
+ EphyDialogClass parent_class;
+};
+
+GType ephy_embed_dialog_get_type (void);
+
+EphyEmbedDialog *ephy_embed_dialog_new (EphyEmbed *embed);
+
+EphyEmbedDialog *ephy_embed_dialog_new_with_parent (GtkWidget *parent_window,
+ EphyEmbed *embed);
+
+void ephy_embed_dialog_set_embed (EphyEmbedDialog *dialog,
+ EphyEmbed *embed);
+
+EphyEmbed * ephy_embed_dialog_get_embed (EphyEmbedDialog *dialog);
+
+G_END_DECLS
+
+#endif
+
diff --git a/embed/ephy-embed-event.c b/embed/ephy-embed-event.c
new file mode 100644
index 000000000..fdbd53eab
--- /dev/null
+++ b/embed/ephy-embed-event.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "ephy-embed-event.h"
+
+#include <bonobo/bonobo-i18n.h>
+#include <glib/ghash.h>
+#include <gtk/gtktypeutils.h>
+
+struct EphyEmbedEventPrivate
+{
+ GHashTable *props;
+};
+
+static void
+ephy_embed_event_class_init (EphyEmbedEventClass *klass);
+static void
+ephy_embed_event_init (EphyEmbedEvent *ges);
+static void
+ephy_embed_event_finalize (GObject *object);
+
+static GObjectClass *parent_class = NULL;
+
+GType
+ephy_embed_event_get_type (void)
+{
+ static GType ephy_embed_event_type = 0;
+
+ if (ephy_embed_event_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (EphyEmbedEventClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) ephy_embed_event_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (EphyEmbedEvent),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) ephy_embed_event_init
+ };
+
+ ephy_embed_event_type = g_type_register_static (G_TYPE_OBJECT,
+ "EphyEmbedEvent",
+ &our_info, 0);
+ }
+
+ return ephy_embed_event_type;
+}
+
+static void
+ephy_embed_event_class_init (EphyEmbedEventClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = ephy_embed_event_finalize;
+}
+
+static void
+ephy_embed_event_init (EphyEmbedEvent *event)
+{
+ event->priv = g_new0 (EphyEmbedEventPrivate, 1);
+
+ event->priv->props = g_hash_table_new (g_str_hash, g_str_equal);
+}
+
+static void
+ephy_embed_event_finalize (GObject *object)
+{
+ EphyEmbedEvent *event;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (IS_EPHY_EMBED_EVENT (object));
+
+ event = EPHY_EMBED_EVENT (object);
+
+ g_return_if_fail (event->priv != NULL);
+
+ g_hash_table_foreach_remove (event->priv->props,
+ (GHRFunc)g_free,
+ NULL);
+ g_hash_table_destroy (event->priv->props);
+
+ g_free (event->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+
+EphyEmbedEvent *
+ephy_embed_event_new (void)
+{
+ EphyEmbedEvent *event;
+
+ event = EPHY_EMBED_EVENT (g_object_new (EPHY_EMBED_EVENT_TYPE, NULL));
+
+ g_return_val_if_fail (event->priv != NULL, NULL);
+
+ return event;
+}
+
+guint
+ephy_embed_event_get_modifier (EphyEmbedEvent *event)
+{
+ return event->modifier;
+}
+
+gresult
+ephy_embed_event_get_mouse_button (EphyEmbedEvent *event,
+ guint *mouse_button)
+{
+ *mouse_button = event->mouse_button;
+ return G_OK;
+}
+
+gresult
+ephy_embed_event_get_mouse_coords (EphyEmbedEvent *event,
+ guint *x, guint *y)
+{
+ *x = event->mouse_x;
+ *y = event->mouse_y;
+ return G_OK;
+}
+
+gresult
+ephy_embed_event_get_context (EphyEmbedEvent *event,
+ EmbedEventContext *context)
+{
+ *context = event->context;
+ return G_OK;
+}
+
+void
+ephy_embed_event_set_property (EphyEmbedEvent *event,
+ const char *name,
+ GValue *value)
+{
+ g_hash_table_insert (event->priv->props,
+ g_strdup (name),
+ value);
+}
+
+void
+ephy_embed_event_get_property (EphyEmbedEvent *event,
+ const char *name,
+ GValue **value)
+{
+ *value = g_hash_table_lookup (event->priv->props, name);
+}
+
+gboolean
+ephy_embed_event_has_property (EphyEmbedEvent *event,
+ const char *name)
+{
+ gpointer tmp;
+
+ tmp = g_hash_table_lookup (event->priv->props,
+ name);
+
+ return tmp != NULL;
+}
diff --git a/embed/ephy-embed-event.h b/embed/ephy-embed-event.h
new file mode 100644
index 000000000..1256dcffc
--- /dev/null
+++ b/embed/ephy-embed-event.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EPHY_EMBED_EVENT_H
+#define EPHY_EMBED_EVENT_H
+
+#include "ephy-embed-types.h"
+
+#include <glib-object.h>
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef struct EphyEmbedEventClass EphyEmbedEventClass;
+
+#define EPHY_EMBED_EVENT_TYPE (ephy_embed_event_get_type ())
+#define EPHY_EMBED_EVENT(obj) (GTK_CHECK_CAST ((obj), EPHY_EMBED_EVENT_TYPE, EphyEmbedEvent))
+#define EPHY_EMBED_EVENT_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), EPHY_PERSIST_SHELL, EphyEmbedEventClass))
+#define IS_EPHY_EMBED_EVENT(obj) (GTK_CHECK_TYPE ((obj), EPHY_EMBED_EVENT_TYPE))
+#define IS_EPHY_EMBED_EVENT_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), EPHY_EMBED_EVENT))
+#define EPHY_EMBED_EVENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EPHY_EMBED_SHELL_TYPE, EphyEmbedEventClass))
+
+typedef struct EphyEmbedEvent EphyEmbedEvent;
+typedef struct EphyEmbedEventPrivate EphyEmbedEventPrivate;
+
+typedef enum
+{
+ EMBED_CONTEXT_NONE = 0,
+ EMBED_CONTEXT_DEFAULT = 1 << 1,
+ EMBED_CONTEXT_LINK = 1 << 2,
+ EMBED_CONTEXT_IMAGE = 1 << 3,
+ EMBED_CONTEXT_DOCUMENT = 1 << 4,
+ EMBED_CONTEXT_INPUT = 1 << 5,
+ EMBED_CONTEXT_XUL = 1 << 7,
+ EMBED_CONTEXT_EMAIL_LINK = 1 << 8
+} EmbedEventContext;
+
+struct EphyEmbedEvent
+{
+ GObject parent;
+ EphyEmbedEventPrivate *priv;
+
+ /* Public to the embed implementations */
+ guint modifier;
+ guint mouse_button;
+ guint context;
+ guint timestamp;
+ guint mouse_x, mouse_y;
+};
+
+struct EphyEmbedEventClass
+{
+ GObjectClass parent_class;
+};
+
+GType ephy_embed_event_get_type (void);
+
+EphyEmbedEvent *ephy_embed_event_new (void);
+
+guint ephy_embed_event_get_modifier (EphyEmbedEvent *event);
+
+gresult ephy_embed_event_get_mouse_button (EphyEmbedEvent *event,
+ guint *mouse_button);
+
+gresult ephy_embed_event_get_mouse_coords (EphyEmbedEvent *event,
+ guint *x, guint *y);
+
+gresult ephy_embed_event_get_context (EphyEmbedEvent *event,
+ EmbedEventContext *context);
+
+void ephy_embed_event_set_property (EphyEmbedEvent *event,
+ const char *name,
+ GValue *value);
+
+void ephy_embed_event_get_property (EphyEmbedEvent *event,
+ const char *name,
+ GValue **value);
+
+gboolean ephy_embed_event_has_property (EphyEmbedEvent *event,
+ const char *name);
+
+
+G_END_DECLS
+
+#endif
diff --git a/embed/ephy-embed-favicon.c b/embed/ephy-embed-favicon.c
new file mode 100644
index 000000000..d88eb91cf
--- /dev/null
+++ b/embed/ephy-embed-favicon.c
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen <jorn@nl.linux.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <string.h>
+
+#include "ephy-embed-favicon.h"
+#include "ephy-embed-shell.h"
+
+static void ephy_embed_favicon_class_init (EphyEmbedFaviconClass *klass);
+static void ephy_embed_favicon_init (EphyEmbedFavicon *ma);
+static void ephy_embed_favicon_finalize (GObject *object);
+static void ephy_embed_favicon_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void ephy_embed_favicon_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+struct EphyEmbedFaviconPrivate
+{
+ EphyEmbed *embed;
+};
+
+enum
+{
+ PROP_0,
+ PROP_EMBED
+};
+
+static GObjectClass *parent_class = NULL;
+
+GType
+ephy_embed_favicon_get_type (void)
+{
+ static GType ephy_embed_favicon_type = 0;
+
+ if (ephy_embed_favicon_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (EphyEmbedFaviconClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) ephy_embed_favicon_class_init,
+ NULL,
+ NULL,
+ sizeof (EphyEmbedFavicon),
+ 0,
+ (GInstanceInitFunc) ephy_embed_favicon_init
+ };
+
+ ephy_embed_favicon_type = g_type_register_static (EPHY_TYPE_FAVICON,
+ "EphyEmbedFavicon",
+ &our_info, 0);
+ }
+
+ return ephy_embed_favicon_type;
+}
+
+static void
+ephy_embed_favicon_class_init (EphyEmbedFaviconClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = ephy_embed_favicon_finalize;
+
+ object_class->set_property = ephy_embed_favicon_set_property;
+ object_class->get_property = ephy_embed_favicon_get_property;
+
+ g_object_class_install_property (object_class,
+ PROP_EMBED,
+ g_param_spec_object ("embed",
+ "Associated embed",
+ "Associated embed",
+ G_TYPE_OBJECT,
+ G_PARAM_READWRITE));
+}
+
+static void
+ephy_embed_favicon_init (EphyEmbedFavicon *ma)
+{
+ ma->priv = g_new0 (EphyEmbedFaviconPrivate, 1);
+}
+
+static void
+ephy_embed_favicon_finalize (GObject *object)
+{
+ EphyEmbedFavicon *ma;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (EPHY_IS_EMBED_FAVICON (object));
+
+ ma = EPHY_EMBED_FAVICON (object);
+
+ g_return_if_fail (ma->priv != NULL);
+
+ g_free (ma->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+location_changed_cb (EphyEmbed *embed,
+ EphyEmbedFavicon *favicon)
+{
+ char *location;
+
+ ephy_embed_get_location (embed, TRUE, FALSE, &location);
+ ephy_favicon_set_url (EPHY_FAVICON (favicon), location);
+
+ g_free (location);
+}
+
+static void
+favicon_cb (EphyEmbed *embed,
+ const char *favicon_url,
+ EphyEmbedFavicon *favicon)
+{
+ char *url = NULL;
+ EphyFaviconCache *cache;
+
+ if (favicon->priv->embed == NULL)
+ return;
+
+ ephy_embed_get_location (favicon->priv->embed, TRUE, TRUE, &url);
+
+ g_object_get (G_OBJECT (favicon),
+ "cache", &cache,
+ NULL);
+
+ ephy_favicon_cache_insert_from_url (cache,
+ url,
+ favicon_url);
+
+ g_object_unref (cache);
+
+ g_free (url);
+}
+
+static void
+ephy_embed_favicon_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EphyEmbedFavicon *favicon = EPHY_EMBED_FAVICON (object);
+
+ switch (prop_id)
+ {
+ case PROP_EMBED:
+ favicon->priv->embed = g_value_get_object (value);
+
+ if (favicon->priv->embed != NULL)
+ {
+ g_signal_connect_object (G_OBJECT (favicon->priv->embed),
+ "ge_favicon",
+ G_CALLBACK (favicon_cb),
+ favicon,
+ 0);
+ g_signal_connect_object (G_OBJECT (favicon->priv->embed),
+ "ge_location",
+ G_CALLBACK (location_changed_cb),
+ favicon,
+ 0);
+ }
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+ephy_embed_favicon_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ EphyEmbedFavicon *favicon = EPHY_EMBED_FAVICON (object);
+
+ switch (prop_id)
+ {
+ case PROP_EMBED:
+ g_value_set_object (value, favicon->priv->embed);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+GtkWidget *
+ephy_embed_favicon_new (EphyEmbed *embed)
+{
+ EphyEmbedFavicon *favicon;
+ EphyFaviconCache *cache = ephy_embed_shell_get_favicon_cache (embed_shell);
+
+ g_return_val_if_fail (EPHY_IS_FAVICON_CACHE (cache), NULL);
+
+ favicon = EPHY_EMBED_FAVICON (g_object_new (EPHY_TYPE_EMBED_FAVICON,
+ "cache", cache,
+ "embed", embed,
+ NULL));
+
+ g_return_val_if_fail (favicon->priv != NULL, NULL);
+
+ return GTK_WIDGET (favicon);
+}
+
+void
+ephy_embed_favicon_set_embed (EphyEmbedFavicon *favicon,
+ EphyEmbed *embed)
+{
+ g_return_if_fail (EPHY_IS_EMBED_FAVICON (favicon));
+
+ g_object_set (G_OBJECT (favicon),
+ "embed", embed,
+ NULL);
+}
+
+EphyEmbed *
+ephy_embed_favicon_get_embed (EphyEmbedFavicon *favicon)
+{
+ EphyEmbed *embed;
+
+ g_return_val_if_fail (EPHY_IS_EMBED_FAVICON (favicon), NULL);
+
+ g_object_get (G_OBJECT (favicon),
+ "embed", &embed,
+ NULL);
+
+ return embed;
+}
diff --git a/embed/ephy-embed-favicon.h b/embed/ephy-embed-favicon.h
new file mode 100644
index 000000000..36f69cc82
--- /dev/null
+++ b/embed/ephy-embed-favicon.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <glib-object.h>
+#include <gtk/gtkimage.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#include "ephy-favicon.h"
+#include "ephy-embed.h"
+
+#ifndef __EPHY_EMBED_FAVICON_H
+#define __EPHY_EMBED_FAVICON_H
+
+G_BEGIN_DECLS
+
+#define EPHY_TYPE_EMBED_FAVICON (ephy_embed_favicon_get_type ())
+#define EPHY_EMBED_FAVICON(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EPHY_TYPE_EMBED_FAVICON, EphyEmbedFavicon))
+#define EPHY_EMBED_FAVICON_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), EPHY_TYPE_EMBED_FAVICON, EphyEmbedFaviconClass))
+#define EPHY_IS_EMBED_FAVICON(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EPHY_TYPE_EMBED_FAVICON))
+#define EPHY_IS_EMBED_FAVICON_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EPHY_TYPE_EMBED_FAVICON))
+#define EPHY_EMBED_FAVICON_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EPHY_TYPE_EMBED_FAVICON, EphyEmbedFaviconClass))
+
+typedef struct EphyEmbedFaviconPrivate EphyEmbedFaviconPrivate;
+
+typedef struct
+{
+ EphyFavicon parent;
+
+ EphyEmbedFaviconPrivate *priv;
+} EphyEmbedFavicon;
+
+typedef struct
+{
+ EphyFaviconClass parent_class;
+} EphyEmbedFaviconClass;
+
+GType ephy_embed_favicon_get_type (void);
+
+GtkWidget *ephy_embed_favicon_new (EphyEmbed *embed);
+
+void ephy_embed_favicon_set_embed (EphyEmbedFavicon *favicon,
+ EphyEmbed *embed);
+
+EphyEmbed *ephy_embed_favicon_get_embed (EphyEmbedFavicon *favicon);
+
+G_END_DECLS
+
+#endif /* __EPHY_EMBED_FAVICON_H */
diff --git a/embed/ephy-embed-persist.c b/embed/ephy-embed-persist.c
new file mode 100644
index 000000000..a1d742587
--- /dev/null
+++ b/embed/ephy-embed-persist.c
@@ -0,0 +1,491 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+
+#include "ephy-embed-persist.h"
+
+#include "mozilla-embed.h"
+#include "mozilla-embed-persist.h"
+
+#include <bonobo/bonobo-i18n.h>
+
+enum
+{
+ COMPLETED,
+ LAST_SIGNAL
+};
+
+enum
+{
+ PROP_0,
+ PROP_EMBED,
+ PROP_SOURCE,
+ PROP_DEST,
+ PROP_MAX_SIZE,
+ PROP_FLAGS,
+ PROP_HANDLER
+};
+
+struct EphyEmbedPersistPrivate
+{
+ char *dir;
+ char *src;
+ PersistHandlerInfo *handler;
+ EphyEmbed *embed;
+ int max_size;
+ EmbedPersistFlags flags;
+};
+
+static void
+ephy_embed_persist_class_init (EphyEmbedPersistClass *klass);
+static void
+ephy_embed_persist_init (EphyEmbedPersist *ges);
+static void
+ephy_embed_persist_finalize (GObject *object);
+static void
+ephy_embed_persist_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void
+ephy_embed_persist_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+static gresult
+impl_set_source (EphyEmbedPersist *persist,
+ const char *url);
+static gresult
+impl_set_dest (EphyEmbedPersist *persist,
+ const char *dir);
+static gresult
+impl_set_max_size (EphyEmbedPersist *persist,
+ int kb_size);
+static gresult
+impl_set_embed (EphyEmbedPersist *persist,
+ EphyEmbed *embed);
+static gresult
+impl_set_flags (EphyEmbedPersist *persist,
+ EmbedPersistFlags flags);
+static gresult
+impl_set_handler (EphyEmbedPersist *persist,
+ const char *command,
+ gboolean need_terminal);
+
+static GObjectClass *parent_class = NULL;
+static guint ephy_embed_persist_signals[LAST_SIGNAL] = { 0 };
+
+GType
+ephy_embed_persist_get_type (void)
+{
+ static GType ephy_embed_persist_type = 0;
+
+ if (ephy_embed_persist_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (EphyEmbedPersistClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) ephy_embed_persist_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (EphyEmbedPersist),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) ephy_embed_persist_init
+ };
+
+ ephy_embed_persist_type = g_type_register_static (G_TYPE_OBJECT,
+ "EphyEmbedPersist",
+ &our_info, 0);
+ }
+
+ return ephy_embed_persist_type;
+}
+
+static void
+ephy_embed_persist_class_init (EphyEmbedPersistClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = ephy_embed_persist_finalize;
+ object_class->set_property = ephy_embed_persist_set_property;
+ object_class->get_property = ephy_embed_persist_get_property;
+
+ klass->set_source = impl_set_source;
+ klass->set_dest = impl_set_dest;
+ klass->set_embed = impl_set_embed;
+ klass->set_max_size = impl_set_max_size;
+ klass->set_flags = impl_set_flags;
+ klass->set_handler = impl_set_handler;
+
+ /* init signals */
+ ephy_embed_persist_signals[COMPLETED] =
+ g_signal_new ("completed",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EphyEmbedPersistClass, completed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+
+ g_object_class_install_property (object_class,
+ PROP_EMBED,
+ g_param_spec_object ("embed",
+ "Embed",
+ "The embed containing the document",
+ G_TYPE_OBJECT,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_SOURCE,
+ g_param_spec_string ("source",
+ "Source",
+ "Url of the document to save",
+ NULL,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (object_class,
+ PROP_DEST,
+ g_param_spec_string ("dest",
+ "Destination",
+ "Destination directory",
+ NULL,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (object_class,
+ PROP_MAX_SIZE,
+ g_param_spec_int ("max_size",
+ "Maxsize",
+ "Maximum size of the file",
+ 0,
+ G_MAXINT,
+ 0,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (object_class,
+ PROP_FLAGS,
+ g_param_spec_int ("flags",
+ "Flags",
+ "Flags",
+ 0,
+ G_MAXINT,
+ 0,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (object_class,
+ PROP_HANDLER,
+ g_param_spec_pointer ("handler",
+ "Handler",
+ "Handler",
+ G_PARAM_READWRITE));
+}
+
+static void
+ephy_embed_persist_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EphyEmbedPersist *persist;
+ PersistHandlerInfo *h;
+
+ persist = EPHY_EMBED_PERSIST (object);
+
+ switch (prop_id)
+ {
+ case PROP_EMBED:
+ ephy_embed_persist_set_embed (persist,
+ g_value_get_object (value));
+ break;
+ case PROP_SOURCE:
+ ephy_embed_persist_set_source (persist,
+ g_value_get_string (value));
+ break;
+ case PROP_DEST:
+ ephy_embed_persist_set_dest (persist,
+ g_value_get_string (value));
+ break;
+ case PROP_MAX_SIZE:
+ ephy_embed_persist_set_max_size (persist,
+ g_value_get_int (value));
+ break;
+ case PROP_FLAGS:
+ ephy_embed_persist_set_flags
+ (persist,
+ (EmbedPersistFlags)g_value_get_int (value));
+ break;
+ case PROP_HANDLER:
+ h = (PersistHandlerInfo *)g_value_get_pointer (value);
+ ephy_embed_persist_set_handler
+ (persist, h->command, h->need_terminal);
+ break;
+ }
+}
+
+static void
+ephy_embed_persist_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ EphyEmbedPersist *persist;
+
+ persist = EPHY_EMBED_PERSIST (object);
+
+ switch (prop_id)
+ {
+ case PROP_EMBED:
+ g_value_set_object (value, persist->priv->embed);
+ break;
+ case PROP_SOURCE:
+ g_value_set_string (value, persist->priv->src);
+ break;
+ case PROP_DEST:
+ g_value_set_string (value, persist->priv->dir);
+ break;
+ case PROP_MAX_SIZE:
+ g_value_set_int (value, persist->priv->max_size);
+ break;
+ case PROP_FLAGS:
+ g_value_set_int (value, (int)persist->priv->flags);
+ break;
+ case PROP_HANDLER:
+ g_value_set_pointer (value, persist->priv->handler);
+ }
+}
+
+static void
+ephy_embed_persist_init (EphyEmbedPersist *persist)
+{
+ persist->priv = g_new0 (EphyEmbedPersistPrivate, 1);
+ persist->priv->src = NULL;
+ persist->priv->dir = NULL;
+ persist->priv->handler = NULL;
+}
+
+static void
+ephy_embed_persist_finalize (GObject *object)
+{
+ EphyEmbedPersist *persist;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (IS_EPHY_EMBED_PERSIST (object));
+
+ persist = EPHY_EMBED_PERSIST (object);
+
+ g_return_if_fail (persist->priv != NULL);
+
+ g_free (persist->priv->dir);
+ g_free (persist->priv->src);
+
+ if (persist->priv->handler)
+ {
+ g_free (persist->priv->handler->command);
+ g_free (persist->priv->handler);
+ }
+
+ g_free (persist->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+
+EphyEmbedPersist *
+ephy_embed_persist_new (EphyEmbed *embed)
+{
+ EphyEmbedPersist *persist;
+ GType type = 0;
+
+ type = MOZILLA_EMBED_PERSIST_TYPE;
+
+ g_assert (type != 0);
+
+ persist = EPHY_EMBED_PERSIST (g_object_new (type,
+ "embed", embed,
+ NULL));
+
+ g_return_val_if_fail (persist->priv != NULL, NULL);
+
+ return persist;
+}
+
+gresult
+ephy_embed_persist_set_source (EphyEmbedPersist *persist,
+ const char *url)
+{
+ EphyEmbedPersistClass *klass = EPHY_EMBED_PERSIST_GET_CLASS (persist);
+ return klass->set_source (persist, url);
+}
+
+gresult
+ephy_embed_persist_get_source (EphyEmbedPersist *persist,
+ const char **url)
+{
+ *url = persist->priv->src;
+
+ return G_OK;
+}
+
+gresult
+ephy_embed_persist_get_dest (EphyEmbedPersist *persist,
+ const char **dir)
+{
+ *dir = persist->priv->dir;
+
+ return G_OK;
+}
+
+gresult
+ephy_embed_persist_set_dest (EphyEmbedPersist *persist,
+ const char *dir)
+{
+ EphyEmbedPersistClass *klass = EPHY_EMBED_PERSIST_GET_CLASS (persist);
+ return klass->set_dest (persist, dir);
+}
+
+gresult
+ephy_embed_persist_save (EphyEmbedPersist *persist)
+{
+ EphyEmbedPersistClass *klass = EPHY_EMBED_PERSIST_GET_CLASS (persist);
+ return klass->save (persist);
+}
+
+gresult
+ephy_embed_persist_set_max_size (EphyEmbedPersist *persist,
+ int kb_size)
+{
+ EphyEmbedPersistClass *klass = EPHY_EMBED_PERSIST_GET_CLASS (persist);
+ return klass->set_max_size (persist, kb_size);
+}
+
+gresult
+ephy_embed_persist_set_embed (EphyEmbedPersist *persist,
+ EphyEmbed *embed)
+{
+ EphyEmbedPersistClass *klass = EPHY_EMBED_PERSIST_GET_CLASS (persist);
+ return klass->set_embed (persist, embed);
+}
+
+gresult
+ephy_embed_persist_get_embed (EphyEmbedPersist *persist,
+ EphyEmbed **embed)
+{
+ *embed = persist->priv->embed;
+
+ return G_OK;
+}
+
+gresult
+ephy_embed_persist_set_flags (EphyEmbedPersist *persist,
+ EmbedPersistFlags flags)
+{
+ EphyEmbedPersistClass *klass = EPHY_EMBED_PERSIST_GET_CLASS (persist);
+ return klass->set_flags (persist, flags);
+}
+
+gresult
+ephy_embed_persist_get_flags (EphyEmbedPersist *persist,
+ EmbedPersistFlags *flags)
+{
+ *flags = persist->priv->flags= persist->priv->flags;
+
+ return G_OK;
+}
+
+gresult
+ephy_embed_persist_set_handler (EphyEmbedPersist *persist,
+ const char *command,
+ gboolean need_terminal)
+{
+ EphyEmbedPersistClass *klass = EPHY_EMBED_PERSIST_GET_CLASS (persist);
+ return klass->set_handler (persist, command, need_terminal);
+}
+
+static gresult
+impl_set_handler (EphyEmbedPersist *persist,
+ const char *command,
+ gboolean need_terminal)
+{
+ persist->priv->handler = g_new0 (PersistHandlerInfo, 1);
+ persist->priv->handler->command = g_strdup (command);
+ persist->priv->handler->need_terminal = need_terminal;
+
+ g_object_notify (G_OBJECT(persist), "handler");
+
+ return G_OK;
+}
+
+static gresult
+impl_set_flags (EphyEmbedPersist *persist,
+ EmbedPersistFlags flags)
+{
+ persist->priv->flags = flags;
+
+ g_object_notify (G_OBJECT(persist), "flags");
+
+ return G_OK;
+}
+
+static gresult
+impl_set_source (EphyEmbedPersist *persist,
+ const char *url)
+{
+ persist->priv->src = g_strdup(url);
+
+ g_object_notify (G_OBJECT(persist), "source");
+
+ return G_OK;
+}
+
+static gresult
+impl_set_dest (EphyEmbedPersist *persist,
+ const char *dir)
+{
+ persist->priv->dir = g_strdup (dir);
+
+ g_object_notify (G_OBJECT(persist), "dest");
+
+ return G_OK;
+}
+
+static gresult
+impl_set_max_size (EphyEmbedPersist *persist,
+ int kb_size)
+{
+ persist->priv->max_size = kb_size;
+
+ g_object_notify (G_OBJECT(persist), "max_size");
+
+ return G_OK;
+}
+
+static gresult
+impl_set_embed (EphyEmbedPersist *persist,
+ EphyEmbed *embed)
+{
+ persist->priv->embed = embed;
+
+ g_object_notify (G_OBJECT(persist), "embed");
+
+ return G_OK;
+}
diff --git a/embed/ephy-embed-persist.h b/embed/ephy-embed-persist.h
new file mode 100644
index 000000000..2ad883647
--- /dev/null
+++ b/embed/ephy-embed-persist.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EPHY_EMBED_PERSIST_H
+#define EPHY_EMBED_PERSIST_H
+
+#include "ephy-embed.h"
+
+#include <glib-object.h>
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef struct EphyEmbedPersistClass EphyEmbedPersistClass;
+
+#define EPHY_EMBED_PERSIST_TYPE (ephy_embed_persist_get_type ())
+#define EPHY_EMBED_PERSIST(obj) (GTK_CHECK_CAST ((obj), EPHY_EMBED_PERSIST_TYPE, EphyEmbedPersist))
+#define EPHY_EMBED_PERSIST_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), EPHY_EMBED_PERSIST_TYPE, EphyEmbedPersistClass))
+#define IS_EPHY_EMBED_PERSIST(obj) (GTK_CHECK_TYPE ((obj), EPHY_EMBED_PERSIST_TYPE))
+#define IS_EPHY_EMBED_PERSIST_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), EPHY_EMBED_PERSIST))
+#define EPHY_EMBED_PERSIST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EPHY_EMBED_PERSIST_TYPE, EphyEmbedPersistClass))
+
+typedef struct EphyEmbedPersist EphyEmbedPersist;
+typedef struct EphyEmbedPersistPrivate EphyEmbedPersistPrivate;
+
+typedef enum
+{
+ EMBED_PERSIST_SHOW_PROGRESS = 1 << 0,
+ EMBED_PERSIST_SAVE_CONTENT = 1 << 1,
+ EMBED_PERSIST_FROMCACHE = 1 << 2,
+ EMBED_PERSIST_BYPASSCACHE = 1 << 3,
+ EMBED_PERSIST_MAINDOC = 1 << 4
+} EmbedPersistFlags;
+
+typedef struct
+{
+ char *command;
+ gboolean need_terminal;
+} PersistHandlerInfo;
+
+struct EphyEmbedPersist
+{
+ GObject parent;
+ EphyEmbedPersistPrivate *priv;
+};
+
+struct EphyEmbedPersistClass
+{
+ GObjectClass parent_class;
+
+ void (* completed) (EphyEmbedPersist *persist);
+
+ /* Methods */
+
+ gresult (* set_source) (EphyEmbedPersist *persist,
+ const char *url);
+ gresult (* set_dest) (EphyEmbedPersist *persist,
+ const char *dir);
+ gresult (* save) (EphyEmbedPersist *persist);
+
+ gresult (* set_max_size) (EphyEmbedPersist *persist,
+ int max_size);
+
+ gresult (* set_embed) (EphyEmbedPersist *persist,
+ EphyEmbed *embed);
+
+ gresult (* set_flags) (EphyEmbedPersist *persist,
+ EmbedPersistFlags flags);
+
+ gresult (* set_handler) (EphyEmbedPersist *persist,
+ const char *command,
+ gboolean need_terminal);
+};
+
+GType ephy_embed_persist_get_type (void);
+
+EphyEmbedPersist *ephy_embed_persist_new (EphyEmbed *embed);
+
+gresult ephy_embed_persist_set_source (EphyEmbedPersist *persist,
+ const char *url);
+
+gresult ephy_embed_persist_get_source (EphyEmbedPersist *persist,
+ const char **url);
+
+gresult ephy_embed_persist_set_dest (EphyEmbedPersist *persist,
+ const char *dir);
+
+gresult ephy_embed_persist_get_dest (EphyEmbedPersist *persist,
+ const char **dir);
+
+gresult ephy_embed_persist_set_handler (EphyEmbedPersist *persist,
+ const char *handler,
+ gboolean need_terminal);
+
+gresult ephy_embed_persist_set_max_size (EphyEmbedPersist *persist,
+ int kb_size);
+
+gresult ephy_embed_persist_set_embed (EphyEmbedPersist *persist,
+ EphyEmbed *embed);
+
+gresult ephy_embed_persist_get_embed (EphyEmbedPersist *persist,
+ EphyEmbed **embed);
+
+gresult ephy_embed_persist_set_flags (EphyEmbedPersist *persist,
+ EmbedPersistFlags flags);
+
+gresult ephy_embed_persist_get_flags (EphyEmbedPersist *persist,
+ EmbedPersistFlags *flags);
+
+gresult ephy_embed_persist_save (EphyEmbedPersist *persist);
+
+G_END_DECLS
+
+#endif
diff --git a/embed/ephy-embed-popup-bw.c b/embed/ephy-embed-popup-bw.c
new file mode 100644
index 000000000..553f73205
--- /dev/null
+++ b/embed/ephy-embed-popup-bw.c
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "ephy-embed-popup-bw.h"
+#include "ephy-gobject-misc.h"
+
+#include <gtk/gtkmain.h>
+
+enum
+{
+ PROP_0,
+ PROP_BONOBO_WINDOW
+};
+
+struct EphyEmbedPopupBWPrivate
+{
+ BonoboWindow *window;
+ GtkWidget *menu;
+};
+
+static void
+ephy_embed_popup_bw_class_init (EphyEmbedPopupBWClass *klass);
+static void
+ephy_embed_popup_bw_init (EphyEmbedPopupBW *gep);
+static void
+ephy_embed_popup_bw_finalize (GObject *object);
+static void
+ephy_embed_popup_bw_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void
+ephy_embed_popup_bw_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void
+ephy_embed_popup_bw_set_window (EphyEmbedPopupBW *p,
+ BonoboWindow *window);
+static void
+ephy_embed_popup_bw_show_impl (EphyEmbedPopup *p,
+ EphyEmbed *embed);
+
+static EphyEmbedPopupClass *parent_class = NULL;
+
+MAKE_GET_TYPE (ephy_embed_popup_bw, "EphyEmbedPopupBW", EphyEmbedPopupBW,
+ ephy_embed_popup_bw_class_init, ephy_embed_popup_bw_init, EPHY_EMBED_POPUP_TYPE);
+
+static void
+ephy_embed_popup_bw_class_init (EphyEmbedPopupBWClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = EPHY_EMBED_POPUP_CLASS (g_type_class_peek_parent (klass));
+
+ object_class->finalize = ephy_embed_popup_bw_finalize;
+ object_class->set_property = ephy_embed_popup_bw_set_property;
+ object_class->get_property = ephy_embed_popup_bw_get_property;
+
+ g_object_class_install_property (object_class,
+ PROP_BONOBO_WINDOW,
+ g_param_spec_object ("BonoboWindow",
+ "BonoboWindow",
+ "Bonobo window",
+ BONOBO_TYPE_WINDOW,
+ G_PARAM_READWRITE));
+
+ EPHY_EMBED_POPUP_CLASS (klass)->show = ephy_embed_popup_bw_show_impl;
+}
+
+static void
+ephy_embed_popup_bw_init (EphyEmbedPopupBW *gep)
+{
+ gep->priv = g_new0 (EphyEmbedPopupBWPrivate, 1);
+ gep->priv->window = NULL;
+ gep->priv->menu = NULL;
+}
+
+static void
+ephy_embed_popup_bw_finalize (GObject *object)
+{
+ EphyEmbedPopupBW *gep;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (IS_EPHY_EMBED_POPUP_BW (object));
+
+ gep = EPHY_EMBED_POPUP_BW (object);
+
+ g_return_if_fail (gep->priv != NULL);
+
+ g_free (gep->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+ephy_embed_popup_bw_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EphyEmbedPopupBW *p = EPHY_EMBED_POPUP_BW (object);
+
+ switch (prop_id)
+ {
+ case PROP_BONOBO_WINDOW:
+ ephy_embed_popup_bw_set_window (p, g_value_get_object (value));
+ break;
+ }
+}
+
+static void
+ephy_embed_popup_bw_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ EphyEmbedPopupBW *p = EPHY_EMBED_POPUP_BW (object);
+
+ switch (prop_id)
+ {
+ case PROP_BONOBO_WINDOW:
+ g_value_set_object (value, p->priv->window);
+ break;
+ }
+}
+
+static void
+ephy_embed_popup_bw_set_window (EphyEmbedPopupBW *p,
+ BonoboWindow *window)
+{
+ p->priv->window = window;
+}
+
+EphyEmbedPopupBW *
+ephy_embed_popup_bw_new (BonoboWindow *window)
+{
+ EphyEmbedPopupBW *p;
+
+ p = EPHY_EMBED_POPUP_BW (g_object_new (EPHY_EMBED_POPUP_BW_TYPE,
+ "BonoboWindow", window,
+ NULL));
+
+ g_return_val_if_fail (p->priv != NULL, NULL);
+
+ return p;
+}
+
+static void
+ephy_embed_popup_bw_show_impl (EphyEmbedPopup *pp,
+ EphyEmbed *embed)
+{
+ EphyEmbedPopupBW *p = EPHY_EMBED_POPUP_BW (pp);
+ EphyEmbedEvent *event = ephy_embed_popup_get_event (pp);
+ guint button;
+
+ ephy_embed_popup_set_embed (pp, embed);
+
+ ephy_embed_event_get_mouse_button (event, &button);
+
+ p->priv->menu = gtk_menu_new ();
+ gtk_widget_show (p->priv->menu);
+
+ bonobo_window_add_popup (p->priv->window,
+ GTK_MENU (p->priv->menu),
+ ephy_embed_popup_get_popup_path (EPHY_EMBED_POPUP (p)));
+
+ gtk_menu_popup (GTK_MENU (p->priv->menu),
+ NULL, NULL, NULL, NULL,
+ button, gtk_get_current_event_time ());
+}
+
diff --git a/embed/ephy-embed-popup-bw.h b/embed/ephy-embed-popup-bw.h
new file mode 100644
index 000000000..49f8fecd5
--- /dev/null
+++ b/embed/ephy-embed-popup-bw.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EPHY_EMBED_POPUP_BW_H
+#define EPHY_EMBED_POPUP_BW_H
+
+#include "ephy-embed-popup.h"
+#include <bonobo/bonobo-window.h>
+
+G_BEGIN_DECLS
+
+typedef struct EphyEmbedPopupBWClass EphyEmbedPopupBWClass;
+
+#define EPHY_EMBED_POPUP_BW_TYPE (ephy_embed_popup_bw_get_type ())
+#define EPHY_EMBED_POPUP_BW(obj) (GTK_CHECK_CAST ((obj), EPHY_EMBED_POPUP_BW_TYPE, \
+ EphyEmbedPopupBW))
+#define EPHY_EMBED_POPUP_BW_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), EPHY_EMBED_POPUP_BW_TYPE,\
+ EphyEmbedPopupBWClass))
+#define IS_EPHY_EMBED_POPUP_BW(obj) (GTK_CHECK_TYPE ((obj), EPHY_EMBED_POPUP_BW_TYPE))
+#define IS_EPHY_EMBED_POPUP_BW_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), EPHY_EMBED_POPUP_BW))
+#define EPHY_EMBED_POPUP_BW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ EPHY_EMBED_POPUP_BW_TYPE, EphyEmbedPopupBWClass))
+
+typedef struct EphyEmbedPopupBW EphyEmbedPopupBW;
+typedef struct EphyEmbedPopupBWPrivate EphyEmbedPopupBWPrivate;
+
+struct EphyEmbedPopupBW
+{
+ EphyEmbedPopup parent;
+ EphyEmbedPopupBWPrivate *priv;
+};
+
+struct EphyEmbedPopupBWClass
+{
+ EphyEmbedPopupClass parent_class;
+};
+
+GType ephy_embed_popup_bw_get_type (void);
+EphyEmbedPopupBW * ephy_embed_popup_bw_new (BonoboWindow *window);
+
+G_END_DECLS
+
+#endif
diff --git a/embed/ephy-embed-popup-control.c b/embed/ephy-embed-popup-control.c
new file mode 100644
index 000000000..a74249cc8
--- /dev/null
+++ b/embed/ephy-embed-popup-control.c
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Ricardo Fernández Pascual
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "ephy-embed-popup-control.h"
+#include "ephy-gobject-misc.h"
+#include "ephy-bonobo-extensions.h"
+
+#include <gtk/gtkmain.h>
+
+enum
+{
+ PROP_0,
+ PROP_BONOBO_CONTROL
+};
+
+struct EphyEmbedPopupControlPrivate
+{
+ BonoboControl *control;
+};
+
+static void
+ephy_embed_popup_control_class_init (EphyEmbedPopupControlClass *klass);
+static void
+ephy_embed_popup_control_init (EphyEmbedPopupControl *gep);
+static void
+ephy_embed_popup_control_finalize (GObject *object);
+static void
+ephy_embed_popup_control_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void
+ephy_embed_popup_control_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void
+ephy_embed_popup_control_set_control (EphyEmbedPopupControl *p,
+ BonoboControl *control);
+static void
+ephy_embed_popup_control_show_impl (EphyEmbedPopup *p,
+ EphyEmbed *embed);
+
+static EphyEmbedPopupClass *parent_class = NULL;
+
+MAKE_GET_TYPE (ephy_embed_popup_control, "EphyEmbedPopupControl", EphyEmbedPopupControl,
+ ephy_embed_popup_control_class_init, ephy_embed_popup_control_init,
+ EPHY_EMBED_POPUP_TYPE);
+
+static void
+ephy_embed_popup_control_class_init (EphyEmbedPopupControlClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = EPHY_EMBED_POPUP_CLASS (g_type_class_peek_parent (klass));
+
+ object_class->finalize = ephy_embed_popup_control_finalize;
+ object_class->set_property = ephy_embed_popup_control_set_property;
+ object_class->get_property = ephy_embed_popup_control_get_property;
+
+ g_object_class_install_property (object_class,
+ PROP_BONOBO_CONTROL,
+ g_param_spec_object ("BonoboControl",
+ "BonoboControl",
+ "Bonobo control",
+ BONOBO_TYPE_CONTROL,
+ G_PARAM_READWRITE));
+
+ EPHY_EMBED_POPUP_CLASS (klass)->show = ephy_embed_popup_control_show_impl;
+}
+
+static void
+ephy_embed_popup_control_init (EphyEmbedPopupControl *gep)
+{
+ gep->priv = g_new0 (EphyEmbedPopupControlPrivate, 1);
+ gep->priv->control = NULL;
+}
+
+static void
+ephy_embed_popup_control_finalize (GObject *object)
+{
+ EphyEmbedPopupControl *gep;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (IS_EPHY_EMBED_POPUP_CONTROL (object));
+
+ gep = EPHY_EMBED_POPUP_CONTROL (object);
+
+ g_return_if_fail (gep->priv != NULL);
+
+ g_free (gep->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+ephy_embed_popup_control_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EphyEmbedPopupControl *p = EPHY_EMBED_POPUP_CONTROL (object);
+
+ switch (prop_id)
+ {
+ case PROP_BONOBO_CONTROL:
+ ephy_embed_popup_control_set_control (p, g_value_get_object (value));
+ break;
+ }
+}
+
+static void
+ephy_embed_popup_control_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ EphyEmbedPopupControl *p = EPHY_EMBED_POPUP_CONTROL (object);
+
+ switch (prop_id)
+ {
+ case PROP_BONOBO_CONTROL:
+ g_value_set_object (value, p->priv->control);
+ break;
+ }
+}
+
+static void
+ephy_embed_popup_control_set_control (EphyEmbedPopupControl *p,
+ BonoboControl *control)
+{
+ p->priv->control = control;
+}
+
+EphyEmbedPopupControl *
+ephy_embed_popup_control_new (BonoboControl *control)
+{
+ EphyEmbedPopupControl *p;
+
+ p = EPHY_EMBED_POPUP_CONTROL (g_object_new (EPHY_EMBED_POPUP_CONTROL_TYPE,
+ "BonoboControl", control,
+ NULL));
+
+ g_return_val_if_fail (p->priv != NULL, NULL);
+
+ return p;
+}
+
+static void
+ephy_embed_popup_control_show_impl (EphyEmbedPopup *pp,
+ EphyEmbed *embed)
+{
+ EphyEmbedPopupControl *p = EPHY_EMBED_POPUP_CONTROL (pp);
+ EphyEmbedEvent *event = ephy_embed_popup_get_event (pp);
+ BonoboUIComponent *uic = bonobo_control_get_popup_ui_component (p->priv->control);
+ const char *path;
+ char *path_dst;
+ guint button;
+
+ ephy_embed_event_get_mouse_button (event, &button);
+ ephy_embed_popup_set_embed (pp, embed);
+ path = ephy_embed_popup_get_popup_path (pp);
+ path_dst = g_strdup_printf ("/popups/button%d", button);
+
+ /* this is a hack because bonobo apis for showing popups are broken */
+ ephy_bonobo_replace_path (uic, path, path_dst);
+
+ bonobo_control_do_popup (p->priv->control, button,
+ gtk_get_current_event_time ());
+
+ g_free (path_dst);
+}
+
diff --git a/embed/ephy-embed-popup-control.h b/embed/ephy-embed-popup-control.h
new file mode 100644
index 000000000..4f45efe5f
--- /dev/null
+++ b/embed/ephy-embed-popup-control.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Ricardo Fernández Pascual
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EPHY_EMBED_POPUP_CONTROL_H
+#define EPHY_EMBED_POPUP_CONTROL_H
+
+#include "ephy-embed-popup.h"
+#include <bonobo/bonobo-control.h>
+
+G_BEGIN_DECLS
+
+typedef struct EphyEmbedPopupControlClass EphyEmbedPopupControlClass;
+
+#define EPHY_EMBED_POPUP_CONTROL_TYPE (ephy_embed_popup_control_get_type ())
+#define EPHY_EMBED_POPUP_CONTROL(obj) (GTK_CHECK_CAST ((obj), EPHY_EMBED_POPUP_CONTROL_TYPE, \
+ EphyEmbedPopupControl))
+#define EPHY_EMBED_POPUP_CONTROL_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), \
+ EPHY_EMBED_POPUP_CONTROL_TYPE,\
+ EphyEmbedPopupControlClass))
+#define IS_EPHY_EMBED_POPUP_CONTROL(obj) (GTK_CHECK_TYPE ((obj), EPHY_EMBED_POPUP_CONTROL_TYPE))
+#define IS_EPHY_EMBED_POPUP_CONTROL_CLASS(klass)(GTK_CHECK_CLASS_TYPE ((klass), \
+ EPHY_EMBED_POPUP_CONTROL))
+#define EPHY_EMBED_POPUP_CONTROL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ EPHY_EMBED_POPUP_CONTROL_TYPE, \
+ EphyEmbedPopupControlClass))
+
+typedef struct EphyEmbedPopupControl EphyEmbedPopupControl;
+typedef struct EphyEmbedPopupControlPrivate EphyEmbedPopupControlPrivate;
+
+struct EphyEmbedPopupControl
+{
+ EphyEmbedPopup parent;
+ EphyEmbedPopupControlPrivate *priv;
+};
+
+struct EphyEmbedPopupControlClass
+{
+ EphyEmbedPopupClass parent_class;
+};
+
+GType ephy_embed_popup_control_get_type (void);
+EphyEmbedPopupControl *ephy_embed_popup_control_new (BonoboControl *control);
+
+G_END_DECLS
+
+#endif
diff --git a/embed/ephy-embed-popup.c b/embed/ephy-embed-popup.c
new file mode 100644
index 000000000..4710fa211
--- /dev/null
+++ b/embed/ephy-embed-popup.c
@@ -0,0 +1,623 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "ephy-embed-popup.h"
+#include "ephy-embed-event.h"
+#include "ephy-embed-utils.h"
+#include "ephy-prefs.h"
+#include "eel-gconf-extensions.h"
+#include "ephy-bonobo-extensions.h"
+#include "ephy-file-helpers.h"
+
+#include <string.h>
+#include <bonobo/bonobo-ui-component.h>
+#include <gtk/gtkclipboard.h>
+#include <libgnome/gnome-exec.h>
+
+typedef enum
+{
+ EMBED_POPUP_INPUT,
+ EMBED_POPUP_DOCUMENT,
+ EMBED_POPUP_ELEMENT
+} EmbedPopupType;
+
+struct EphyEmbedPopupPrivate
+{
+ EphyEmbedEvent *event;
+ EphyEmbed *embed;
+ EmbedEventContext context;
+ BonoboUIComponent *ui_component;
+ char *selection;
+ EmbedPopupType popup_type;
+};
+
+static void
+ephy_embed_popup_class_init (EphyEmbedPopupClass *klass);
+static void
+ephy_embed_popup_init (EphyEmbedPopup *gep);
+static void
+ephy_embed_popup_finalize (GObject *object);
+static void
+embed_popup_copy_location_cmd (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname);
+static void
+embed_popup_copy_email_cmd (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname);
+static void
+embed_popup_copy_link_location_cmd (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname);
+static void
+embed_popup_download_link_cmd (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname);
+static void
+embed_popup_save_image_as_cmd (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname);
+static void
+embed_popup_set_image_as_background_cmd (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname);
+static void
+embed_popup_copy_image_location_cmd (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname);
+static void
+embed_popup_save_page_as_cmd (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname);
+static void
+embed_popup_save_background_as_cmd (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname);
+static void
+embed_popup_open_frame_cmd (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname);
+static void
+embed_popup_reload_frame_cmd (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname);
+
+static void
+embed_popup_open_image_cmd (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname);
+static void
+embed_popup_copy_to_clipboard (EphyEmbedPopup *popup, const char *text);
+
+static GObjectClass *parent_class = NULL;
+
+#define DOCUMENT_POPUP_PATH "/popups/EphyEmbedDocumentPopup"
+#define ELEMENT_POPUP_PATH "/popups/EphyEmbedElementPopup"
+#define INPUT_POPUP_PATH "/popups/EphyEmbedInputPopup"
+
+#define EPHY_POPUP_NAVIGATION_ITEMS_PLACEHOLDER "/popups/EphyEmbedDocumentPopup/NavigationItems"
+#define EPHY_POPUP_LINK_ITEMS_PLACEHOLDER "/popups/EphyEmbedElementPopup/LinkItems"
+#define EPHY_POPUP_EMAIL_LINK_ITEMS_PLACEHOLDER "/popups/EphyEmbedElementPopup/EmailLinkItems"
+#define EPHY_POPUP_IMAGE_ITEMS_PLACEHOLDER "/popups/EphyEmbedElementPopup/ImageItems"
+#define EPHY_POPUP_FRAME_ITEMS_PLACEHOLDER "/popups/EphyEmbedDocumentPopup/FrameItems"
+#define EPHY_POPUP_BETWEEN_ELEMENTS1_PLACEHOLDER "/popups/EphyEmbedElementPopup/BetweenElements1"
+#define EPHY_POPUP_SAVE_BG_PATH "/commands/DPSaveBackgroundAs"
+#define EPHY_POPUP_OPEN_IMAGE_PATH "/commands/EPOpenImage"
+
+BonoboUIVerb embed_popup_verbs [] = {
+ BONOBO_UI_VERB ("EPCopyLinkLocation", (BonoboUIVerbFn)embed_popup_copy_link_location_cmd),
+ BONOBO_UI_VERB ("EPDownloadLink", (BonoboUIVerbFn)embed_popup_download_link_cmd),
+ BONOBO_UI_VERB ("EPOpenImage", (BonoboUIVerbFn)embed_popup_open_image_cmd),
+ BONOBO_UI_VERB ("EPSaveImageAs", (BonoboUIVerbFn)embed_popup_save_image_as_cmd),
+ BONOBO_UI_VERB ("EPSetImageAsBackground", (BonoboUIVerbFn)embed_popup_set_image_as_background_cmd),
+ BONOBO_UI_VERB ("EPCopyImageLocation", (BonoboUIVerbFn)embed_popup_copy_image_location_cmd),
+
+ BONOBO_UI_VERB ("DPCopyLocation", (BonoboUIVerbFn)embed_popup_copy_location_cmd),
+ BONOBO_UI_VERB ("EPCopyEmail", (BonoboUIVerbFn)embed_popup_copy_email_cmd),
+ BONOBO_UI_VERB ("DPSavePageAs", (BonoboUIVerbFn)embed_popup_save_page_as_cmd),
+ BONOBO_UI_VERB ("DPSaveBackgroundAs", (BonoboUIVerbFn)embed_popup_save_background_as_cmd),
+ BONOBO_UI_VERB ("DPOpenFrame", (BonoboUIVerbFn)embed_popup_open_frame_cmd),
+ BONOBO_UI_VERB ("DPReloadFrame", (BonoboUIVerbFn)embed_popup_reload_frame_cmd),
+
+ BONOBO_UI_VERB_END
+};
+
+GType
+ephy_embed_popup_get_type (void)
+{
+ static GType ephy_embed_popup_type = 0;
+
+ if (ephy_embed_popup_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (EphyEmbedPopupClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) ephy_embed_popup_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (EphyEmbedPopup),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) ephy_embed_popup_init
+ };
+
+
+ ephy_embed_popup_type = g_type_register_static (G_TYPE_OBJECT,
+ "EphyEmbedPopup",
+ &our_info, 0);
+ }
+
+ return ephy_embed_popup_type;
+}
+
+static void
+ephy_embed_popup_class_init (EphyEmbedPopupClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = (GObjectClass *) g_type_class_peek_parent (klass);
+
+ object_class->finalize = ephy_embed_popup_finalize;
+
+ klass->show = NULL; /* abstract */
+}
+
+static void
+ephy_embed_popup_init (EphyEmbedPopup *gep)
+{
+ gep->priv = g_new0 (EphyEmbedPopupPrivate, 1);
+ gep->priv->embed = NULL;
+ gep->priv->event = NULL;
+ gep->priv->ui_component = NULL;
+}
+
+static void
+ephy_embed_popup_finalize (GObject *object)
+{
+ EphyEmbedPopup *gep;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (IS_EPHY_EMBED_POPUP (object));
+
+ gep = EPHY_EMBED_POPUP (object);
+
+ g_return_if_fail (gep->priv != NULL);
+
+ if (gep->priv->event)
+ {
+ g_object_unref (G_OBJECT (gep->priv->event));
+ }
+
+ g_free (gep->priv->selection);
+
+ g_free (gep->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+setup_element_menu (EphyEmbedPopup *p)
+{
+ gboolean is_link, is_image, is_email_link;
+
+ is_image = p->priv->context & EMBED_CONTEXT_IMAGE;
+ is_email_link = p->priv->context & EMBED_CONTEXT_EMAIL_LINK;
+ is_link = (p->priv->context & EMBED_CONTEXT_LINK) && !is_email_link;
+
+ ephy_bonobo_set_hidden (p->priv->ui_component,
+ EPHY_POPUP_LINK_ITEMS_PLACEHOLDER,
+ !is_link);
+ ephy_bonobo_set_hidden (p->priv->ui_component,
+ EPHY_POPUP_IMAGE_ITEMS_PLACEHOLDER,
+ !is_image);
+ ephy_bonobo_set_hidden (p->priv->ui_component,
+ EPHY_POPUP_EMAIL_LINK_ITEMS_PLACEHOLDER,
+ !is_email_link);
+ ephy_bonobo_set_hidden (p->priv->ui_component,
+ EPHY_POPUP_BETWEEN_ELEMENTS1_PLACEHOLDER,
+ !is_image || (!is_link && !is_email_link));
+}
+
+static void
+setup_document_menu (EphyEmbedPopup *p)
+{
+ gboolean is_framed;
+ GValue *value;
+ gboolean has_background;
+
+ ephy_embed_event_get_property (p->priv->event,
+ "framed_page", &value);
+ is_framed = g_value_get_int (value);
+ ephy_bonobo_set_hidden (BONOBO_UI_COMPONENT(p->priv->ui_component),
+ EPHY_POPUP_FRAME_ITEMS_PLACEHOLDER, !is_framed);
+
+ has_background = ephy_embed_event_has_property (p->priv->event,
+ "background_image");
+ ephy_bonobo_set_hidden (BONOBO_UI_COMPONENT(p->priv->ui_component),
+ EPHY_POPUP_SAVE_BG_PATH, !has_background);
+}
+
+void
+ephy_embed_popup_set_event (EphyEmbedPopup *p,
+ EphyEmbedEvent *event)
+{
+ EmbedEventContext context;
+
+ if (p->priv->event)
+ {
+ g_object_unref (G_OBJECT (p->priv->event));
+ }
+
+ ephy_embed_event_get_context (event, &context);
+
+ p->priv->context = context;
+
+ p->priv->event = event;
+ g_object_ref (G_OBJECT(event));
+
+ if ((p->priv->context & EMBED_CONTEXT_LINK) ||
+ (p->priv->context & EMBED_CONTEXT_EMAIL_LINK) ||
+ (p->priv->context & EMBED_CONTEXT_IMAGE))
+ {
+ setup_element_menu (p);
+ p->priv->popup_type = EMBED_POPUP_ELEMENT;
+ }
+ else if (p->priv->context & EMBED_CONTEXT_INPUT)
+ {
+ p->priv->popup_type = EMBED_POPUP_INPUT;
+ }
+ else
+ {
+ setup_document_menu (p);
+ p->priv->popup_type = EMBED_POPUP_DOCUMENT;
+ }
+}
+
+void
+ephy_embed_popup_set_embed (EphyEmbedPopup *p,
+ EphyEmbed *e)
+{
+ p->priv->embed = e;
+}
+
+EphyEmbed *
+ephy_embed_popup_get_embed (EphyEmbedPopup *p)
+{
+ return p->priv->embed;
+}
+
+void
+ephy_embed_popup_show (EphyEmbedPopup *p,
+ EphyEmbed *embed)
+{
+ EphyEmbedPopupClass *klass = EPHY_EMBED_POPUP_GET_CLASS (p);
+ return klass->show (p, embed);
+
+}
+
+void
+ephy_embed_popup_connect_verbs (EphyEmbedPopup *p,
+ BonoboUIComponent *ui_component)
+{
+
+ p->priv->ui_component = BONOBO_UI_COMPONENT (ui_component);
+
+ bonobo_ui_component_add_verb_list_with_data (BONOBO_UI_COMPONENT(ui_component),
+ embed_popup_verbs,
+ p);
+}
+
+EphyEmbedEvent *
+ephy_embed_popup_get_event (EphyEmbedPopup *p)
+{
+ g_return_val_if_fail (IS_EPHY_EMBED_POPUP (p), NULL);
+
+ return p->priv->event;
+}
+
+static void
+embed_popup_copy_location_cmd (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname)
+{
+ char *location;
+ ephy_embed_get_location (popup->priv->embed, FALSE,
+ FALSE, &location);
+ embed_popup_copy_to_clipboard (popup, location);
+ g_free (location);
+}
+
+static void
+embed_popup_copy_email_cmd (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname)
+{
+ EphyEmbedEvent *info;
+ const char *location;
+ GValue *value;
+
+ info = ephy_embed_popup_get_event (popup);
+ ephy_embed_event_get_property (info, "email", &value);
+ location = g_value_get_string (value);
+ embed_popup_copy_to_clipboard (popup, location);
+}
+
+static void
+embed_popup_copy_link_location_cmd (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname)
+{
+ EphyEmbedEvent *info;
+ const char *location;
+ GValue *value;
+
+ info = ephy_embed_popup_get_event (popup);
+ ephy_embed_event_get_property (info, "link", &value);
+ location = g_value_get_string (value);
+ embed_popup_copy_to_clipboard (popup, location);
+}
+
+static void
+save_property_url (EphyEmbedPopup *popup,
+ gboolean ask_dest,
+ gboolean show_progress,
+ const char *property)
+{
+ EphyEmbedEvent *info;
+ const char *location;
+ GValue *value;
+ GtkWidget *widget;
+ GtkWidget *window;
+ EphyEmbedPersist *persist;
+
+ info = ephy_embed_popup_get_event (popup);
+ ephy_embed_event_get_property (info, property, &value);
+ location = g_value_get_string (value);
+
+ widget = GTK_WIDGET (popup->priv->embed);
+ window = gtk_widget_get_toplevel (widget);
+
+ persist = ephy_embed_persist_new (popup->priv->embed);
+
+ ephy_embed_persist_set_source (persist, location);
+
+ if (show_progress)
+ {
+ ephy_embed_persist_set_flags (persist,
+ EMBED_PERSIST_SHOW_PROGRESS);
+ }
+
+ ephy_embed_utils_save (window,
+ CONF_STATE_DOWNLOADING_DIR,
+ ask_dest,
+ FALSE,
+ persist);
+}
+
+const char *
+ephy_embed_popup_get_popup_path (EphyEmbedPopup *p)
+{
+ const char *result = NULL;
+
+ switch (p->priv->popup_type)
+ {
+ case EMBED_POPUP_INPUT:
+ result = INPUT_POPUP_PATH;
+ break;
+ case EMBED_POPUP_ELEMENT:
+ result = ELEMENT_POPUP_PATH;
+ break;
+ case EMBED_POPUP_DOCUMENT:
+ result = DOCUMENT_POPUP_PATH;
+ break;
+ }
+
+ return result;
+}
+
+/* commands */
+
+static void
+embed_popup_download_link_cmd (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname)
+{
+ save_property_url (popup,
+ eel_gconf_get_boolean
+ (CONF_STATE_DOWNLOADING_DIR),
+ TRUE, "link");
+}
+
+static void
+embed_popup_save_image_as_cmd (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname)
+{
+ save_property_url (popup, TRUE, FALSE, "image");
+}
+
+#define CONF_DESKTOP_BG_PICTURE "/desktop/gnome/background/picture_filename"
+#define CONF_DESKTOP_BG_TYPE "/desktop/gnome/background/picture_options"
+
+static void
+background_download_completed (EphyEmbedPersist *persist,
+ gpointer data)
+{
+ const char *bg;
+ char *type;
+
+ ephy_embed_persist_get_dest (persist, &bg);
+ eel_gconf_set_string (CONF_DESKTOP_BG_PICTURE, bg);
+
+ type = eel_gconf_get_string (CONF_DESKTOP_BG_TYPE);
+ if (type || strcmp (type, "none") == 0)
+ {
+ eel_gconf_set_string (CONF_DESKTOP_BG_TYPE,
+ "wallpaper");
+ }
+
+ g_free (type);
+
+ g_object_unref (persist);
+}
+
+static void
+embed_popup_set_image_as_background_cmd (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname)
+{
+ EphyEmbedEvent *info;
+ const char *location;
+ char *dest, *base;
+ GValue *value;
+ EphyEmbedPersist *persist;
+
+ info = ephy_embed_popup_get_event (popup);
+ ephy_embed_event_get_property (info, "image", &value);
+ location = g_value_get_string (value);
+
+ persist = ephy_embed_persist_new (popup->priv->embed);
+
+ base = g_path_get_basename (location);
+ dest = g_build_filename (ephy_dot_dir (),
+ base, NULL);
+
+ ephy_embed_persist_set_source (persist, location);
+ ephy_embed_persist_set_dest (persist, dest);
+
+ ephy_embed_persist_save (persist);
+
+ g_signal_connect (persist, "completed",
+ G_CALLBACK (background_download_completed),
+ NULL);
+
+ g_free (dest);
+ g_free (base);
+}
+
+static void
+embed_popup_copy_image_location_cmd (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname)
+{
+ EphyEmbedEvent *info;
+ const char *location;
+ GValue *value;
+
+ info = ephy_embed_popup_get_event (popup);
+ ephy_embed_event_get_property (info, "image", &value);
+ location = g_value_get_string (value);
+ embed_popup_copy_to_clipboard (popup, location);
+}
+
+static void
+save_url (EphyEmbedPopup *popup,
+ gboolean ask_dest,
+ gboolean show_progress,
+ const char *url)
+{
+ GtkWidget *widget;
+ GtkWidget *window;
+ EphyEmbedPersist *persist;
+
+ widget = GTK_WIDGET (popup->priv->embed);
+ window = gtk_widget_get_toplevel (widget);
+
+ persist = ephy_embed_persist_new (popup->priv->embed);
+ ephy_embed_persist_set_source (persist, url);
+
+ if (show_progress)
+ {
+ ephy_embed_persist_set_flags (persist,
+ EMBED_PERSIST_SHOW_PROGRESS);
+ }
+
+ ephy_embed_utils_save (window,
+ CONF_STATE_DOWNLOADING_DIR,
+ ask_dest,
+ FALSE,
+ persist);
+}
+
+static void
+embed_popup_save_page_as_cmd (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname)
+{
+ char *location;
+
+ ephy_embed_get_location (popup->priv->embed,
+ FALSE, FALSE, &location);
+ save_url (popup, TRUE, FALSE, location);
+ g_free (location);
+}
+
+static void
+embed_popup_save_background_as_cmd (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname)
+{
+ save_property_url (popup, TRUE, FALSE, "background_image");
+}
+
+static void
+embed_popup_open_frame_cmd (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname)
+{
+ char *location;
+
+ ephy_embed_get_location (popup->priv->embed,
+ FALSE, FALSE, &location);
+
+ ephy_embed_load_url (popup->priv->embed, location);
+}
+
+static void
+embed_popup_reload_frame_cmd (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname)
+{
+ /* FIXME implement */
+}
+
+static void
+embed_popup_open_image_cmd (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname)
+{
+ EphyEmbedEvent *info;
+ const char *location;
+ GValue *value;
+
+ info = ephy_embed_popup_get_event (popup);
+ ephy_embed_event_get_property (info, "image", &value);
+ location = g_value_get_string (value);
+
+ ephy_embed_load_url (popup->priv->embed, location);
+}
+
+static void
+embed_popup_copy_to_clipboard (EphyEmbedPopup *popup, const char *text)
+{
+ gtk_clipboard_set_text (gtk_clipboard_get (GDK_NONE),
+ text, -1);
+ gtk_clipboard_set_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
+ text, -1);
+}
diff --git a/embed/ephy-embed-popup.h b/embed/ephy-embed-popup.h
new file mode 100644
index 000000000..6416bdfcd
--- /dev/null
+++ b/embed/ephy-embed-popup.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EPHY_EMBED_POPUP_H
+#define EPHY_EMBED_POPUP_H
+
+#include "ephy-embed.h"
+#include <glib-object.h>
+#include <bonobo/bonobo-ui-component.h>
+
+G_BEGIN_DECLS
+
+typedef struct EphyEmbedPopupClass EphyEmbedPopupClass;
+
+#define EPHY_EMBED_POPUP_TYPE (ephy_embed_popup_get_type ())
+#define EPHY_EMBED_POPUP(obj) (GTK_CHECK_CAST ((obj), EPHY_EMBED_POPUP_TYPE, EphyEmbedPopup))
+#define EPHY_EMBED_POPUP_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), EPHY_EMBED_POPUP_TYPE, EphyEmbedPopupClass))
+#define IS_EPHY_EMBED_POPUP(obj) (GTK_CHECK_TYPE ((obj), EPHY_EMBED_POPUP_TYPE))
+#define IS_EPHY_EMBED_POPUP_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), EPHY_EMBED_POPUP))
+#define EPHY_EMBED_POPUP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EPHY_EMBED_POPUP_TYPE, EphyEmbedPopupClass))
+
+typedef struct EphyEmbedPopup EphyEmbedPopup;
+typedef struct EphyEmbedPopupPrivate EphyEmbedPopupPrivate;
+
+struct EphyEmbedPopup
+{
+ GObject parent;
+ EphyEmbedPopupPrivate *priv;
+};
+
+struct EphyEmbedPopupClass
+{
+ GObjectClass parent_class;
+
+ void (*show) (EphyEmbedPopup *p,
+ EphyEmbed *embed);
+};
+
+
+
+/* this class is abstract, don't look for the constructor */
+
+GType ephy_embed_popup_get_type (void);
+void ephy_embed_popup_connect_verbs (EphyEmbedPopup *p,
+ BonoboUIComponent *ui_component);
+void ephy_embed_popup_set_embed (EphyEmbedPopup *p,
+ EphyEmbed *e);
+EphyEmbed * ephy_embed_popup_get_embed (EphyEmbedPopup *p);
+void ephy_embed_popup_set_event (EphyEmbedPopup *p,
+ EphyEmbedEvent *event);
+EphyEmbedEvent * ephy_embed_popup_get_event (EphyEmbedPopup *p);
+void ephy_embed_popup_show (EphyEmbedPopup *p,
+ EphyEmbed *embed);
+const char * ephy_embed_popup_get_popup_path (EphyEmbedPopup *p);
+
+G_END_DECLS
+
+#endif
diff --git a/embed/ephy-embed-prefs.h b/embed/ephy-embed-prefs.h
new file mode 100644
index 000000000..8caa14b07
--- /dev/null
+++ b/embed/ephy-embed-prefs.h
@@ -0,0 +1,46 @@
+#define CONF_NETWORK_SOCKS_PROXY_VERSION "/apps/epiphany/network/socks_proxy_version"
+#define CONF_NETWORK_NO_PROXIES_FOR "/apps/epiphany/network/no_proxies_for"
+#define CONF_NETWORK_DISK_CACHE "/apps/epiphany/network/disk_cache_size"
+#define CONF_NETWORK_MEMORY_CACHE "/apps/epiphany/network/mem_cache_size"
+#define CONF_NETWORK_CACHE_COMPARE "/apps/epiphany/network/cache_compare"
+#define CONF_NETWORK_USER_AGENT "/apps/epiphany/network/user_agent"
+#define CONF_RENDERING_FONT "/apps/epiphany/rendering/font"
+#define CONF_RENDERING_FONT_VAR_SIZE "/apps/epiphany/rendering/font_var_size"
+#define CONF_RENDERING_FONT_FIXED_SIZE "/apps/epiphany/rendering/font_fixed_size"
+#define CONF_RENDERING_FONT_MIN_SIZE "/apps/epiphany/rendering/font_min_size"
+#define CONF_RENDERING_LANGUAGE "/apps/epiphany/rendering/lang"
+#define CONF_RENDERING_USE_OWN_COLORS "/apps/epiphany/rendering/use_own_colors"
+#define CONF_RENDERING_USE_SYSTEM_COLORS "/apps/epiphany/rendering/use_system_colors"
+#define CONF_RENDERING_USE_OWN_FONTS "/apps/epiphany/rendering/use_own_fonts"
+#define CONF_RENDERING_BG_COLOR "/apps/epiphany/rendering/background_color"
+#define CONF_RENDERING_TEXT_COLOR "/apps/epiphany/rendering/text_color"
+#define CONF_RENDERING_VISITED_LINKS "/apps/epiphany/rendering/visited_link_color"
+#define CONF_RENDERING_UNVISITED_LINKS "/apps/epiphany/rendering/unvisited_link_color"
+#define CONF_RENDERING_UNDERLINE_LINKS "/apps/epiphany/rendering/underline_links"
+#define CONF_FILTERING_ALLOW_POPUPS "/apps/epiphany/filtering/allow_popups"
+#define CONF_FILTERING_IMAGE_LOADING_TYPE "/apps/epiphany/filtering/image_loading_type"
+#define CONF_FILTERING_ANIMATE_TYPE "/apps/epiphany/filtering/animate_type"
+#define CONF_FILTERING_STATUSBAR_REWRITE "/apps/epiphany/filtering/statusbar_rewrite"
+#define CONF_FILTERING_JAVA_ENABLED "/apps/epiphany/filtering/java_enabled"
+#define CONF_FILTERING_JAVASCRIPT_ENABLED "/apps/epiphany/filtering/javascript_enabled"
+#define CONF_PERSISTENT_COOKIES_BEHAVIOR "/apps/epiphany/filtering/cookie_behavior"
+#define CONF_PERSISTENT_COOKIE_WARN "/apps/epiphany/filterin/cookie_warn"
+#define CONF_PERSISTENT_COOKIE_LIFETIME "/apps/epiphany/filtering/cookie_lifetime"
+#define CONF_PERSISTENT_PASSWORDS_SAVE "/apps/epiphany/filtering/passwords_save"
+#define CONF_LANGUAGE_AUTODETECT_CHARSET "/apps/epiphany/rendering/autodetect_charset"
+#define CONF_LANGUAGE_DEFAULT_CHARSET "/apps/epiphany/rendering/default_charset"
+#define CONF_RENDERING_DEFAULT_FONT "/apps/epiphany/rendering/default_font"
+#define CONF_FILTERING_DEFAULT_STATUSBAR "/apps/epiphany/filtering/default_allow_statusbar"
+
+/* These are defined gnome wide now */
+#define CONF_NETWORK_PROXY_MODE "/system/proxy/mode"
+#define CONF_NETWORK_HTTP_PROXY "/system/http_proxy/host"
+#define CONF_NETWORK_SSL_PROXY "/system/proxy/secure_host"
+#define CONF_NETWORK_FTP_PROXY "/system/proxy/ftp_host"
+#define CONF_NETWORK_SOCKS_PROXY "/system/proxy/socks_host"
+#define CONF_NETWORK_HTTP_PROXY_PORT "/system/http_proxy/port"
+#define CONF_NETWORK_SSL_PROXY_PORT "/system/proxy/secure_port"
+#define CONF_NETWORK_FTP_PROXY_PORT "/system/proxy/ftp_port"
+#define CONF_NETWORK_SOCKS_PROXY_PORT "/system/proxy/socks_port"
+#define CONF_NETWORK_PROXY_AUTO_URL "/system/proxy/autoconfig_url"
+
diff --git a/embed/ephy-embed-shell.c b/embed/ephy-embed-shell.c
new file mode 100644
index 000000000..541e48007
--- /dev/null
+++ b/embed/ephy-embed-shell.c
@@ -0,0 +1,507 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+
+#include "ephy-embed-shell.h"
+#include "ephy-marshal.h"
+#include "ephy-favicon-cache.h"
+
+#include "mozilla-embed-shell.h"
+
+#include <string.h>
+
+enum
+{
+ NEW_WINDOW,
+ LAST_SIGNAL
+};
+
+struct EphyEmbedShellPrivate
+{
+ EphyHistory *global_history;
+ DownloaderView *downloader_view;
+ GList *embeds;
+ EphyFaviconCache *favicon_cache;
+};
+
+static void
+ephy_embed_shell_class_init (EphyEmbedShellClass *klass);
+static void
+ephy_embed_shell_init (EphyEmbedShell *ges);
+static void
+ephy_embed_shell_finalize (GObject *object);
+static void
+ephy_embed_shell_finalize (GObject *object);
+
+static EphyHistory *
+impl_get_global_history (EphyEmbedShell *shell);
+static DownloaderView *
+impl_get_downloader_view (EphyEmbedShell *shell);
+
+static GObjectClass *parent_class = NULL;
+static guint ephy_embed_shell_signals[LAST_SIGNAL] = { 0 };
+
+EphyEmbedShell *embed_shell;
+
+GType
+ephy_embed_shell_get_type (void)
+{
+ static GType ephy_embed_shell_type = 0;
+
+ if (ephy_embed_shell_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (EphyEmbedShellClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) ephy_embed_shell_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (EphyEmbedShell),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) ephy_embed_shell_init
+ };
+
+ ephy_embed_shell_type = g_type_register_static (G_TYPE_OBJECT,
+ "EphyEmbedShell",
+ &our_info, 0);
+ }
+
+ return ephy_embed_shell_type;
+}
+
+static void
+ephy_embed_shell_class_init (EphyEmbedShellClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = (GObjectClass *) g_type_class_peek_parent (klass);
+
+ object_class->finalize = ephy_embed_shell_finalize;
+ klass->get_downloader_view = impl_get_downloader_view;
+ klass->get_global_history = impl_get_global_history;
+
+ ephy_embed_shell_signals[NEW_WINDOW] =
+ g_signal_new ("new_window_orphan",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EphyEmbedShellClass, new_window),
+ NULL, NULL,
+ ephy_marshal_VOID__POINTER_INT,
+ G_TYPE_NONE,
+ 2,
+ G_TYPE_POINTER,
+ G_TYPE_INT);
+}
+
+static void
+ephy_embed_shell_init (EphyEmbedShell *ges)
+{
+
+ /* Singleton, globally accessible */
+ embed_shell = ges;
+
+ ges->priv = g_new0 (EphyEmbedShellPrivate, 1);
+
+ ges->priv->global_history = NULL;
+ ges->priv->downloader_view = NULL;
+ ges->priv->embeds = NULL;
+
+ ges->priv->favicon_cache = NULL;
+}
+
+static void
+ephy_embed_shell_finalize (GObject *object)
+{
+ EphyEmbedShell *ges;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (IS_EPHY_EMBED_SHELL (object));
+
+ ges = EPHY_EMBED_SHELL (object);
+
+ g_return_if_fail (ges->priv != NULL);
+
+ if (ges->priv->global_history)
+ {
+ g_object_unref (ges->priv->global_history);
+ }
+
+ if (ges->priv->downloader_view)
+ {
+ g_object_remove_weak_pointer
+ (G_OBJECT(ges->priv->downloader_view),
+ (gpointer *)&ges->priv->downloader_view);
+ g_object_unref (ges->priv->downloader_view);
+ }
+
+ if (ges->priv->favicon_cache)
+ {
+ g_object_unref (G_OBJECT (ges->priv->favicon_cache));
+ }
+
+ g_free (ges->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+EphyEmbedShell *
+ephy_embed_shell_new (const char *type)
+{
+ if (strcmp (type, "mozilla") == 0)
+ {
+ return EPHY_EMBED_SHELL (g_object_new
+ (MOZILLA_EMBED_SHELL_TYPE, NULL));
+ }
+
+ g_assert_not_reached ();
+ return NULL;
+}
+
+const char *supported_embeds [] = {
+#ifdef ENABLE_MOZILLA_EMBED
+ "mozilla",
+#endif
+#ifdef ENABLE_GTKHTML_EMBED
+ "gtkhtml",
+#endif
+ NULL };
+
+const char **
+ephy_embed_shell_get_supported (void)
+{
+ return supported_embeds;
+}
+
+/**
+ * ephy_embed_shell_get_favicon_cache:
+ * @gs: a #EphyShell
+ *
+ * Returns the favicons cache.
+ *
+ * Return value: the favicons cache
+ **/
+EphyFaviconCache *
+ephy_embed_shell_get_favicon_cache (EphyEmbedShell *ees)
+{
+ if (ees->priv->favicon_cache == NULL)
+ {
+ EphyHistory *history;
+
+ history = ephy_embed_shell_get_global_history (ees);
+ ees->priv->favicon_cache = ephy_favicon_cache_new (history);
+ }
+
+ return ees->priv->favicon_cache;
+}
+
+void
+ephy_embed_shell_add_embed (EphyEmbedShell *ges,
+ EphyEmbed *embed)
+{
+ ges->priv->embeds = g_list_append (ges->priv->embeds, embed);
+}
+
+void
+ephy_embed_shell_remove_embed (EphyEmbedShell *ges,
+ EphyEmbed *embed)
+{
+ ges->priv->embeds = g_list_remove (ges->priv->embeds, embed);
+}
+
+EphyEmbed *
+ephy_embed_shell_get_active_embed (EphyEmbedShell *ges)
+{
+ GList *list = ges->priv->embeds;
+
+ g_return_val_if_fail (ges->priv->embeds != NULL, NULL);
+
+ return EPHY_EMBED (list->data);
+}
+
+GList *
+ephy_embed_shell_get_embeds (EphyEmbedShell *ges)
+{
+ return ges->priv->embeds;
+}
+
+void
+ephy_embed_shell_get_capabilities (EphyEmbedShell *shell,
+ EmbedShellCapabilities *caps)
+{
+ EphyEmbedShellClass *klass = EPHY_EMBED_SHELL_GET_CLASS (shell);
+ return klass->get_capabilities (shell, caps);
+}
+
+EphyHistory *
+ephy_embed_shell_get_global_history (EphyEmbedShell *shell)
+{
+ EphyEmbedShellClass *klass = EPHY_EMBED_SHELL_GET_CLASS (shell);
+ return klass->get_global_history (shell);
+}
+
+DownloaderView *
+ephy_embed_shell_get_downloader_view (EphyEmbedShell *shell)
+{
+ EphyEmbedShellClass *klass = EPHY_EMBED_SHELL_GET_CLASS (shell);
+ return klass->get_downloader_view (shell);
+}
+
+gresult
+ephy_embed_shell_clear_cache (EphyEmbedShell *shell,
+ CacheType type)
+{
+ EphyEmbedShellClass *klass = EPHY_EMBED_SHELL_GET_CLASS (shell);
+ return klass->clear_cache (shell, type);
+}
+
+gresult
+ephy_embed_shell_set_offline_mode (EphyEmbedShell *shell,
+ gboolean offline)
+{
+ EphyEmbedShellClass *klass = EPHY_EMBED_SHELL_GET_CLASS (shell);
+ return klass->set_offline_mode (shell, offline);
+}
+
+gresult
+ephy_embed_shell_load_proxy_autoconf (EphyEmbedShell *shell,
+ const char* url)
+{
+ EphyEmbedShellClass *klass = EPHY_EMBED_SHELL_GET_CLASS (shell);
+ return klass->load_proxy_autoconf (shell, url);
+}
+
+gresult
+ephy_embed_shell_get_charset_titles (EphyEmbedShell *shell,
+ const char *group,
+ GList **charsets)
+{
+ EphyEmbedShellClass *klass = EPHY_EMBED_SHELL_GET_CLASS (shell);
+ return klass->get_charset_titles (shell, group, charsets);
+}
+
+gresult
+ephy_embed_shell_get_charset_groups (EphyEmbedShell *shell,
+ GList **groups)
+{
+ EphyEmbedShellClass *klass = EPHY_EMBED_SHELL_GET_CLASS (shell);
+ return klass->get_charset_groups (shell, groups);
+}
+
+gresult
+ephy_embed_shell_get_font_list (EphyEmbedShell *shell,
+ const char *langGroup,
+ const char *fontType,
+ GList **fontList,
+ char **default_font)
+{
+ EphyEmbedShellClass *klass = EPHY_EMBED_SHELL_GET_CLASS (shell);
+ return klass->get_font_list (shell, langGroup, fontType, fontList,
+ default_font);
+}
+
+gresult
+ephy_embed_shell_set_permission (EphyEmbedShell *shell,
+ const char *url,
+ PermissionType type,
+ gboolean allow)
+{
+ EphyEmbedShellClass *klass = EPHY_EMBED_SHELL_GET_CLASS (shell);
+ return klass->set_permission (shell, url, type, allow);
+}
+
+gresult
+ephy_embed_shell_list_permissions (EphyEmbedShell *shell,
+ PermissionType type,
+ GList **permissions)
+{
+ EphyEmbedShellClass *klass = EPHY_EMBED_SHELL_GET_CLASS (shell);
+ return klass->list_permissions (shell, type, permissions);
+}
+
+gresult
+ephy_embed_shell_remove_permissions (EphyEmbedShell *shell,
+ PermissionType type,
+ GList *permissions)
+{
+ EphyEmbedShellClass *klass = EPHY_EMBED_SHELL_GET_CLASS (shell);
+ return klass->remove_permissions (shell, type, permissions);
+}
+
+gresult
+ephy_embed_shell_list_cookies (EphyEmbedShell *shell,
+ GList **cookies)
+{
+ EphyEmbedShellClass *klass = EPHY_EMBED_SHELL_GET_CLASS (shell);
+ return klass->list_cookies (shell, cookies);
+}
+
+gresult
+ephy_embed_shell_remove_cookies (EphyEmbedShell *shell,
+ GList *cookies)
+{
+ EphyEmbedShellClass *klass = EPHY_EMBED_SHELL_GET_CLASS (shell);
+ return klass->remove_cookies (shell, cookies);
+}
+
+gresult
+ephy_embed_shell_list_passwords (EphyEmbedShell *shell,
+ PasswordType type,
+ GList **passwords)
+{
+ EphyEmbedShellClass *klass = EPHY_EMBED_SHELL_GET_CLASS (shell);
+ return klass->list_passwords (shell, type, passwords);
+}
+
+gresult
+ephy_embed_shell_remove_passwords (EphyEmbedShell *shell,
+ GList *passwords,
+ PasswordType type)
+{
+ EphyEmbedShellClass *klass = EPHY_EMBED_SHELL_GET_CLASS (shell);
+ return klass->remove_passwords (shell, passwords, type);
+}
+
+/**
+ * show_file_picker: Shows a file picker. Can be configured to select a
+ * file or a directory.
+ * @parentWidget: Parent Widget for file picker.
+ * @title: Title for file picker.
+ * @directory: Initial directory to start in.
+ * @file: Initial filename to show in filepicker.
+ * @mode: Mode to run filepicker in (modeOpen, modeSave, modeGetFolder)
+ * @ret_fullpath: On a successful return, will hold the full path to selected
+ * file or directory.
+ * @file_formats: an array of FileFormat structures to fill the format chooser
+ * optionmenu. NULL if not needed. The last item must have
+ * description == NULL.
+ * @ret_file_format: where to store the index of the format selected (can be
+ * NULL)
+ * returns: TRUE for success, FALSE for failure.
+ */
+
+gresult
+ephy_embed_shell_show_file_picker (EphyEmbedShell *shell,
+ GtkWidget *parentWidget,
+ const char *title,
+ const char *directory,
+ const char *file,
+ FilePickerMode mode,
+ char **ret_fullpath,
+ gboolean *ret_save_content,
+ FileFormat *file_formats,
+ int *ret_file_format)
+{
+ EphyEmbedShellClass *klass = EPHY_EMBED_SHELL_GET_CLASS (shell);
+ return klass->show_file_picker (shell, parentWidget, title,
+ directory, file, mode,
+ ret_fullpath, ret_save_content,
+ file_formats, ret_file_format);
+}
+
+static EphyHistory *
+impl_get_global_history (EphyEmbedShell *shell)
+{
+ if (!shell->priv->global_history)
+ {
+ shell->priv->global_history = ephy_history_new ();
+ }
+
+ return shell->priv->global_history;
+}
+
+static DownloaderView *
+impl_get_downloader_view (EphyEmbedShell *shell)
+{
+ if (!shell->priv->downloader_view)
+ {
+ shell->priv->downloader_view = downloader_view_new ();
+ g_object_add_weak_pointer
+ (G_OBJECT(shell->priv->downloader_view),
+ (gpointer *)&shell->priv->downloader_view);
+ }
+
+ return shell->priv->downloader_view;
+}
+
+gresult
+ephy_embed_shell_free_permissions (EphyEmbedShell *shell,
+ GList *permissions)
+{
+ GList *l;
+
+ for (l = permissions; l != NULL; l = l->next)
+ {
+ PermissionInfo *info = (PermissionInfo *)l->data;
+
+ g_free (info->type);
+ g_free (info->domain);
+ g_free (info);
+ }
+
+ g_list_free (permissions);
+
+ return G_OK;
+}
+
+gresult
+ephy_embed_shell_free_cookies (EphyEmbedShell *shell,
+ GList *cookies)
+{
+ GList *l;
+
+ for (l = cookies; l != NULL; l = l->next)
+ {
+ CookieInfo *info = (CookieInfo *)l->data;
+
+ g_free (info->base.type);
+ g_free (info->base.domain);
+ g_free (info->name);
+ g_free (info->value);
+ g_free (info->path);
+ g_free (info->secure);
+ g_free (info->expire);
+ g_free (info);
+ }
+
+ g_list_free (cookies);
+
+ return G_OK;
+}
+
+gresult
+ephy_embed_shell_free_passwords (EphyEmbedShell *shell,
+ GList *passwords)
+{
+ GList *l;
+
+ for (l = passwords; l != NULL; l = l->next)
+ {
+ PasswordInfo *info = (PasswordInfo *)l->data;
+ g_free (info->host);
+ g_free (info->username);
+ g_free (info);
+ }
+
+ g_list_free (passwords);
+
+ return G_OK;
+}
+
diff --git a/embed/ephy-embed-shell.h b/embed/ephy-embed-shell.h
new file mode 100644
index 000000000..3c3b11603
--- /dev/null
+++ b/embed/ephy-embed-shell.h
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EPHY_EMBED_SHELL_H
+#define EPHY_EMBED_SHELL_H
+
+#include "ephy-embed.h"
+#include "ephy-favicon-cache.h"
+#include "ephy-history.h"
+#include "downloader-view.h"
+
+#include <glib-object.h>
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef struct EphyEmbedShellClass EphyEmbedShellClass;
+
+#define EPHY_EMBED_SHELL_TYPE (ephy_embed_shell_get_type ())
+#define EPHY_EMBED_SHELL(obj) (GTK_CHECK_CAST ((obj), EPHY_EMBED_SHELL_TYPE, EphyEmbedShell))
+#define EPHY_EMBED_SHELL_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), EPHY_EMBED_SHELL_TYPE, EphyEmbedShellClass))
+#define IS_EPHY_EMBED_SHELL(obj) (GTK_CHECK_TYPE ((obj), EPHY_EMBED_SHELL_TYPE))
+#define IS_EPHY_EMBED_SHELL_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), EPHY_EMBED_SHELL))
+#define EPHY_EMBED_SHELL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EPHY_EMBED_SHELL_TYPE, EphyEmbedShellClass))
+
+typedef struct EphyEmbedShell EphyEmbedShell;
+typedef struct EphyEmbedShellPrivate EphyEmbedShellPrivate;
+
+extern EphyEmbedShell *embed_shell;
+
+/**
+ * FilePickerMode: What mode FilePicker should run in
+ */
+
+typedef enum
+{
+ modeOpen = 0,
+ modeSave = 1,
+ modeGetFolder =2
+} FilePickerMode;
+
+typedef struct
+{
+ /* description of the file format */
+ gchar *description;
+ /* tipical sufixes, NULL terminated */
+ gchar **extensions;
+} FileFormat;
+
+/**
+ * BlockedHost: a blocked host
+ */
+typedef struct
+{
+ gchar *type;
+ gchar *domain;
+} PermissionInfo;
+
+/**
+ * Cookie: the type of cookies
+ */
+typedef struct
+{
+ PermissionInfo base;
+ gchar *name;
+ gchar *value;
+ gchar *path;
+ gchar *secure;
+ gchar *expire;
+} CookieInfo;
+
+/**
+ * Password: a password manager entry
+ */
+typedef struct
+{
+ gchar *host;
+ gchar *username;
+} PasswordInfo;
+
+typedef struct
+{
+ const char *name;
+ const char *title;
+} CharsetInfo;
+
+/**
+ * PasswordType: To distinguish actual passwords from blocked password sites
+ */
+typedef enum
+{
+ PASSWORD_PASSWORD,
+ PASSWORD_REJECT
+} PasswordType;
+
+typedef enum
+{
+ COOKIES_PERMISSION,
+ IMAGES_PERMISSION
+} PermissionType;
+
+typedef enum
+{
+ DISK_CACHE = 2,
+ MEMORY_CACHE = 1
+} CacheType;
+
+typedef enum
+{
+ CACHE_CLEAR_CAP = 1 << 0,
+ OFFLINE_CAP = 1 << 1,
+ PROXY_AUTOCONF_CAP = 1 << 2,
+ JAVA_CONSOLE_CAP = 1 << 3,
+ JS_CONSOLE_CAP = 1 << 4,
+ CHARSETS_CAP = 1 << 5,
+ PERMISSIONS_CAP = 1 << 6,
+ COOKIES_CAP = 1 << 7,
+ PASSWORDS_CAP = 1 << 8,
+ FILEPICKER_CAP = 1 << 9
+} EmbedShellCapabilities;
+
+struct EphyEmbedShell
+{
+ GObject parent;
+ EphyEmbedShellPrivate *priv;
+};
+
+struct EphyEmbedShellClass
+{
+ GObjectClass parent_class;
+
+ void (* new_window) (EphyEmbedShell *shell,
+ EphyEmbed **new_embed,
+ EmbedChromeMask chromemask);
+
+ /* Methods */
+
+ void (* get_capabilities) (EphyEmbedShell *shell,
+ EmbedShellCapabilities *caps);
+ EphyHistory * (* get_global_history) (EphyEmbedShell *shell);
+ DownloaderView* (* get_downloader_view) (EphyEmbedShell *shell);
+ gresult (* clear_cache) (EphyEmbedShell *shell,
+ CacheType type);
+ gresult (* set_offline_mode) (EphyEmbedShell *shell,
+ gboolean offline);
+ gresult (* load_proxy_autoconf) (EphyEmbedShell *shell,
+ const char* url);
+ gresult (* show_java_console) (EphyEmbedShell *shell);
+ gresult (* show_js_console) (EphyEmbedShell *shell);
+ gresult (* get_charset_groups) (EphyEmbedShell *shell,
+ GList **groups);
+ gresult (* get_charset_titles) (EphyEmbedShell *shell,
+ const char *group,
+ GList **charsets);
+ gresult (* get_font_list) (EphyEmbedShell *shell,
+ const char *langGroup,
+ const char *fontType,
+ GList **fontList,
+ char **default_font);
+ gresult (* set_permission) (EphyEmbedShell *shell,
+ const char *url,
+ PermissionType type,
+ gboolean allow);
+ gresult (* list_permissions) (EphyEmbedShell *shell,
+ PermissionType type,
+ GList **permissions);
+ gresult (* remove_permissions) (EphyEmbedShell *shell,
+ PermissionType type,
+ GList *permissions);
+ gresult (* list_cookies) (EphyEmbedShell *shell,
+ GList **cokies);
+ gresult (* remove_cookies) (EphyEmbedShell *shell,
+ GList *cookies);
+ gresult (* list_passwords) (EphyEmbedShell *shell,
+ PasswordType type,
+ GList **passwords);
+ gresult (* remove_passwords) (EphyEmbedShell *shell,
+ GList *passwords,
+ PasswordType type);
+ gresult (* show_file_picker) (EphyEmbedShell *shell,
+ GtkWidget *parentWidget,
+ const char* title,
+ const char* directory,
+ const char* file,
+ FilePickerMode mode,
+ char **ret_fullpath,
+ gboolean *ret_save_content,
+ FileFormat *file_formats,
+ gint *ret_file_format);
+};
+
+GType ephy_embed_shell_get_type (void);
+
+EphyEmbedShell *ephy_embed_shell_new (const char *type);
+
+EphyFaviconCache *ephy_embed_shell_get_favicon_cache (EphyEmbedShell *ges);
+
+void ephy_embed_shell_add_embed (EphyEmbedShell *ges,
+ EphyEmbed *embed);
+
+void ephy_embed_shell_remove_embed (EphyEmbedShell *ges,
+ EphyEmbed *embed);
+
+EphyEmbed *ephy_embed_shell_get_active_embed (EphyEmbedShell *ges);
+
+GList *ephy_embed_shell_get_embeds (EphyEmbedShell *ges);
+
+const char **ephy_embed_shell_get_supported (void);
+
+void ephy_embed_shell_get_capabilities (EphyEmbedShell *shell,
+ EmbedShellCapabilities *caps);
+
+EphyHistory *ephy_embed_shell_get_global_history (EphyEmbedShell *shell);
+
+DownloaderView *ephy_embed_shell_get_downloader_view (EphyEmbedShell *shell);
+
+gresult ephy_embed_shell_clear_cache (EphyEmbedShell *shell,
+ CacheType type);
+
+gresult ephy_embed_shell_set_offline_mode (EphyEmbedShell *shell,
+ gboolean offline);
+
+gresult ephy_embed_shell_load_proxy_autoconf (EphyEmbedShell *shell,
+ const char* url);
+
+/* Charsets */
+gresult ephy_embed_shell_get_charset_groups (EphyEmbedShell *shell,
+ GList **groups);
+
+gresult ephy_embed_shell_get_charset_titles (EphyEmbedShell *shell,
+ const char *group,
+ GList **charsets);
+
+gresult ephy_embed_shell_get_font_list (EphyEmbedShell *shell,
+ const char *langGroup,
+ const char *fontType,
+ GList **fontList,
+ char **default_font);
+
+/* Permissions */
+gresult ephy_embed_shell_set_permission (EphyEmbedShell *shell,
+ const char *url,
+ PermissionType type,
+ gboolean allow);
+
+gresult ephy_embed_shell_list_permissions (EphyEmbedShell *shell,
+ PermissionType type,
+ GList **permissions);
+
+gresult ephy_embed_shell_free_permissions (EphyEmbedShell *shell,
+ GList *permissions);
+
+gresult ephy_embed_shell_remove_permissions (EphyEmbedShell *shell,
+ PermissionType type,
+ GList *permissions);
+
+/* Cookies */
+gresult ephy_embed_shell_list_cookies (EphyEmbedShell *shell,
+ GList **cookies);
+
+gresult ephy_embed_shell_remove_cookies (EphyEmbedShell *shell,
+ GList *cookies);
+
+gresult ephy_embed_shell_free_cookies (EphyEmbedShell *shell,
+ GList *cookies);
+
+/* Passwords */
+gresult ephy_embed_shell_list_passwords (EphyEmbedShell *shell,
+ PasswordType type,
+ GList **passwords);
+
+gresult ephy_embed_shell_free_passwords (EphyEmbedShell *shell,
+ GList *passwords);
+
+gresult ephy_embed_shell_remove_passwords (EphyEmbedShell *shell,
+ GList *passwords,
+ PasswordType type);
+
+gresult ephy_embed_shell_show_file_picker (EphyEmbedShell *shell,
+ GtkWidget *parentWidget,
+ const char *title,
+ const char *directory,
+ const char *file,
+ FilePickerMode mode,
+ char **ret_fullpath,
+ gboolean *ret_save_content,
+ FileFormat *file_formats,
+ int *ret_file_format);
+
+G_END_DECLS
+
+#endif
diff --git a/embed/ephy-embed-types.h b/embed/ephy-embed-types.h
new file mode 100644
index 000000000..adf32cc6f
--- /dev/null
+++ b/embed/ephy-embed-types.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GALEON_EMBED_TYPES_H
+#define GALEON_EMBED_TYPES_H
+
+#include "ephy-types.h"
+
+G_BEGIN_DECLS
+
+typedef enum
+{
+ EMBED_CHROME_NONE = 0,
+ EMBED_CHROME_DEFAULT = 1 << 0,
+ EMBED_CHROME_MENUBARON = 1 << 1,
+ EMBED_CHROME_TOOLBARON = 1 << 2,
+ EMBED_CHROME_PERSONALTOOLBARON = 1 << 3,
+ EMBED_CHROME_STATUSBARON = 1 << 4,
+ EMBED_CHROME_WINDOWRAISED = 1 << 5,
+ EMBED_CHROME_WINDOWLOWERED = 1 << 6,
+ EMBED_CHROME_CENTERSCREEN = 1 << 7,
+ EMBED_CHROME_OPENASDIALOG = 1 << 8,
+ EMBED_CHROME_OPENASCHROME = 1 << 9,
+ EMBED_CHROME_OPENASPOPUP = 1 << 10,
+ EMBED_CHROME_OPENASFULLSCREEN = 1 << 11,
+ EMBED_CHROME_PPVIEWTOOLBARON = 1 << 12,
+ EMBED_CHROME_SIDEBARON = 1 << 13
+} EmbedChromeMask;
+
+G_END_DECLS
+
+#endif
diff --git a/embed/ephy-embed-utils.c b/embed/ephy-embed-utils.c
new file mode 100644
index 000000000..0d94e5374
--- /dev/null
+++ b/embed/ephy-embed-utils.c
@@ -0,0 +1,321 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "eel-gconf-extensions.h"
+#include "ephy-embed-utils.h"
+#include "ephy-embed-shell.h"
+#include "ephy-bonobo-extensions.h"
+#include "ephy-gui.h"
+
+#include <gtk/gtkdialog.h>
+#include <gtk/gtkmessagedialog.h>
+#include <bonobo/bonobo-i18n.h>
+#include <bonobo/bonobo-ui-util.h>
+#include <libgnomevfs/gnome-vfs-uri.h>
+#include <string.h>
+
+/**
+ * ephy_embed_utils_save:
+ * @window: the referrer window. Used to parent the dialogs.
+ * @default_dir_pref: the gconf path to persist the directory selected by the user.
+ * @ask_dest: ask the user the destination path
+ * @ask_content: show the user an option to save the content
+ * of the web page (images, javascript...)
+ * @persist: the #GaleonEmbedPersist referring to the url
+ *
+ * Download a save an url asking a location to the user when requested
+ **/
+void
+ephy_embed_utils_save (GtkWidget *window,
+ const char *default_dir_pref,
+ gboolean ask_dest, gboolean ask_content,
+ EphyEmbedPersist *persist)
+{
+ GnomeVFSURI *uri;
+ char *retPath = NULL;
+ char *fileName = NULL;
+ char *dirName = NULL;
+ char *retDir;
+ char *target;
+ const char *source;
+ gresult ret;
+ EphyEmbed *embed;
+ EmbedPersistFlags flags;
+ gboolean content;
+
+ g_object_ref (G_OBJECT(persist));
+
+ ephy_embed_persist_get_flags (persist, &flags);
+
+ ephy_embed_persist_get_source (persist, &source);
+
+ if (source)
+ {
+ target = g_strdup (source);
+ }
+ else
+ {
+ ephy_embed_persist_get_embed (persist, &embed);
+ g_return_if_fail (embed != NULL);
+
+ ephy_embed_get_location (embed,
+ flags &
+ EMBED_PERSIST_MAINDOC,
+ FALSE,
+ &target);
+ }
+
+ /* Get a filename from the target url */
+ uri = gnome_vfs_uri_new (target);
+ if (uri)
+ {
+ fileName = gnome_vfs_uri_extract_short_name (uri);
+ gnome_vfs_uri_unref (uri);
+ }
+
+ dirName = eel_gconf_get_string (default_dir_pref);
+ if (dirName && dirName[0] == '\0')
+ {
+ g_free (dirName);
+ dirName = NULL;
+ }
+
+ if (!dirName || strcmp (dirName,"~") == 0)
+ {
+ g_free (dirName);
+ dirName = g_strdup(g_get_home_dir ());
+ }
+
+ /* If we aren't asking for downloading dir, check that we aren't
+ * overwriting anything. If we are, pop up a warning dialog and show
+ * the filepicker if the user doesn't want to overwrite the file.
+ */
+ ret = G_FAILED;
+ if (!ask_dest)
+ {
+ retPath = g_build_filename (dirName, fileName, NULL);
+ if (ephy_gui_confirm_overwrite_file (window, retPath))
+ {
+ ret = G_OK;
+ }
+ else
+ {
+ g_free (retPath);
+ ask_dest = TRUE;
+ }
+ }
+
+ if (ask_dest)
+ {
+ /* show the file picker */
+ ret = ephy_embed_shell_show_file_picker
+ (embed_shell, window,
+ _("Select the destination filename"),
+ dirName, fileName, modeSave, &retPath,
+ ask_content ? &content : NULL,
+ NULL, NULL);
+ }
+
+ if (ret == G_OK)
+ {
+ uri = gnome_vfs_uri_new (retPath);
+ g_return_if_fail (uri != NULL);
+
+ retDir = gnome_vfs_uri_extract_dirname (uri);
+
+ if (ask_content && content)
+ {
+ flags |= EMBED_PERSIST_SAVE_CONTENT;
+ ephy_embed_persist_set_flags (persist,
+ flags);
+ }
+
+ ephy_embed_persist_set_dest (persist, retPath);
+
+ ephy_embed_persist_save (persist);
+
+ /* set default save dir */
+ eel_gconf_set_string (default_dir_pref,
+ retDir);
+
+ g_free (retDir);
+ gnome_vfs_uri_unref (uri);
+ }
+
+ g_object_unref (G_OBJECT(persist));
+
+ g_free (dirName);
+ g_free (fileName);
+ g_free (retPath);
+}
+
+static void
+build_group (GString *xml_string, const char *group, int index)
+{
+ char *tmp;
+
+ tmp = g_strdup_printf ("<submenu label=\"%s\" name=\"CharsetGroup%d\">\n",
+ group, index);
+ xml_string = g_string_append (xml_string, tmp);
+ g_free (tmp);
+}
+
+static void
+build_charset (GString *xml_string, CharsetInfo *info, int index)
+{
+ char *tmp;
+ char *verb;
+
+ verb = g_strdup_printf ("Charset%d", index);
+ tmp = g_strdup_printf ("<menuitem label=\"%s\" name=\"%s\" verb=\"%s\"/>\n",
+ info->title, verb, verb);
+ xml_string = g_string_append (xml_string, tmp);
+
+ g_free (tmp);
+ g_free (verb);
+}
+
+static void
+add_verbs (BonoboUIComponent *ui_component,
+ BonoboUIVerbFn fn, GList *verbs)
+{
+ GList *l;
+ char verb[15];
+ int charset_index = 0;
+
+ for (l = verbs; l != NULL; l = l->next)
+ {
+ EncodingMenuData *edata = (EncodingMenuData *)l->data;
+
+ sprintf (verb, "Charset%d", charset_index);
+ charset_index++;
+ bonobo_ui_component_add_verb_full
+ (ui_component, verb,
+ g_cclosure_new (G_CALLBACK (fn), edata,
+ (GClosureNotify)g_free));
+ }
+}
+
+/**
+ * ephy_embed_utils_build_charsets_submenu:
+ * @ui_component: the parent #BonoboUIComponent
+ * @path: the bonoboui path where to create the submenu.
+ * It's recommended to use a <placeholder/>
+ * @fn: callback to report the selected charsets
+ * @data: the data passed to the callback
+ *
+ * Create a charset submenu using bonobo ui.
+ **/
+void
+ephy_embed_utils_build_charsets_submenu (BonoboUIComponent *ui_component,
+ const char *path,
+ BonoboUIVerbFn fn,
+ gpointer data)
+{
+ GList *groups;
+ GString *xml_string;
+ GList *verbs = NULL;
+ int group_index = 0;
+ int charset_index = 0;
+
+#ifdef DEBUG_MARCO
+ GTimer *timer;
+ gulong s;
+
+ timer = g_timer_new ();
+ g_timer_start(timer);
+#endif
+
+ g_return_if_fail (ephy_embed_shell_get_charset_groups (embed_shell, &groups) == G_OK);
+
+ xml_string = g_string_new (NULL);
+ g_string_append (xml_string, "<submenu name=\"Encoding\" _label=\"_Encoding\">");
+
+ for (; groups != NULL; groups = groups->next)
+ {
+ GList *charsets;
+ const char *group = (const char *)groups->data;
+
+ build_group (xml_string, group, group_index);
+
+ ephy_embed_shell_get_charset_titles (embed_shell,
+ group,
+ &charsets);
+
+ for (; charsets != NULL; charsets = charsets->next)
+ {
+ CharsetInfo *info = (CharsetInfo *) charsets->data;
+ EncodingMenuData *edata;
+
+ edata = g_new0 (EncodingMenuData, 1);
+ edata->encoding = info->name;
+ edata->data = data;
+ verbs = g_list_append (verbs, edata);
+
+ build_charset (xml_string, info, charset_index);
+ charset_index++;
+ }
+
+
+ g_list_free (charsets);
+ g_string_append (xml_string, "</submenu>");
+ group_index++;
+ }
+
+ g_string_append (xml_string, "</submenu>");
+
+ bonobo_ui_component_set_translate (ui_component, path,
+ xml_string->str, NULL);
+ add_verbs (ui_component, fn, verbs);
+
+ g_list_free (verbs);
+ g_list_free (groups);
+ g_string_free (xml_string, TRUE);
+
+#ifdef DEBUG_MARCO
+ g_timer_stop (timer);
+ g_timer_elapsed (timer, &s);
+ g_print ("Time to build charset menu: %f\n", (double)(s)/1000000);
+#endif
+}
+
+/**
+ * ephy_embed_utils_handlernotfound_dialog_run:
+ * @parent: the dialog parent window
+ *
+ * Show a dialog to warn the user that no application capable
+ * to open the specified file are found. Used in the downloader
+ * and in the mime type dialog.
+ **/
+void
+ephy_embed_utils_nohandler_dialog_run (GtkWidget *parent)
+{
+ GtkWidget *dialog;
+
+ /* FIXME mime db shortcut */
+
+ dialog = gtk_message_dialog_new
+ (GTK_WINDOW(parent),
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ _("No available applications to open "
+ "the specified file."));
+ gtk_dialog_run (GTK_DIALOG(dialog));
+ gtk_widget_destroy (dialog);
+}
diff --git a/embed/ephy-embed-utils.h b/embed/ephy-embed-utils.h
new file mode 100644
index 000000000..19f7b72f1
--- /dev/null
+++ b/embed/ephy-embed-utils.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EPHY_EMBED_UTILS_H
+#define EPHY_EMBED_UTILS_H
+
+#include "ephy-embed-persist.h"
+
+#include <gtk/gtkwidget.h>
+#include <bonobo/bonobo-ui-component.h>
+
+G_BEGIN_DECLS
+
+typedef struct
+{
+ const char *encoding;
+ gpointer data;
+} EncodingMenuData;
+
+void ephy_embed_utils_save (GtkWidget *window,
+ const char *default_dir_pref,
+ gboolean ask_dest,
+ gboolean ask_content,
+ EphyEmbedPersist *persist);
+
+void ephy_embed_utils_build_charsets_submenu (BonoboUIComponent *ui_component,
+ const char *path,
+ BonoboUIVerbFn fn,
+ gpointer data);
+
+void ephy_embed_utils_nohandler_dialog_run (GtkWidget *parent);
+
+G_END_DECLS
+
+#endif
diff --git a/embed/ephy-embed.c b/embed/ephy-embed.c
new file mode 100644
index 000000000..cb513f95c
--- /dev/null
+++ b/embed/ephy-embed.c
@@ -0,0 +1,608 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "ephy-marshal.h"
+#include "ephy-embed.h"
+
+#include "mozilla-embed.h"
+#include "mozilla-embed-shell.h"
+
+enum
+{
+ NEW_WINDOW,
+ LINK_MESSAGE,
+ FAVICON,
+ JS_STATUS,
+ LOCATION,
+ TITLE,
+ PROGRESS,
+ NET_STATE,
+ VISIBILITY,
+ DESTROY_BRSR,
+ OPEN_URI,
+ SIZE_TO,
+ DOM_MOUSE_CLICK,
+ DOM_MOUSE_DOWN,
+ SECURITY_CHANGE,
+ ZOOM_CHANGE,
+ LAST_SIGNAL
+};
+
+static void
+ephy_embed_base_init (gpointer base_class);
+
+struct EphyEmbedPrivate
+{
+ gpointer dummy;
+};
+
+static guint ephy_embed_signals[LAST_SIGNAL] = { 0 };
+
+GType
+ephy_embed_get_type (void)
+{
+ static GType ephy_embed_type = 0;
+
+ if (ephy_embed_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (EphyEmbedClass),
+ ephy_embed_base_init,
+ NULL,
+ };
+
+ ephy_embed_type = g_type_register_static (G_TYPE_INTERFACE,
+ "EphyEmbed",
+ &our_info,
+ (GTypeFlags)0);
+ }
+
+ return ephy_embed_type;
+}
+
+static void
+ephy_embed_base_init (gpointer g_class)
+{
+ static gboolean initialized = FALSE;
+
+ if (! initialized)
+ {
+ ephy_embed_signals[NEW_WINDOW] =
+ g_signal_new ("ge_new_window",
+ EPHY_EMBED_TYPE,
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (EphyEmbedClass, new_window),
+ NULL, NULL,
+ ephy_marshal_VOID__POINTER_INT,
+ G_TYPE_NONE,
+ 2,
+ G_TYPE_POINTER,
+ G_TYPE_INT);
+ ephy_embed_signals[LINK_MESSAGE] =
+ g_signal_new ("ge_link_message",
+ EPHY_EMBED_TYPE,
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (EphyEmbedClass, link_message),
+ NULL, NULL,
+ ephy_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_STRING);
+ ephy_embed_signals[FAVICON] =
+ g_signal_new ("ge_favicon",
+ EPHY_EMBED_TYPE,
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (EphyEmbedClass, favicon),
+ NULL, NULL,
+ ephy_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_STRING);
+ ephy_embed_signals[JS_STATUS] =
+ g_signal_new ("ge_js_status",
+ EPHY_EMBED_TYPE,
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (EphyEmbedClass, js_status),
+ NULL, NULL,
+ ephy_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_STRING);
+ ephy_embed_signals[LOCATION] =
+ g_signal_new ("ge_location",
+ EPHY_EMBED_TYPE,
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (EphyEmbedClass, location),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+ ephy_embed_signals[TITLE] =
+ g_signal_new ("ge_title",
+ EPHY_EMBED_TYPE,
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (EphyEmbedClass, title),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+ ephy_embed_signals[PROGRESS] =
+ g_signal_new ("ge_progress",
+ EPHY_EMBED_TYPE,
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (EphyEmbedClass, progress),
+ NULL, NULL,
+ ephy_marshal_VOID__STRING_INT_INT,
+ G_TYPE_NONE,
+ 3,
+ G_TYPE_STRING,
+ G_TYPE_INT,
+ G_TYPE_INT);
+ ephy_embed_signals[NET_STATE] =
+ g_signal_new ("ge_net_state",
+ EPHY_EMBED_TYPE,
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (EphyEmbedClass, net_state),
+ NULL, NULL,
+ ephy_marshal_VOID__STRING_INT,
+ G_TYPE_NONE,
+ 2,
+ G_TYPE_STRING,
+ G_TYPE_INT);
+ ephy_embed_signals[VISIBILITY] =
+ g_signal_new ("ge_visibility",
+ EPHY_EMBED_TYPE,
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (EphyEmbedClass, visibility),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__BOOLEAN,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_BOOLEAN);
+ ephy_embed_signals[DESTROY_BRSR] =
+ g_signal_new ("ge_destroy_brsr",
+ EPHY_EMBED_TYPE,
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (EphyEmbedClass, destroy_brsr),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+ ephy_embed_signals[OPEN_URI] =
+ g_signal_new ("ge_open_uri",
+ EPHY_EMBED_TYPE,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EphyEmbedClass, open_uri),
+ NULL, NULL,
+ ephy_marshal_INT__STRING,
+ G_TYPE_INT,
+ 1,
+ G_TYPE_STRING);
+ ephy_embed_signals[SIZE_TO] =
+ g_signal_new ("ge_size_to",
+ EPHY_EMBED_TYPE,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EphyEmbedClass, size_to),
+ NULL, NULL,
+ ephy_marshal_VOID__INT_INT,
+ G_TYPE_NONE,
+ 2,
+ G_TYPE_INT,
+ G_TYPE_INT);
+ ephy_embed_signals[DOM_MOUSE_DOWN] =
+ g_signal_new ("ge_dom_mouse_down",
+ EPHY_EMBED_TYPE,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EphyEmbedClass, dom_mouse_down),
+ NULL, NULL,
+ ephy_marshal_INT__OBJECT,
+ G_TYPE_INT,
+ 1,
+ G_TYPE_POINTER);
+ ephy_embed_signals[DOM_MOUSE_CLICK] =
+ g_signal_new ("ge_dom_mouse_click",
+ EPHY_EMBED_TYPE,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EphyEmbedClass, dom_mouse_click),
+ NULL, NULL,
+ ephy_marshal_INT__OBJECT,
+ G_TYPE_INT,
+ 1,
+ G_TYPE_POINTER);
+ ephy_embed_signals[SECURITY_CHANGE] =
+ g_signal_new ("ge_security_change",
+ EPHY_EMBED_TYPE,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EphyEmbedClass, security_change),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__INT,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_INT);
+ ephy_embed_signals[ZOOM_CHANGE] =
+ g_signal_new ("ge_zoom_change",
+ EPHY_EMBED_TYPE,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EphyEmbedClass, zoom_change),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__INT,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_INT);
+ }
+}
+
+EphyEmbed *
+ephy_embed_new (GObject *shell)
+{
+ if (IS_MOZILLA_EMBED_SHELL (shell))
+ {
+ return EPHY_EMBED (g_object_new
+ (MOZILLA_EMBED_TYPE, NULL));
+ }
+
+ g_assert_not_reached ();
+
+ return NULL;
+}
+
+void
+ephy_embed_get_capabilities (EphyEmbed *embed,
+ EmbedCapabilities *caps)
+{
+ EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed);
+ klass->get_capabilities (embed, caps);
+}
+
+gresult
+ephy_embed_load_url (EphyEmbed *embed,
+ const char *url)
+{
+ EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed);
+ return klass->load_url (embed, url);
+}
+
+gresult
+ephy_embed_stop_load (EphyEmbed *embed)
+{
+ EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed);
+ return klass->stop_load (embed);
+}
+
+gresult
+ephy_embed_can_go_back (EphyEmbed *embed)
+{
+ EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed);
+ return klass->can_go_back (embed);
+}
+
+gresult
+ephy_embed_can_go_forward (EphyEmbed *embed)
+{
+ EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed);
+ return klass->can_go_forward (embed);
+}
+
+gresult
+ephy_embed_can_go_up (EphyEmbed *embed)
+{
+ EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed);
+ return klass->can_go_up (embed);
+}
+
+gresult
+ephy_embed_get_go_up_list (EphyEmbed *embed, GSList **l)
+{
+ EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed);
+ return klass->get_go_up_list (embed, l);
+}
+
+gresult
+ephy_embed_go_back (EphyEmbed *embed)
+{
+ EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed);
+ return klass->go_back (embed);
+}
+
+gresult
+ephy_embed_go_forward (EphyEmbed *embed)
+{
+ EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed);
+ return klass->go_forward (embed);
+}
+
+gresult
+ephy_embed_go_up (EphyEmbed *embed)
+{
+ EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed);
+ return klass->go_up (embed);
+}
+
+gresult
+ephy_embed_render_data (EphyEmbed *embed,
+ const char *data,
+ guint32 len,
+ const char *base_uri,
+ const char *mime_type)
+{
+ EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed);
+ return klass->render_data (embed, data, len, base_uri, mime_type);
+}
+
+gresult
+ephy_embed_open_stream (EphyEmbed *embed,
+ const char *base_uri,
+ const char *mime_type)
+{
+ EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed);
+ return klass->open_stream (embed, base_uri, mime_type);
+}
+
+gresult
+ephy_embed_append_data (EphyEmbed *embed,
+ const char *data,
+ guint32 len)
+{
+ EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed);
+ return klass->append_data (embed, data, len);
+}
+
+gresult
+ephy_embed_close_stream (EphyEmbed *embed)
+{
+ EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed);
+ return klass->close_stream (embed);
+}
+
+gresult
+ephy_embed_get_title (EphyEmbed *embed,
+ char **title)
+{
+ EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed);
+ return klass->get_title (embed, title);
+}
+
+gresult
+ephy_embed_get_location (EphyEmbed *embed,
+ gboolean toplevel,
+ gboolean requested,
+ char **location)
+{
+ EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed);
+ return klass->get_location (embed, toplevel, requested, location);
+}
+
+gresult
+ephy_embed_reload (EphyEmbed *embed,
+ EmbedReloadFlags flags)
+{
+ EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed);
+ return klass->reload (embed, flags);
+}
+
+gresult
+ephy_embed_copy_page (EphyEmbed *dest,
+ EphyEmbed *source,
+ EmbedDisplayType display_type)
+{
+ EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (dest);
+ return klass->copy_page (dest, source, display_type);
+}
+
+gresult
+ephy_embed_grab_focus (EphyEmbed *embed)
+{
+ EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed);
+ return klass->grab_focus (embed);
+}
+
+gresult
+ephy_embed_get_link_tags (EphyEmbed *embed,
+ const char *link_type,
+ GList **tags)
+{
+ EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed);
+ return klass->get_link_tags (embed, link_type, tags);
+}
+
+gresult
+ephy_embed_zoom_set (EphyEmbed *embed,
+ int zoom,
+ gboolean reflow)
+{
+ EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed);
+ return klass->zoom_set (embed, zoom, reflow);
+}
+
+gresult
+ephy_embed_zoom_get (EphyEmbed *embed,
+ int *zoom)
+{
+ EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed);
+ return klass->zoom_get (embed, zoom);
+}
+
+gresult
+ephy_embed_selection_can_cut (EphyEmbed *embed)
+{
+ EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed);
+ return klass->selection_can_cut (embed);
+}
+
+gresult
+ephy_embed_selection_can_copy (EphyEmbed *embed)
+{
+ EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed);
+ return klass->selection_can_copy (embed);
+}
+
+gresult
+ephy_embed_can_paste (EphyEmbed *embed)
+{
+ EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed);
+ return klass->can_paste (embed);
+}
+
+gresult
+ephy_embed_select_all (EphyEmbed *embed)
+{
+ EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed);
+ return klass->select_all (embed);
+}
+
+gresult
+ephy_embed_selection_cut (EphyEmbed *embed)
+{
+ EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed);
+ return klass->selection_cut (embed);
+}
+
+gresult
+ephy_embed_selection_copy (EphyEmbed *embed)
+{
+ EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed);
+ return klass->selection_copy (embed);
+}
+
+gresult
+ephy_embed_paste (EphyEmbed *embed)
+{
+ EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed);
+ return klass->paste (embed);
+}
+
+gresult
+ephy_embed_shistory_count (EphyEmbed *embed,
+ int *count)
+{
+ EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed);
+ return klass->shistory_count (embed, count);
+}
+
+gresult
+ephy_embed_shistory_get_nth (EphyEmbed *embed,
+ int nth,
+ gboolean is_relative,
+ char **url,
+ char **title)
+{
+ EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed);
+ return klass->shistory_get_nth (embed, nth, is_relative, url, title);
+}
+
+gresult
+ephy_embed_shistory_get_pos (EphyEmbed *embed,
+ int *pos)
+{
+ EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed);
+ return klass->shistory_get_pos (embed, pos);
+}
+
+gresult
+ephy_embed_shistory_go_nth (EphyEmbed *embed,
+ int nth)
+{
+ EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed);
+ return klass->shistory_go_nth (embed, nth);
+}
+
+gboolean
+ephy_embed_shistory_copy (EphyEmbed *source,
+ EphyEmbed *dest)
+{
+ EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (source);
+ return klass->shistory_copy (source, dest);
+}
+
+gresult
+ephy_embed_scroll (EphyEmbed *embed,
+ EmbedScrollDirection direction)
+{
+ EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed);
+ return klass->scroll (embed, direction);
+}
+
+gresult
+ephy_embed_fine_scroll (EphyEmbed *embed,
+ int horiz, int vert)
+{
+ EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed);
+ return klass->fine_scroll (embed, horiz, vert);
+}
+
+gresult
+ephy_embed_get_security_level (EphyEmbed *embed,
+ EmbedSecurityLevel *level,
+ char **description)
+{
+ EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed);
+ return klass->get_security_level (embed, level, description);
+}
+
+gresult
+ephy_embed_find (EphyEmbed *embed,
+ EmbedFindInfo *info)
+{
+ EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed);
+ return klass->find (embed, info);
+}
+
+gresult
+ephy_embed_set_charset (EphyEmbed *embed,
+ const char *charset)
+{
+ EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed);
+ return klass->set_charset (embed, charset);
+}
+
+gresult
+ephy_embed_print (EphyEmbed *embed,
+ EmbedPrintInfo *info)
+{
+ EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed);
+ return klass->print (embed, info);
+}
+
+gresult
+ephy_embed_print_preview_close (EphyEmbed *embed)
+{
+ EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed);
+ return klass->print_preview_close (embed);
+}
+
+gresult
+ephy_embed_print_preview_num_pages (EphyEmbed *embed, gint *retNum)
+{
+ EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed);
+ return klass->print_preview_num_pages (embed, retNum);
+}
+
+gresult
+ephy_embed_print_preview_navigate (EphyEmbed *embed,
+ EmbedPrintPreviewNavType navType,
+ gint pageNum)
+{
+ EphyEmbedClass *klass = EPHY_EMBED_GET_CLASS (embed);
+ return klass->print_preview_navigate (embed, navType, pageNum);
+}
+
diff --git a/embed/ephy-embed.h b/embed/ephy-embed.h
new file mode 100644
index 000000000..1de35d7aa
--- /dev/null
+++ b/embed/ephy-embed.h
@@ -0,0 +1,443 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EPHY_EMBED_H
+#define EPHY_EMBED_H
+
+#include "ephy-embed-types.h"
+#include "ephy-embed-event.h"
+
+#include <glib-object.h>
+#include <glib.h>
+#include <gtk/gtkwidget.h>
+
+G_BEGIN_DECLS
+
+typedef struct EphyEmbedClass EphyEmbedClass;
+
+#define EPHY_EMBED_TYPE (ephy_embed_get_type ())
+#define EPHY_EMBED(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EPHY_EMBED_TYPE, EphyEmbed))
+#define EPHY_EMBED_CLASS(vtable) (G_TYPE_CHECK_CLASS_CAST ((vtable), EPHY_EMBED_TYPE, EphyEmbedClass))
+#define IS_EPHY_EMBED(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EPHY_EMBED_TYPE))
+#define IS_EPHY_EMBED_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), EPHY_EMBED_TYPE))
+#define EPHY_EMBED_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), EPHY_EMBED_TYPE, EphyEmbedClass))
+
+typedef struct _EphyEmbed EphyEmbed;
+
+typedef enum
+{
+ EMBED_STATE_UNKNOWN = 0,
+ EMBED_STATE_START = 1 << 0,
+ EMBED_STATE_REDIRECTING = 1 << 1,
+ EMBED_STATE_TRANSFERRING = 1 << 2,
+ EMBED_STATE_NEGOTIATING = 1 << 3,
+ EMBED_STATE_STOP = 1 << 4,
+
+ EMBED_STATE_IS_REQUEST = 1 << 5,
+ EMBED_STATE_IS_DOCUMENT = 1 << 6,
+ EMBED_STATE_IS_NETWORK = 1 << 7,
+ EMBED_STATE_IS_WINDOW = 1 << 8
+} EmbedState;
+
+typedef enum
+{
+ EMBED_CLIPBOARD_CAP = 1 << 0,
+ EMBED_COOKIES_CAP = 1 << 1,
+ EMBED_LINKS_CAP = 1 << 2,
+ EMBED_ZOOM_CAP = 1 << 3,
+ EMBED_PRINT_CAP = 1 << 6,
+ EMBED_FIND_CAP = 1 << 7,
+ EMBED_SCROLL_CAP = 1 << 8,
+ EMBED_SECURITY_CAP = 1 << 9,
+ EMBED_CHARSET_CAP = 1 << 10,
+ EMBED_SHISTORY_CAP = 1 << 11,
+ EMBED_FINE_SCROLL_CAP = 1 << 12
+} EmbedCapabilities;
+
+typedef struct
+{
+ char *modification_date;
+
+ /* lists of hashtables with gvalues */
+ GList *images; /* url, alt, title, width, height */
+ GList *forms; /* action, type */
+ GList *links; /* url, title, type */
+ GList *stylesheets; /* url, title */
+} EmbedPageInfo;
+
+typedef enum
+{
+ EMBED_RELOAD_NORMAL = 1 << 1,
+ EMBED_RELOAD_BYPASSCACHE = 1 << 2,
+ EMBED_RELOAD_BYPASSPROXY = 1 << 3
+} EmbedReloadFlags;
+
+typedef enum
+{
+ DISPLAY_AS_SOURCE = 1U,
+ DISPLAY_NORMAL = 2U
+} EmbedDisplayType;
+
+typedef struct
+{
+ gchar *search_string;
+ gboolean backwards;
+ gboolean wrap;
+ gboolean entire_word;
+ gboolean match_case;
+ gboolean search_frames;
+ gboolean interactive;
+} EmbedFindInfo;
+
+typedef struct
+{
+ gboolean print_to_file;
+ gchar *printer;
+ gchar *file;
+ gint paper;
+ gdouble top_margin;
+ gdouble bottom_margin;
+ gdouble left_margin;
+ gdouble right_margin;
+ gint pages;
+ gint from_page;
+ gint to_page;
+ gint frame_type;
+ gint orientation;
+ gboolean print_color;
+
+ /*
+ * &T - title
+ * &U - Document URL
+ * &D - Date/Time
+ * &P - Page Number
+ * &PT - Page Number with total Number of Pages (example: 1 of 34)
+ *
+ * So, if headerLeftStr = "&T" the title and the document URL
+ * will be printed out on the top left-hand side of each page.
+ */
+ gchar *header_left_string;
+ gchar *header_center_string;
+ gchar *header_right_string;
+ gchar *footer_left_string;
+ gchar *footer_center_string;
+ gchar *footer_right_string;
+
+ gboolean preview;
+}
+EmbedPrintInfo;
+
+typedef enum
+{
+ PRINTPREVIEW_GOTO_PAGENUM = 0,
+ PRINTPREVIEW_PREV_PAGE = 1,
+ PRINTPREVIEW_NEXT_PAGE = 2,
+ PRINTPREVIEW_HOME = 3,
+ PRINTPREVIEW_END = 4
+} EmbedPrintPreviewNavType;
+
+typedef enum
+{
+ EMBED_SCROLL_UP,
+ EMBED_SCROLL_DOWN,
+ EMBED_SCROLL_LEFT,
+ EMBED_SCROLL_RIGHT
+} EmbedScrollDirection;
+
+typedef enum
+{
+ STATE_IS_UNKNOWN,
+ STATE_IS_INSECURE,
+ STATE_IS_BROKEN,
+ STATE_IS_SECURE_MED,
+ STATE_IS_SECURE_LOW,
+ STATE_IS_SECURE_HIGH
+} EmbedSecurityLevel;
+
+struct EphyEmbedClass
+{
+ GTypeInterface base_iface;
+
+ void (* favicon) (EphyEmbed *embed,
+ const char *location);
+ void (* link_message) (EphyEmbed *embed,
+ const char *link);
+ void (* js_status) (EphyEmbed *embed,
+ const char *status);
+ void (* location) (EphyEmbed *embed);
+ void (* title) (EphyEmbed *embed);
+ void (* progress) (EphyEmbed *embed,
+ const char *uri,
+ gint curprogress,
+ gint maxprogress);
+ void (* net_state) (EphyEmbed *embed,
+ const char *uri,
+ EmbedState state);
+ void (* new_window) (EphyEmbed *embed,
+ EphyEmbed **new_embed,
+ EmbedChromeMask chromemask);
+ void (* visibility) (EphyEmbed *embed,
+ gboolean visibility);
+ void (* destroy_brsr) (EphyEmbed *embed);
+ gint (* open_uri) (EphyEmbed *embed,
+ const char *uri);
+ void (* size_to) (EphyEmbed *embed,
+ gint width,
+ gint height);
+ gint (* dom_mouse_click) (EphyEmbed *embed,
+ EphyEmbedEvent *event);
+ gint (* dom_mouse_down) (EphyEmbed *embed,
+ EphyEmbedEvent *event);
+ void (* security_change) (EphyEmbed *embed,
+ EmbedSecurityLevel level);
+ void (* zoom_change) (EphyEmbed *embed,
+ guint new_zoom);
+
+ /* Methods */
+ void (* get_capabilities) (EphyEmbed *embed,
+ EmbedCapabilities *caps);
+ gresult (* load_url) (EphyEmbed *embed,
+ const char *url);
+ gresult (* stop_load) (EphyEmbed *embed);
+ gresult (* can_go_back) (EphyEmbed *embed);
+ gresult (* can_go_forward) (EphyEmbed *embed);
+ gresult (* can_go_up) (EphyEmbed *embed);
+ gresult (* get_go_up_list) (EphyEmbed *embed, GSList **l);
+ gresult (* go_back) (EphyEmbed *embed);
+ gresult (* go_forward) (EphyEmbed *embed);
+ gresult (* go_up) (EphyEmbed *embed);
+ gresult (* render_data) (EphyEmbed *embed,
+ const char *data,
+ guint32 len,
+ const char *base_uri,
+ const char *mime_type);
+ gresult (* open_stream) (EphyEmbed *embed,
+ const char *base_uri,
+ const char *mime_type);
+ gresult (* append_data) (EphyEmbed *embed,
+ const char *data,
+ guint32 len);
+ gresult (* close_stream) (EphyEmbed *embed);
+ gresult (* get_title) (EphyEmbed *embed,
+ char **title);
+ gresult (* get_location) (EphyEmbed *embed,
+ gboolean toplevel,
+ gboolean requested,
+ char **location);
+ gresult (* reload) (EphyEmbed *embed,
+ EmbedReloadFlags flags);
+ gresult (* copy_page) (EphyEmbed *dest,
+ EphyEmbed *source,
+ EmbedDisplayType display_type);
+ gresult (* grab_focus) (EphyEmbed *embed);
+ gresult (* get_link_tags) (EphyEmbed *embed,
+ const char *link_type,
+ GList **tags);
+ gresult (* zoom_set) (EphyEmbed *embed,
+ int zoom,
+ gboolean reflow);
+ gresult (* zoom_get) (EphyEmbed *embed,
+ int *zoom);
+ gresult (* selection_can_cut) (EphyEmbed *embed);
+ gresult (* selection_can_copy) (EphyEmbed *embed);
+ gresult (* can_paste) (EphyEmbed *embed);
+ gresult (* selection_cut) (EphyEmbed *embed);
+ gresult (* selection_copy) (EphyEmbed *embed);
+ gresult (* paste) (EphyEmbed *embed);
+ gresult (* select_all) (EphyEmbed *embed);
+ gresult (* shistory_count) (EphyEmbed *embed,
+ int *count);
+ gresult (* shistory_get_nth) (EphyEmbed *embed,
+ int nth,
+ gboolean is_relative,
+ char **url,
+ char **title);
+ gresult (* shistory_get_pos) (EphyEmbed *embed,
+ int *pos);
+ gresult (* shistory_go_nth) (EphyEmbed *embed,
+ int nth);
+ gboolean (* shistory_copy) (EphyEmbed *source,
+ EphyEmbed *dest);
+ gresult (* scroll) (EphyEmbed *embed,
+ EmbedScrollDirection direction);
+ gresult (* fine_scroll) (EphyEmbed *embed,
+ int horiz, int vert);
+ gresult (* get_security_level) (EphyEmbed *embed,
+ EmbedSecurityLevel *level,
+ char **description);
+ gresult (* find) (EphyEmbed *embed,
+ EmbedFindInfo *find);
+ gresult (* print) (EphyEmbed *embed,
+ EmbedPrintInfo *info);
+ gresult (* print_preview_close) (EphyEmbed *embed);
+ gresult (* print_preview_num_pages) (EphyEmbed *embed,
+ gint *retNum);
+ gresult (* print_preview_navigate) (EphyEmbed *embed,
+ EmbedPrintPreviewNavType navType,
+ gint pageNum);
+ gresult (* set_charset) (EphyEmbed *embed,
+ const char *charset);
+};
+
+GType ephy_embed_get_type (void);
+
+/* Base */
+
+EphyEmbed *ephy_embed_new (GObject *shell);
+
+void ephy_embed_get_capabilities (EphyEmbed *embed,
+ EmbedCapabilities *caps);
+
+gresult ephy_embed_load_url (EphyEmbed *embed,
+ const char *url);
+
+gresult ephy_embed_stop_load (EphyEmbed *embed);
+
+gresult ephy_embed_can_go_back (EphyEmbed *embed);
+
+gresult ephy_embed_can_go_forward (EphyEmbed *embed);
+
+gresult ephy_embed_can_go_up (EphyEmbed *embed);
+
+gresult ephy_embed_get_go_up_list (EphyEmbed *embed,
+ GSList **l);
+
+gresult ephy_embed_go_back (EphyEmbed *embed);
+
+gresult ephy_embed_go_forward (EphyEmbed *embed);
+
+gresult ephy_embed_go_up (EphyEmbed *embed);
+
+gresult ephy_embed_render_data (EphyEmbed *embed,
+ const char *data,
+ guint32 len,
+ const char *base_uri,
+ const char *mime_type);
+
+gresult ephy_embed_open_stream (EphyEmbed *embed,
+ const char *base_uri,
+ const char *mime_type);
+
+gresult ephy_embed_append_data (EphyEmbed *embed,
+ const char *data,
+ guint32 len);
+
+gresult ephy_embed_close_stream (EphyEmbed *embed);
+
+gresult ephy_embed_get_title (EphyEmbed *embed,
+ char **title);
+
+gresult ephy_embed_get_location (EphyEmbed *embed,
+ gboolean toplevel,
+ gboolean requested,
+ char **location);
+
+gresult ephy_embed_reload (EphyEmbed *embed,
+ EmbedReloadFlags flags);
+
+gresult ephy_embed_copy_page (EphyEmbed *dest,
+ EphyEmbed *source,
+ EmbedDisplayType display_type);
+
+gresult ephy_embed_grab_focus (EphyEmbed *embed);
+
+/* Link */
+gresult ephy_embed_get_favicon_location (EphyEmbed *embed,
+ char **url);
+
+gresult ephy_embed_get_link_tags (EphyEmbed *embed,
+ const char *link_type,
+ GList **tags);
+
+/* Zoom */
+gresult ephy_embed_zoom_set (EphyEmbed *embed,
+ int zoom,
+ gboolean reflow);
+
+gresult ephy_embed_zoom_get (EphyEmbed *embed,
+ int *zoom);
+
+/* Clipboard */
+gresult ephy_embed_selection_can_cut (EphyEmbed *embed);
+
+gresult ephy_embed_selection_can_copy (EphyEmbed *embed);
+
+gresult ephy_embed_can_paste (EphyEmbed *embed);
+
+gresult ephy_embed_selection_cut (EphyEmbed *embed);
+
+gresult ephy_embed_selection_copy (EphyEmbed *embed);
+
+gresult ephy_embed_paste (EphyEmbed *embed);
+
+gresult ephy_embed_select_all (EphyEmbed *embed);
+
+/* Session history */
+gresult ephy_embed_shistory_count (EphyEmbed *embed,
+ int *count);
+
+gresult ephy_embed_shistory_get_nth (EphyEmbed *embed,
+ int nth,
+ gboolean is_relative,
+ char **url,
+ char **title);
+
+gresult ephy_embed_shistory_get_pos (EphyEmbed *embed,
+ int *pos);
+
+gresult ephy_embed_shistory_go_nth (EphyEmbed *embed,
+ int nth);
+
+gboolean ephy_embed_shistory_copy (EphyEmbed *source,
+ EphyEmbed *dest);
+
+/* Utils */
+
+gresult ephy_embed_scroll (EphyEmbed *embed,
+ EmbedScrollDirection direction);
+
+gresult ephy_embed_fine_scroll (EphyEmbed *embed,
+ int horiz, int vert);
+
+gresult ephy_embed_get_security_level (EphyEmbed *embed,
+ EmbedSecurityLevel *level,
+ char **description);
+
+gresult ephy_embed_find (EphyEmbed *embed,
+ EmbedFindInfo *find);
+
+gresult ephy_embed_set_charset (EphyEmbed *embed,
+ const char *charset);
+
+/* Printing */
+
+gresult ephy_embed_print (EphyEmbed *embed,
+ EmbedPrintInfo *info);
+
+gresult ephy_embed_print_preview_close (EphyEmbed *embed);
+
+gresult ephy_embed_print_preview_num_pages (EphyEmbed *embed,
+ gint *retNum);
+
+gresult ephy_embed_print_preview_navigate (EphyEmbed *embed,
+ EmbedPrintPreviewNavType navType,
+ gint pageNum);
+
+G_END_DECLS
+
+#endif
diff --git a/embed/ephy-favicon-cache.c b/embed/ephy-favicon-cache.c
new file mode 100644
index 000000000..fd3c4192b
--- /dev/null
+++ b/embed/ephy-favicon-cache.c
@@ -0,0 +1,367 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen <jorn@nl.linux.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <libgnomevfs/gnome-vfs-uri.h>
+#include <libxml/tree.h>
+#include <string.h>
+#include <gtk/gtktoolbar.h>
+#include <gtk/gtkstock.h>
+#include <sys/stat.h>
+
+#include "ephy-embed-persist.h"
+#include "ephy-file-helpers.h"
+#include "ephy-favicon-cache.h"
+
+static void ephy_favicon_cache_class_init (EphyFaviconCacheClass *klass);
+static void ephy_favicon_cache_init (EphyFaviconCache *ma);
+static void ephy_favicon_cache_finalize (GObject *object);
+static void ephy_favicon_cache_insert (EphyFaviconCache *cache,
+ const char *url,
+ const char *pixbuf_location);
+static char *ephy_favicon_cache_dest (EphyFaviconCache *cache,
+ const char *url);
+static void favicon_download_completed_cb (EphyEmbedPersist *persist,
+ EphyFaviconCache *cache);
+
+struct EphyFaviconCachePrivate
+{
+ char *directory;
+
+ GdkPixbuf *default_pixbuf;
+ EphyHistory *history;
+};
+
+enum
+{
+ CHANGED,
+ LAST_SIGNAL
+};
+
+enum
+{
+ PROP_0,
+ PROP_HISTORY
+};
+
+enum
+{
+ EPHY_NODE_PAGE_PROP_FAVICON = 100
+};
+
+static guint ephy_favicon_cache_signals[LAST_SIGNAL] = { 0 };
+
+static GObjectClass *parent_class = NULL;
+
+GType
+ephy_favicon_cache_get_type (void)
+{
+ static GType ephy_favicon_cache_type = 0;
+
+ if (ephy_favicon_cache_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (EphyFaviconCacheClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) ephy_favicon_cache_class_init,
+ NULL,
+ NULL,
+ sizeof (EphyFaviconCache),
+ 0,
+ (GInstanceInitFunc) ephy_favicon_cache_init
+ };
+
+ ephy_favicon_cache_type = g_type_register_static (G_TYPE_OBJECT,
+ "EphyFaviconCache",
+ &our_info, 0);
+ }
+
+ return ephy_favicon_cache_type;
+}
+
+static void
+ephy_favicon_cache_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EphyFaviconCache *cache = EPHY_FAVICON_CACHE (object);
+
+ switch (prop_id)
+ {
+ case PROP_HISTORY:
+ cache->priv->history = g_value_get_object (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+ephy_favicon_cache_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ EphyFaviconCache *cache = EPHY_FAVICON_CACHE (object);
+
+ switch (prop_id)
+ {
+ case PROP_HISTORY:
+ g_value_set_object (value, cache->priv->history);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+static void
+ephy_favicon_cache_class_init (EphyFaviconCacheClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = ephy_favicon_cache_finalize;
+ object_class->set_property = ephy_favicon_cache_set_property;
+ object_class->get_property = ephy_favicon_cache_get_property;
+
+ g_object_class_install_property (object_class,
+ PROP_HISTORY,
+ g_param_spec_object ("History",
+ "Source history",
+ "Source history",
+ EPHY_HISTORY_TYPE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+
+ ephy_favicon_cache_signals[CHANGED] =
+ g_signal_new ("changed",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EphyFaviconCacheClass, changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_STRING);
+}
+
+static void
+ephy_favicon_cache_init (EphyFaviconCache *cache)
+{
+ GtkWidget *dummy;
+
+ cache->priv = g_new0 (EphyFaviconCachePrivate, 1);
+
+ cache->priv->directory = g_build_filename (ephy_dot_dir (),
+ "favicon_cache/",
+ NULL);
+
+ if (g_file_test (cache->priv->directory, G_FILE_TEST_IS_DIR) == FALSE)
+ {
+ if (g_file_test (cache->priv->directory, G_FILE_TEST_EXISTS))
+ {
+ g_error ("Please remove %s to continue.", cache->priv->directory);
+ }
+
+ if (mkdir (cache->priv->directory, 488) != 0)
+ {
+ g_error ("Couldn't mkdir %s.", cache->priv->directory);
+ }
+ }
+
+ dummy = gtk_toolbar_new ();
+ cache->priv->default_pixbuf = gtk_widget_render_icon (dummy,
+ GTK_STOCK_JUMP_TO,
+ GTK_ICON_SIZE_MENU, NULL);
+ gtk_widget_destroy (dummy);
+}
+
+static void
+ephy_favicon_cache_finalize (GObject *object)
+{
+ EphyFaviconCache *cache;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (EPHY_IS_FAVICON_CACHE (object));
+
+ cache = EPHY_FAVICON_CACHE (object);
+
+ g_return_if_fail (cache->priv != NULL);
+
+ g_object_unref (G_OBJECT (cache->priv->default_pixbuf));
+
+ g_object_unref (cache->priv->history);
+
+ g_free (cache->priv->directory);
+
+ g_free (cache->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+EphyFaviconCache *
+ephy_favicon_cache_new (EphyHistory *history)
+{
+ EphyFaviconCache *cache;
+
+ cache = EPHY_FAVICON_CACHE (g_object_new (EPHY_TYPE_FAVICON_CACHE,
+ "History", history,
+ NULL));
+
+ g_return_val_if_fail (cache->priv != NULL, NULL);
+
+ return cache;
+}
+
+GdkPixbuf *
+ephy_favicon_cache_lookup (EphyFaviconCache *cache,
+ const char *url)
+{
+ GdkPixbuf *ret;
+
+ g_return_val_if_fail (EPHY_IS_FAVICON_CACHE (cache), NULL);
+
+ if (url == NULL)
+ {
+ return cache->priv->default_pixbuf;
+ }
+
+ ret = ephy_favicon_cache_lookup_direct (cache, url);
+
+ if (ret == NULL)
+ {
+ return cache->priv->default_pixbuf;
+ }
+
+ return ret;
+}
+
+GdkPixbuf *
+ephy_favicon_cache_lookup_direct (EphyFaviconCache *cache,
+ const char *cache_url)
+{
+ GdkPixbuf *pixbuf;
+ EphyNode *node;
+ const char *pix_file;
+
+ node = ephy_history_get_page (cache->priv->history, cache_url);
+ if (node == NULL) return NULL;
+
+ pix_file = ephy_node_get_property_string
+ (node, EPHY_NODE_PAGE_PROP_FAVICON);
+ if (pix_file == NULL) return NULL;
+
+ pixbuf = gdk_pixbuf_new_from_file (pix_file, NULL);
+ g_return_val_if_fail (pixbuf != NULL, NULL);
+
+ if (gdk_pixbuf_get_width (pixbuf) > 16 ||
+ gdk_pixbuf_get_height (pixbuf) > 16)
+ {
+ GdkPixbuf *scaled = gdk_pixbuf_scale_simple (pixbuf, 16, 16,
+ GDK_INTERP_NEAREST);
+ g_object_unref (G_OBJECT (pixbuf));
+ pixbuf = scaled;
+ }
+
+ return pixbuf;
+}
+
+static void
+ephy_favicon_cache_insert (EphyFaviconCache *cache,
+ const char *url,
+ const char *pixbuf_location)
+{
+ EphyNode *node;
+ GValue value = { 0, };
+
+ node = ephy_history_get_page (cache->priv->history, url);
+ g_return_if_fail (node != NULL);
+
+ g_value_init (&value, G_TYPE_STRING);
+ g_value_set_string (&value, pixbuf_location);
+ ephy_node_set_property (node, EPHY_NODE_PAGE_PROP_FAVICON,
+ &value);
+ g_value_unset (&value);
+
+ g_signal_emit (G_OBJECT (cache), ephy_favicon_cache_signals[CHANGED], 0, url);
+}
+
+static char *
+ephy_favicon_cache_dest (EphyFaviconCache *cache, const char *url)
+{
+ char *slashpos, *dest, *my_url;
+
+ my_url = g_strdup (url);
+
+ while ((slashpos = strstr (my_url, "/")) != NULL)
+ *slashpos = '_';
+
+ dest = g_build_filename (cache->priv->directory, my_url, NULL);
+
+ g_free (my_url);
+
+ return dest;
+}
+
+void
+ephy_favicon_cache_insert_from_url (EphyFaviconCache *cache,
+ const char *url,
+ const char *favicon_url)
+{
+ EphyEmbedPersist *persist;
+ char *dest;
+
+ g_return_if_fail (EPHY_IS_FAVICON_CACHE (cache));
+ g_return_if_fail (url != NULL);
+ g_return_if_fail (favicon_url != NULL);
+
+ dest = ephy_favicon_cache_dest (cache, favicon_url);
+ g_return_if_fail (dest != NULL);
+
+ persist = ephy_embed_persist_new (NULL);
+
+ ephy_embed_persist_set_max_size (persist, 100);
+ ephy_embed_persist_set_flags (persist, EMBED_PERSIST_BYPASSCACHE);
+ ephy_embed_persist_set_source (persist, favicon_url);
+ ephy_embed_persist_set_dest (persist, dest);
+
+ g_object_set_data_full (G_OBJECT (persist), "url", g_strdup (url), g_free);
+ g_object_set_data_full (G_OBJECT (persist), "favicon", dest, g_free);
+
+ g_signal_connect (G_OBJECT (persist),
+ "completed",
+ G_CALLBACK (favicon_download_completed_cb),
+ cache);
+
+ ephy_embed_persist_save (persist);
+}
+
+static void
+favicon_download_completed_cb (EphyEmbedPersist *persist,
+ EphyFaviconCache *cache)
+{
+ ephy_favicon_cache_insert (cache,
+ g_object_get_data (G_OBJECT (persist), "url"),
+ g_object_get_data (G_OBJECT (persist), "favicon"));
+
+ g_object_unref (G_OBJECT (persist));
+}
diff --git a/embed/ephy-favicon-cache.h b/embed/ephy-favicon-cache.h
new file mode 100644
index 000000000..ff4ebcd56
--- /dev/null
+++ b/embed/ephy-favicon-cache.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "ephy-history.h"
+
+#include <glib-object.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#ifndef __EPHY_FAVICON_CACHE_H
+#define __EPHY_FAVICON_CACHE_H
+
+G_BEGIN_DECLS
+
+#define EPHY_TYPE_FAVICON_CACHE (ephy_favicon_cache_get_type ())
+#define EPHY_FAVICON_CACHE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EPHY_TYPE_FAVICON_CACHE, EphyFaviconCache))
+#define EPHY_FAVICON_CACHE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), EPHY_TYPE_FAVICON_CACHE, EphyFaviconCacheClass))
+#define EPHY_IS_FAVICON_CACHE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EPHY_TYPE_FAVICON_CACHE))
+#define EPHY_IS_FAVICON_CACHE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EPHY_TYPE_FAVICON_CACHE))
+#define EPHY_FAVICON_CACHE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EPHY_TYPE_FAVICON_CACHE, EphyFaviconCacheClass))
+
+typedef struct EphyFaviconCachePrivate EphyFaviconCachePrivate;
+
+typedef struct
+{
+ GObject parent;
+
+ EphyFaviconCachePrivate *priv;
+} EphyFaviconCache;
+
+typedef struct
+{
+ GObjectClass parent_class;
+
+ void (*changed) (EphyFaviconCache *cache, const char *url);
+} EphyFaviconCacheClass;
+
+GType ephy_favicon_cache_get_type (void);
+
+EphyFaviconCache *ephy_favicon_cache_new (EphyHistory *history);
+
+GdkPixbuf *ephy_favicon_cache_lookup (EphyFaviconCache *cache,
+ const char *url);
+
+GdkPixbuf *ephy_favicon_cache_lookup_direct (EphyFaviconCache *cache,
+ const char *cache_url);
+
+void ephy_favicon_cache_insert_from_url (EphyFaviconCache *cache,
+ const char *url,
+ const char *favicon_url);
+
+G_END_DECLS
+
+#endif /* __EPHY_FAVICON_CACHE_H */
diff --git a/embed/ephy-favicon.c b/embed/ephy-favicon.c
new file mode 100644
index 000000000..6670c20ab
--- /dev/null
+++ b/embed/ephy-favicon.c
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen <jorn@nl.linux.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <gtk/gtkwidget.h>
+#include <string.h>
+
+#include "ephy-favicon.h"
+#include "ephy-embed-shell.h"
+
+static void ephy_favicon_class_init (EphyFaviconClass *klass);
+static void ephy_favicon_init (EphyFavicon *ma);
+static void ephy_favicon_finalize (GObject *object);
+static void ephy_favicon_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void ephy_favicon_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void ephy_favicon_update_image (EphyFavicon *favicon);
+static void cache_changed_cb (EphyFaviconCache *cache,
+ const char *url,
+ EphyFavicon *favicon);
+
+struct EphyFaviconPrivate
+{
+ EphyFaviconCache *cache;
+
+ char *url;
+};
+
+enum
+{
+ PROP_0,
+ PROP_CACHE,
+ PROP_URL
+};
+
+enum
+{
+ CHANGED,
+ LAST_SIGNAL
+};
+
+static guint ephy_favicon_signals[LAST_SIGNAL] = { 0 };
+
+static GObjectClass *parent_class = NULL;
+
+GType
+ephy_favicon_get_type (void)
+{
+ static GType ephy_favicon_type = 0;
+
+ if (ephy_favicon_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (EphyFaviconClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) ephy_favicon_class_init,
+ NULL,
+ NULL,
+ sizeof (EphyFavicon),
+ 0,
+ (GInstanceInitFunc) ephy_favicon_init
+ };
+
+ ephy_favicon_type = g_type_register_static (GTK_TYPE_IMAGE,
+ "EphyFavicon",
+ &our_info, 0);
+ }
+
+ return ephy_favicon_type;
+}
+
+static void
+ephy_favicon_class_init (EphyFaviconClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = ephy_favicon_finalize;
+
+ object_class->set_property = ephy_favicon_set_property;
+ object_class->get_property = ephy_favicon_get_property;
+
+ g_object_class_install_property (object_class,
+ PROP_CACHE,
+ g_param_spec_object ("cache",
+ "Favicon cache",
+ "Favicon cache",
+ EPHY_TYPE_FAVICON_CACHE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (object_class,
+ PROP_URL,
+ g_param_spec_string ("url",
+ "Associated URL",
+ "Associated URL",
+ NULL,
+ G_PARAM_READWRITE));
+
+ ephy_favicon_signals[CHANGED] =
+ g_signal_new ("changed",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EphyFaviconClass, changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+}
+
+static void
+ephy_favicon_init (EphyFavicon *ma)
+{
+ ma->priv = g_new0 (EphyFaviconPrivate, 1);
+
+ gtk_widget_set_size_request (GTK_WIDGET (ma), 16, 16);
+}
+
+static void
+ephy_favicon_finalize (GObject *object)
+{
+ EphyFavicon *ma;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (EPHY_IS_FAVICON (object));
+
+ ma = EPHY_FAVICON (object);
+
+ g_return_if_fail (ma->priv != NULL);
+
+ g_free (ma->priv->url);
+
+ g_free (ma->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+ephy_favicon_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EphyFavicon *favicon = EPHY_FAVICON (object);
+
+ switch (prop_id)
+ {
+ case PROP_CACHE:
+ favicon->priv->cache = g_value_get_object (value);
+
+ g_signal_connect_object (G_OBJECT (favicon->priv->cache),
+ "changed",
+ G_CALLBACK (cache_changed_cb),
+ favicon,
+ 0);
+
+ ephy_favicon_update_image (favicon);
+ break;
+ case PROP_URL:
+ g_free (favicon->priv->url);
+ favicon->priv->url = g_strdup (g_value_get_string (value));
+
+ ephy_favicon_update_image (favicon);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+ephy_favicon_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ EphyFavicon *favicon = EPHY_FAVICON (object);
+
+ switch (prop_id)
+ {
+ case PROP_CACHE:
+ g_value_set_object (value, favicon->priv->cache);
+ break;
+ case PROP_URL:
+ g_value_set_string (value, favicon->priv->url);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+GtkWidget *
+ephy_favicon_new (const char *url)
+{
+ EphyFavicon *favicon;
+ EphyFaviconCache *cache = ephy_embed_shell_get_favicon_cache (embed_shell);
+
+ g_return_val_if_fail (EPHY_IS_FAVICON_CACHE (cache), NULL);
+
+ favicon = EPHY_FAVICON (g_object_new (EPHY_TYPE_FAVICON,
+ "cache", cache,
+ "url", url,
+ NULL));
+
+ g_return_val_if_fail (favicon->priv != NULL, NULL);
+
+ return GTK_WIDGET (favicon);
+}
+
+void
+ephy_favicon_set_url (EphyFavicon *favicon,
+ const char *url)
+{
+ g_return_if_fail (EPHY_IS_FAVICON (favicon));
+
+ g_object_set (G_OBJECT (favicon),
+ "url", url,
+ NULL);
+}
+
+const char *
+ephy_favicon_get_url (EphyFavicon *favicon)
+{
+ char *url;
+
+ g_return_val_if_fail (EPHY_IS_FAVICON (favicon), NULL);
+
+ g_object_get (G_OBJECT (favicon),
+ "url", &url,
+ NULL);
+
+ return (const char *) url;
+}
+
+static void
+cache_changed_cb (EphyFaviconCache *cache,
+ const char *url,
+ EphyFavicon *favicon)
+{
+ if (strcmp (url, favicon->priv->url) == 0)
+ {
+ ephy_favicon_update_image (favicon);
+ }
+}
+
+static void
+ephy_favicon_update_image (EphyFavicon *favicon)
+{
+ GdkPixbuf *pixbuf;
+
+ g_return_if_fail (EPHY_IS_FAVICON_CACHE (favicon->priv->cache));
+
+ pixbuf = ephy_favicon_cache_lookup (favicon->priv->cache,
+ favicon->priv->url);
+
+ gtk_image_set_from_pixbuf (GTK_IMAGE (favicon), pixbuf);
+
+ g_signal_emit (G_OBJECT (favicon), ephy_favicon_signals[CHANGED], 0);
+}
diff --git a/embed/ephy-favicon.h b/embed/ephy-favicon.h
new file mode 100644
index 000000000..97206cde5
--- /dev/null
+++ b/embed/ephy-favicon.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <glib-object.h>
+#include <gtk/gtkimage.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#include "ephy-favicon-cache.h"
+
+#ifndef __EPHY_FAVICON_H
+#define __EPHY_FAVICON_H
+
+G_BEGIN_DECLS
+
+#define EPHY_TYPE_FAVICON (ephy_favicon_get_type ())
+#define EPHY_FAVICON(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EPHY_TYPE_FAVICON, EphyFavicon))
+#define EPHY_FAVICON_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), EPHY_TYPE_FAVICON, EphyFaviconClass))
+#define EPHY_IS_FAVICON(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EPHY_TYPE_FAVICON))
+#define EPHY_IS_FAVICON_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EPHY_TYPE_FAVICON))
+#define EPHY_FAVICON_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EPHY_TYPE_FAVICON, EphyFaviconClass))
+
+typedef struct EphyFaviconPrivate EphyFaviconPrivate;
+
+typedef struct
+{
+ GtkImage parent;
+
+ EphyFaviconPrivate *priv;
+} EphyFavicon;
+
+typedef struct
+{
+ GtkImageClass parent_class;
+
+ void (*changed) (EphyFavicon *favicon);
+} EphyFaviconClass;
+
+GType ephy_favicon_get_type (void);
+
+GtkWidget *ephy_favicon_new (const char *url);
+
+void ephy_favicon_set_url (EphyFavicon *favicon,
+ const char *url);
+
+const char *ephy_favicon_get_url (EphyFavicon *favicon);
+
+G_END_DECLS
+
+#endif /* __EPHY_FAVICON_H */
diff --git a/embed/ephy-history.c b/embed/ephy-history.c
new file mode 100644
index 000000000..c106b274a
--- /dev/null
+++ b/embed/ephy-history.c
@@ -0,0 +1,644 @@
+/*
+ * Copyright (C) 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "ephy-history.h"
+#include "ephy-file-helpers.h"
+#include "ephy-autocompletion-source.h"
+
+#include <time.h>
+#include <string.h>
+#include <libgnome/gnome-i18n.h>
+#include <libgnomevfs/gnome-vfs-uri.h>
+
+//#define DEBUG_MSG(x) g_print x
+#define DEBUG_MSG(x)
+
+#define EPHY_HISTORY_XML_VERSION "0.1"
+
+struct EphyHistoryPrivate
+{
+ char *xml_file;
+ EphyNode *hosts;
+ EphyNode *pages;
+ EphyNode *last_page;
+ GHashTable *hosts_hash;
+ GStaticRWLock *hosts_hash_lock;
+ GHashTable *pages_hash;
+ GStaticRWLock *pages_hash_lock;
+};
+
+enum
+{
+ ADD,
+ UPDATE,
+ REMOVE,
+ VISITED,
+ LAST_SIGNAL
+};
+
+static void
+ephy_history_class_init (EphyHistoryClass *klass);
+static void
+ephy_history_init (EphyHistory *tab);
+static void
+ephy_history_finalize (GObject *object);
+static void
+ephy_history_autocompletion_source_init (EphyAutocompletionSourceIface *iface);
+
+static GObjectClass *parent_class = NULL;
+
+static guint ephy_history_signals[LAST_SIGNAL] = { 0 };
+
+GType
+ephy_history_get_type (void)
+{
+ static GType ephy_history_type = 0;
+
+ if (ephy_history_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (EphyHistoryClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) ephy_history_class_init,
+ NULL,
+ NULL, /* class_data */
+ sizeof (EphyHistory),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) ephy_history_init
+ };
+
+ static const GInterfaceInfo autocompletion_source_info =
+ {
+ (GInterfaceInitFunc) ephy_history_autocompletion_source_init,
+ NULL,
+ NULL
+ };
+
+ ephy_history_type = g_type_register_static (G_TYPE_OBJECT,
+ "EphyHistory",
+ &our_info, 0);
+
+ g_type_add_interface_static (ephy_history_type,
+ EPHY_TYPE_AUTOCOMPLETION_SOURCE,
+ &autocompletion_source_info);
+ }
+
+ return ephy_history_type;
+}
+
+static void
+ephy_history_autocompletion_source_set_basic_key (EphyAutocompletionSource *source,
+ const gchar *basic_key)
+{
+ /* nothing to do here */
+}
+
+static void
+ephy_history_autocompletion_source_foreach (EphyAutocompletionSource *source,
+ const gchar *current_text,
+ EphyAutocompletionSourceForeachFunc func,
+ gpointer data)
+{
+ GPtrArray *children;
+ int i;
+ EphyHistory *eb = EPHY_HISTORY (source);
+
+ children = ephy_node_get_children (eb->priv->pages);
+ for (i = 0; i < children->len; i++)
+ {
+ EphyNode *kid;
+ const char *url, *title;
+
+ kid = g_ptr_array_index (children, i);
+ url = ephy_node_get_property_string
+ (kid, EPHY_NODE_PAGE_PROP_LOCATION);
+ title = ephy_node_get_property_string
+ (kid, EPHY_NODE_PAGE_PROP_TITLE);
+
+ func (source, url,
+ url, url, FALSE,
+ FALSE, 0, data);
+ }
+ ephy_node_thaw (eb->priv->pages);
+}
+
+static void
+ephy_history_emit_data_changed (EphyHistory *eb)
+{
+ g_signal_emit_by_name (eb, "data-changed");
+}
+
+static void
+ephy_history_autocompletion_source_init (EphyAutocompletionSourceIface *iface)
+{
+ iface->foreach = ephy_history_autocompletion_source_foreach;
+ iface->set_basic_key = ephy_history_autocompletion_source_set_basic_key;
+}
+
+static void
+ephy_history_class_init (EphyHistoryClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = ephy_history_finalize;
+
+ ephy_history_signals[VISITED] =
+ g_signal_new ("visited",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (EphyHistoryClass, visited),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_STRING);
+}
+
+static void
+ephy_history_load (EphyHistory *eb)
+{
+ xmlDocPtr doc;
+ xmlNodePtr root, child;
+ char *tmp;
+
+ if (g_file_test (eb->priv->xml_file, G_FILE_TEST_EXISTS) == FALSE)
+ return;
+
+ doc = xmlParseFile (eb->priv->xml_file);
+ g_assert (doc != NULL);
+
+ root = xmlDocGetRootElement (doc);
+
+ tmp = xmlGetProp (root, "version");
+ g_assert (tmp != NULL && strcmp (tmp, EPHY_HISTORY_XML_VERSION) == 0);
+ g_free (tmp);
+
+ for (child = root->children; child != NULL; child = child->next)
+ {
+ EphyNode *node;
+
+ node = ephy_node_new_from_xml (child);
+ }
+
+ xmlFreeDoc (doc);
+}
+
+static void
+ephy_history_save (EphyHistory *eb)
+{
+ xmlDocPtr doc;
+ xmlNodePtr root;
+ GPtrArray *children;
+ int i;
+
+ DEBUG_MSG (("Saving history\n"));
+
+ /* save nodes to xml */
+ xmlIndentTreeOutput = TRUE;
+ doc = xmlNewDoc ("1.0");
+
+ root = xmlNewDocNode (doc, NULL, "ephy_history", NULL);
+ xmlSetProp (root, "version", EPHY_HISTORY_XML_VERSION);
+ xmlDocSetRootElement (doc, root);
+
+ children = ephy_node_get_children (eb->priv->hosts);
+ for (i = 0; i < children->len; i++)
+ {
+ EphyNode *kid;
+
+ kid = g_ptr_array_index (children, i);
+
+ ephy_node_save_to_xml (kid, root);
+ }
+ ephy_node_thaw (eb->priv->hosts);
+
+ children = ephy_node_get_children (eb->priv->pages);
+ for (i = 0; i < children->len; i++)
+ {
+ EphyNode *kid;
+
+ kid = g_ptr_array_index (children, i);
+
+ ephy_node_save_to_xml (kid, root);
+ }
+ ephy_node_thaw (eb->priv->pages);
+
+ xmlSaveFormatFile (eb->priv->xml_file, doc, 1);
+}
+
+static void
+hosts_added_cb (EphyNode *node,
+ EphyNode *child,
+ EphyHistory *eb)
+{
+ g_static_rw_lock_writer_lock (eb->priv->hosts_hash_lock);
+
+ g_hash_table_insert (eb->priv->hosts_hash,
+ (char *) ephy_node_get_property_string (child, EPHY_NODE_PAGE_PROP_TITLE),
+ child);
+
+ g_static_rw_lock_writer_unlock (eb->priv->hosts_hash_lock);
+}
+
+static void
+hosts_removed_cb (EphyNode *node,
+ EphyNode *child,
+ EphyHistory *eb)
+{
+ g_static_rw_lock_writer_lock (eb->priv->hosts_hash_lock);
+
+ g_hash_table_remove (eb->priv->hosts_hash,
+ ephy_node_get_property_string (child, EPHY_NODE_PAGE_PROP_TITLE));
+
+ g_static_rw_lock_writer_unlock (eb->priv->hosts_hash_lock);
+}
+
+static void
+pages_added_cb (EphyNode *node,
+ EphyNode *child,
+ EphyHistory *eb)
+{
+ g_static_rw_lock_writer_lock (eb->priv->pages_hash_lock);
+
+ g_hash_table_insert (eb->priv->pages_hash,
+ (char *) ephy_node_get_property_string (child, EPHY_NODE_PAGE_PROP_LOCATION),
+ child);
+
+ g_static_rw_lock_writer_unlock (eb->priv->pages_hash_lock);
+}
+
+static void
+pages_removed_cb (EphyNode *node,
+ EphyNode *child,
+ EphyHistory *eb)
+{
+ g_static_rw_lock_writer_lock (eb->priv->pages_hash_lock);
+
+ g_hash_table_remove (eb->priv->pages_hash,
+ ephy_node_get_property_string (child, EPHY_NODE_PAGE_PROP_LOCATION));
+
+ g_static_rw_lock_writer_unlock (eb->priv->pages_hash_lock);
+}
+
+static void
+ephy_history_init (EphyHistory *eb)
+{
+ eb->priv = g_new0 (EphyHistoryPrivate, 1);
+
+ eb->priv->xml_file = g_build_filename (ephy_dot_dir (),
+ "ephy-history.xml",
+ NULL);
+
+ ephy_node_system_init ();
+
+ eb->priv->pages_hash = g_hash_table_new (g_str_hash,
+ g_str_equal);
+ eb->priv->pages_hash_lock = g_new0 (GStaticRWLock, 1);
+ g_static_rw_lock_init (eb->priv->pages_hash_lock);
+
+ eb->priv->hosts_hash = g_hash_table_new (g_str_hash,
+ g_str_equal);
+ eb->priv->hosts_hash_lock = g_new0 (GStaticRWLock, 1);
+ g_static_rw_lock_init (eb->priv->hosts_hash_lock);
+
+ /* Bookmarks */
+ eb->priv->pages = ephy_node_new ();
+ ephy_node_ref (eb->priv->pages);
+ g_signal_connect_object (G_OBJECT (eb->priv->pages),
+ "child_added",
+ G_CALLBACK (pages_added_cb),
+ G_OBJECT (eb),
+ 0);
+ g_signal_connect_object (G_OBJECT (eb->priv->pages),
+ "child_removed",
+ G_CALLBACK (pages_removed_cb),
+ G_OBJECT (eb),
+ 0);
+
+ /* Hosts */
+ eb->priv->hosts = ephy_node_new ();
+ ephy_node_ref (eb->priv->hosts);
+ g_signal_connect_object (G_OBJECT (eb->priv->hosts),
+ "child_added",
+ G_CALLBACK (hosts_added_cb),
+ G_OBJECT (eb),
+ 0);
+ g_signal_connect_object (G_OBJECT (eb->priv->hosts),
+ "child_removed",
+ G_CALLBACK (hosts_removed_cb),
+ G_OBJECT (eb),
+ 0);
+
+ ephy_history_load (eb);
+ ephy_history_emit_data_changed (eb);
+}
+
+static void
+ephy_history_finalize (GObject *object)
+{
+ EphyHistory *eb;
+
+ g_return_if_fail (IS_EPHY_HISTORY (object));
+
+ eb = EPHY_HISTORY (object);
+
+ g_return_if_fail (eb->priv != NULL);
+
+ ephy_history_save (eb);
+
+ ephy_node_unref (eb->priv->pages);
+ ephy_node_unref (eb->priv->hosts);
+
+ g_hash_table_destroy (eb->priv->pages_hash);
+ g_static_rw_lock_free (eb->priv->pages_hash_lock);
+ g_hash_table_destroy (eb->priv->hosts_hash);
+ g_static_rw_lock_free (eb->priv->hosts_hash_lock);
+
+ g_free (eb->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+EphyHistory *
+ephy_history_new ()
+{
+ EphyHistory *tab;
+
+ tab = EPHY_HISTORY (g_object_new (EPHY_HISTORY_TYPE, NULL));
+
+ return tab;
+}
+
+static EphyNode *
+ephy_history_add_host (EphyHistory *eh, const char *url)
+{
+ EphyNode *host;
+ GnomeVFSURI *vfs_uri = NULL;
+ const char *host_name = NULL;
+ char *host_location = NULL;
+ GTime now;
+ GValue value = { 0, };
+ int visits;
+
+ now = time (NULL);
+
+ /* Build an host name */
+ if (!g_ascii_strncasecmp (url, "file://", 7))
+ {
+ host_name = _("Local files");
+ host_location = g_strdup ("file://");
+ }
+ else
+ {
+ vfs_uri = gnome_vfs_uri_new (url);
+ if (vfs_uri != NULL)
+ {
+ host_name = gnome_vfs_uri_get_host_name (vfs_uri);
+ host_location = gnome_vfs_uri_to_string
+ (vfs_uri, GNOME_VFS_URI_HIDE_FRAGMENT_IDENTIFIER);
+ }
+
+ if (host_name == NULL)
+ {
+ host_name = _("Other");
+ host_location = g_strdup ("about:blank");
+ }
+ }
+
+ g_static_rw_lock_reader_lock (eh->priv->hosts_hash_lock);
+ host = g_hash_table_lookup (eh->priv->hosts_hash, host_name);
+ g_static_rw_lock_reader_unlock (eh->priv->hosts_hash_lock);
+
+ if (!host)
+ {
+ host = ephy_node_new ();
+ g_value_init (&value, G_TYPE_STRING);
+ g_value_set_string (&value, host_name);
+ ephy_node_set_property (host, EPHY_NODE_PAGE_PROP_TITLE,
+ &value);
+ g_value_unset (&value);
+
+ g_value_init (&value, G_TYPE_STRING);
+ g_value_set_string (&value, host_location);
+ ephy_node_set_property (host, EPHY_NODE_PAGE_PROP_LOCATION,
+ &value);
+ g_value_unset (&value);
+
+ g_value_init (&value, G_TYPE_INT);
+ g_value_set_int (&value, now);
+ ephy_node_set_property (host, EPHY_NODE_PAGE_PROP_FIRST_VISIT,
+ &value);
+ g_value_unset (&value);
+
+ ephy_node_add_child (eh->priv->hosts, host);
+ }
+
+ visits = ephy_node_get_property_int
+ (host, EPHY_NODE_PAGE_PROP_VISITS);
+ if (visits < 0) visits = 0;
+ visits++;
+
+ g_value_init (&value, G_TYPE_INT);
+ g_value_set_int (&value, visits);
+ ephy_node_set_property (host, EPHY_NODE_PAGE_PROP_VISITS,
+ &value);
+ g_value_unset (&value);
+
+ g_value_init (&value, G_TYPE_INT);
+ g_value_set_int (&value, now);
+ ephy_node_set_property (host, EPHY_NODE_PAGE_PROP_LAST_VISIT,
+ &value);
+ g_value_unset (&value);
+
+ if (vfs_uri)
+ {
+ gnome_vfs_uri_unref (vfs_uri);
+ }
+
+ g_free (host_location);
+
+ return host;
+}
+
+static void
+ephy_history_visited (EphyHistory *eh, EphyNode *node)
+{
+ GValue value = { 0, };
+ GTime now;
+ int visits;
+ const char *url;
+
+ now = time (NULL);
+
+ url = ephy_node_get_property_string
+ (node, EPHY_NODE_PAGE_PROP_LOCATION);
+
+ visits = ephy_node_get_property_int
+ (node, EPHY_NODE_PAGE_PROP_VISITS);
+ if (visits < 0) visits = 0;
+ visits++;
+
+ g_value_init (&value, G_TYPE_INT);
+ g_value_set_int (&value, visits);
+ ephy_node_set_property (node, EPHY_NODE_PAGE_PROP_VISITS,
+ &value);
+ g_value_unset (&value);
+
+ g_value_init (&value, G_TYPE_INT);
+ g_value_set_int (&value, now);
+ ephy_node_set_property (node, EPHY_NODE_PAGE_PROP_LAST_VISIT,
+ &value);
+ if (visits == 1)
+ {
+ ephy_node_set_property
+ (node, EPHY_NODE_PAGE_PROP_FIRST_VISIT, &value);
+ }
+ g_value_unset (&value);
+
+ eh->priv->last_page = node;
+
+ g_signal_emit (G_OBJECT (eh), ephy_history_signals[VISITED], 0, url);
+ ephy_history_emit_data_changed (eh);
+}
+
+int
+ephy_history_get_page_visits (EphyHistory *gh,
+ const char *url)
+{
+ EphyNode *node;
+ int visits;
+
+ node = ephy_history_get_page (gh, url);
+
+ visits = ephy_node_get_property_int
+ (node, EPHY_NODE_PAGE_PROP_VISITS);
+ if (visits < 0) visits = 0;
+ visits++;
+
+ return visits;
+}
+
+void
+ephy_history_add_page (EphyHistory *eb,
+ const char *url)
+{
+ EphyNode *bm, *node, *host;
+ GValue value = { 0, };
+
+ node = ephy_history_get_page (eb, url);
+ if (node)
+ {
+ ephy_history_visited (eb, node);
+ return;
+ }
+
+ bm = ephy_node_new ();
+
+ g_value_init (&value, G_TYPE_STRING);
+ g_value_set_string (&value, url);
+ ephy_node_set_property (bm, EPHY_NODE_PAGE_PROP_LOCATION,
+ &value);
+ ephy_node_set_property (bm, EPHY_NODE_PAGE_PROP_TITLE,
+ &value);
+ g_value_unset (&value);
+
+ host = ephy_history_add_host (eb, url);
+
+ g_value_init (&value, G_TYPE_INT);
+ g_value_set_int (&value, ephy_node_get_id (host));
+ ephy_node_set_property (bm, EPHY_NODE_PAGE_PROP_HOST_ID,
+ &value);
+ g_value_unset (&value);
+
+ ephy_history_visited (eb, bm);
+
+ ephy_node_add_child (host, bm);
+ ephy_node_add_child (eb->priv->pages, bm);
+}
+
+EphyNode *
+ephy_history_get_page (EphyHistory *eb,
+ const char *url)
+{
+ EphyNode *node;
+
+ g_static_rw_lock_reader_lock (eb->priv->pages_hash_lock);
+ node = g_hash_table_lookup (eb->priv->pages_hash, url);
+ g_static_rw_lock_reader_unlock (eb->priv->pages_hash_lock);
+
+ return node;
+}
+
+gboolean
+ephy_history_is_page_visited (EphyHistory *gh,
+ const char *url)
+{
+ return (ephy_history_get_page (gh, url) != NULL);
+}
+
+void
+ephy_history_set_page_title (EphyHistory *gh,
+ const char *url,
+ const char *title)
+{
+ EphyNode *node;
+
+ node = ephy_history_get_page (gh, url);
+ if (node)
+ {
+ GValue value = { 0, };
+
+ g_value_init (&value, G_TYPE_STRING);
+ g_value_set_string (&value, title);
+ ephy_node_set_property
+ (node, EPHY_NODE_PAGE_PROP_TITLE, &value);
+ g_value_unset (&value);
+ }
+}
+
+void
+ephy_history_clear (EphyHistory *gh)
+{
+ ephy_node_unref (gh->priv->hosts);
+ ephy_history_save (gh);
+}
+
+EphyNode *
+ephy_history_get_hosts (EphyHistory *eb)
+{
+ return eb->priv->hosts;
+}
+
+EphyNode *
+ephy_history_get_pages (EphyHistory *eb)
+{
+ return eb->priv->pages;
+}
+
+const char *
+ephy_history_get_last_page (EphyHistory *gh)
+{
+ if (gh->priv->last_page == NULL) return NULL;
+
+ return ephy_node_get_property_string
+ (gh->priv->last_page, EPHY_NODE_PAGE_PROP_LOCATION);
+}
diff --git a/embed/ephy-history.h b/embed/ephy-history.h
new file mode 100644
index 000000000..641ab6d7c
--- /dev/null
+++ b/embed/ephy-history.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EPHY_HISTORY_H
+#define EPHY_HISTORY_H
+
+#include <glib-object.h>
+
+#include "ephy-node.h"
+
+G_BEGIN_DECLS
+
+typedef struct EphyHistoryClass EphyHistoryClass;
+
+#define EPHY_HISTORY_TYPE (ephy_history_get_type ())
+#define EPHY_HISTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EPHY_HISTORY_TYPE, EphyHistory))
+#define EPHY_HISTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EPHY_HISTORY_TYPE, EphyHistoryClass))
+#define IS_EPHY_HISTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EPHY_HISTORY_TYPE))
+#define IS_EPHY_HISTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EPHY_HISTORY_TYPE))
+
+typedef struct EphyHistory EphyHistory;
+typedef struct EphyHistoryPrivate EphyHistoryPrivate;
+
+enum
+{
+ EPHY_NODE_PAGE_PROP_TITLE = 2,
+ EPHY_NODE_PAGE_PROP_LOCATION = 3,
+ EPHY_NODE_PAGE_PROP_VISITS = 4,
+ EPHY_NODE_PAGE_PROP_LAST_VISIT = 5,
+ EPHY_NODE_PAGE_PROP_FIRST_VISIT = 6,
+ EPHY_NODE_PAGE_PROP_HOST_ID = 7
+};
+
+struct EphyHistory
+{
+ GObject parent;
+ EphyHistoryPrivate *priv;
+};
+
+struct EphyHistoryClass
+{
+ GObjectClass parent_class;
+
+ void (* visited) (const char *url);
+};
+
+GType ephy_history_get_type (void);
+
+EphyHistory *ephy_history_new (void);
+
+EphyNode *ephy_history_get_hosts (EphyHistory *gh);
+
+EphyNode *ephy_history_get_pages (EphyHistory *gh);
+
+EphyNode *ephy_history_get_page (EphyHistory *gh,
+ const char *url);
+
+void ephy_history_add_page (EphyHistory *gh,
+ const char *url);
+
+gboolean ephy_history_is_page_visited (EphyHistory *gh,
+ const char *url);
+
+int ephy_history_get_page_visits (EphyHistory *gh,
+ const char *url);
+
+void ephy_history_set_page_title (EphyHistory *gh,
+ const char *url,
+ const char *title);
+
+const char *ephy_history_get_last_page (EphyHistory *gh);
+
+void ephy_history_clear (EphyHistory *gh);
+
+G_END_DECLS
+
+#endif
diff --git a/embed/find-dialog.c b/embed/find-dialog.c
new file mode 100755
index 000000000..7b96e86c1
--- /dev/null
+++ b/embed/find-dialog.c
@@ -0,0 +1,431 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "find-dialog.h"
+#include "ephy-prefs.h"
+#include "ephy-embed.h"
+
+#define CONF_FIND_MATCH_CASE "/apps/epiphany/find/match_case"
+#define CONF_FIND_AUTOWRAP "/apps/epiphany/find/autowrap"
+#define CONF_FIND_WORD "/apps/epiphany/find/word"
+
+static void find_dialog_class_init (FindDialogClass *klass);
+static void find_dialog_init (FindDialog *dialog);
+static void find_dialog_finalize (GObject *object);
+
+static void
+impl_construct (EphyDialog *dialog,
+ const EphyDialogProperty *properties,
+ const char *file,
+ const char *name);
+static void
+impl_destruct (EphyDialog *dialog);
+static void
+impl_show (EphyDialog *dialog);
+
+
+/* Glade callbacks */
+void find_close_button_clicked_cb (GtkWidget *button, EphyDialog *dialog);
+void find_next_button_clicked_cb (GtkWidget *button, EphyDialog *dialog);
+void find_prev_button_clicked_cb (GtkWidget *button, EphyDialog *dialog);
+void find_entry_activate_cb (GtkWidget *editable, EphyDialog *dialog);
+void find_entry_changed_cb (GtkWidget *editable, EphyDialog *dialog);
+void find_check_toggled_cb (GtkWidget *toggle, EphyDialog *dialog);
+
+static GObjectClass *parent_class = NULL;
+
+struct FindDialogPrivate
+{
+ EmbedFindInfo *properties;
+ gboolean can_go_prev;
+ gboolean can_go_next;
+ gboolean constructed;
+};
+
+enum
+{
+ SEARCH,
+ LAST_SIGNAL
+};
+
+enum
+{
+ MATCH_CASE_PROP,
+ AUTOWRAP_PROP,
+ WORD_PROP,
+ BACK_BUTTON,
+ FORWARD_BUTTON
+};
+
+static const
+EphyDialogProperty properties [] =
+{
+ { MATCH_CASE_PROP, "case_check", CONF_FIND_MATCH_CASE, PT_NORMAL, NULL },
+ { AUTOWRAP_PROP, "wrap_check", CONF_FIND_AUTOWRAP, PT_NORMAL, NULL },
+ { WORD_PROP, "find_entry", CONF_FIND_WORD, PT_NORMAL, NULL },
+ { BACK_BUTTON, "back_button", NULL, PT_NORMAL, NULL },
+ { FORWARD_BUTTON, "forward_button", NULL, PT_NORMAL, NULL },
+ { -1, NULL, NULL }
+};
+
+static guint find_dialog_signals[LAST_SIGNAL] = { 0 };
+
+GType
+find_dialog_get_type (void)
+{
+ static GType find_dialog_type = 0;
+
+ if (find_dialog_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (FindDialogClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) find_dialog_class_init,
+ NULL,
+ NULL, /* class_data */
+ sizeof (FindDialog),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) find_dialog_init
+ };
+
+ find_dialog_type = g_type_register_static (EPHY_EMBED_DIALOG_TYPE,
+ "FindDialog",
+ &our_info, 0);
+ }
+
+ return find_dialog_type;
+
+}
+
+static void
+find_dialog_class_init (FindDialogClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ EphyDialogClass *ephy_dialog_class;
+
+ parent_class = g_type_class_peek_parent (klass);
+ ephy_dialog_class = EPHY_DIALOG_CLASS (klass);
+
+ object_class->finalize = find_dialog_finalize;
+
+ ephy_dialog_class->construct = impl_construct;
+ ephy_dialog_class->destruct = impl_destruct;
+ ephy_dialog_class->show = impl_show;
+
+ find_dialog_signals[SEARCH] =
+ g_signal_new ("search",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (FindDialogClass, search),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+}
+
+static void
+find_update_nav (EphyDialog *dialog)
+{
+ GtkWidget *forward_button;
+ GtkWidget *back_button;
+
+ g_signal_emit (G_OBJECT (dialog), find_dialog_signals[SEARCH], 0);
+
+ if (!FIND_DIALOG(dialog)->priv->constructed) return;
+
+ forward_button = ephy_dialog_get_control (dialog, FORWARD_BUTTON);
+ gtk_widget_set_sensitive (forward_button,
+ FIND_DIALOG(dialog)->priv->can_go_next);
+
+ back_button = ephy_dialog_get_control (dialog, BACK_BUTTON);
+ gtk_widget_set_sensitive (back_button,
+ FIND_DIALOG(dialog)->priv->can_go_prev);
+}
+
+void static
+ensure_constructed (FindDialog *dialog)
+{
+ if (!dialog->priv->constructed)
+ {
+ ephy_dialog_construct (EPHY_DIALOG(dialog),
+ properties,
+ "epiphany.glade",
+ "find_dialog");
+ }
+}
+
+static void
+find_dialog_init (FindDialog *dialog)
+{
+ dialog->priv = g_new0 (FindDialogPrivate, 1);
+
+ dialog->priv->properties = NULL;
+ dialog->priv->can_go_prev = TRUE;
+ dialog->priv->can_go_next = TRUE;
+ dialog->priv->constructed = FALSE;
+
+ ensure_constructed (dialog);
+}
+
+static void
+impl_construct (EphyDialog *dialog,
+ const EphyDialogProperty *properties,
+ const char *file,
+ const char *name)
+{
+ FIND_DIALOG(dialog)->priv->constructed = TRUE;
+
+ EPHY_DIALOG_CLASS (parent_class)->construct (dialog, properties, file, name);
+}
+
+static void
+impl_destruct (EphyDialog *dialog)
+{
+ FIND_DIALOG(dialog)->priv->constructed = FALSE;
+
+ EPHY_DIALOG_CLASS (parent_class)->destruct (dialog);
+}
+
+static void
+impl_show (EphyDialog *dialog)
+{
+ FindDialog *find_dialog = FIND_DIALOG(dialog);
+ ensure_constructed (find_dialog);
+
+ find_dialog->priv->can_go_prev = TRUE;
+ find_dialog->priv->can_go_next = TRUE;
+ find_update_nav (dialog);
+
+ /* Focus the text entry. This will correctly select or leave
+ * unselected the existing text in the entry depending on the
+ * 'gtk-entry-select-on-focus = 0 / 1' setting in user's gtkrc.
+ */
+ gtk_widget_grab_focus (ephy_dialog_get_control (dialog, WORD_PROP));
+
+ EPHY_DIALOG_CLASS (parent_class)->show (dialog);
+}
+
+static void
+find_dialog_finalize (GObject *object)
+{
+ FindDialog *dialog;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (IS_FIND_DIALOG (object));
+
+ dialog = FIND_DIALOG (object);
+
+ g_return_if_fail (dialog->priv != NULL);
+
+ g_free (dialog->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+EphyDialog *
+find_dialog_new (EphyEmbed *embed)
+{
+ FindDialog *dialog;
+
+ dialog = FIND_DIALOG (g_object_new (FIND_DIALOG_TYPE,
+ "EphyEmbed", embed,
+ NULL));
+
+ return EPHY_DIALOG(dialog);
+}
+
+EphyDialog *
+find_dialog_new_with_parent (GtkWidget *window,
+ EphyEmbed *embed)
+{
+ FindDialog *dialog;
+
+ dialog = FIND_DIALOG (g_object_new (FIND_DIALOG_TYPE,
+ "EphyEmbed", embed,
+ "ParentWindow", window,
+ NULL));
+
+ return EPHY_DIALOG(dialog);
+}
+
+gboolean
+find_dialog_can_go_next (FindDialog *dialog)
+{
+ return dialog->priv->can_go_next;
+}
+
+gboolean
+find_dialog_can_go_prev (FindDialog *dialog)
+{
+ return dialog->priv->can_go_prev;
+}
+
+void
+find_dialog_go_next (FindDialog *dialog,
+ gboolean interactive)
+{
+ gresult result;
+ EphyEmbed *embed;
+
+ if (!find_dialog_can_go_next (dialog)) return;
+
+ dialog->priv->properties->backwards = FALSE;
+ dialog->priv->properties->interactive = interactive;
+
+ embed = ephy_embed_dialog_get_embed (EPHY_EMBED_DIALOG(dialog));
+ g_return_if_fail (embed != NULL);
+
+ result = ephy_embed_find (embed,
+ dialog->priv->properties);
+
+ dialog->priv->can_go_prev = TRUE;
+ if (result != G_OK)
+ {
+ dialog->priv->can_go_next = FALSE;
+ }
+
+ find_update_nav (EPHY_DIALOG(dialog));
+}
+
+void
+find_dialog_go_prev (FindDialog *dialog,
+ gboolean interactive)
+{
+ gresult result;
+ EphyEmbed *embed;
+
+ if (!find_dialog_can_go_prev (dialog)) return;
+
+ dialog->priv->properties->backwards = TRUE;
+ dialog->priv->properties->interactive = interactive;
+
+ embed = ephy_embed_dialog_get_embed (EPHY_EMBED_DIALOG(dialog));
+ g_return_if_fail (embed != NULL);
+
+ result = ephy_embed_find (embed,
+ dialog->priv->properties);
+
+ dialog->priv->can_go_next = TRUE;
+ if (result != G_OK)
+ {
+ dialog->priv->can_go_prev = FALSE;
+ }
+
+ find_update_nav (EPHY_DIALOG(dialog));
+}
+
+static void
+find_get_info (EphyDialog *dialog)
+{
+ EmbedFindInfo *properties;
+ char *search_string;
+ GValue word = {0, };
+ GValue match_case = {0, };
+ GValue wrap = {0, };
+ FindDialog *find_dialog = FIND_DIALOG(dialog);
+
+ /* get the search string from the entry field */
+ ephy_dialog_get_value (dialog, WORD_PROP, &word);
+ search_string = g_strdup(g_value_get_string (&word));
+
+ /* don't do null searches */
+ if (search_string[0] == '\0')
+ {
+ return;
+ }
+
+ if (find_dialog->priv->properties != NULL)
+ {
+ g_free (find_dialog->priv->properties->search_string);
+ g_free (find_dialog->priv->properties);
+ }
+
+ /* build search structure */
+ properties = g_new0 (EmbedFindInfo,1);
+ properties->search_string = search_string;
+
+ ephy_dialog_get_value (dialog, MATCH_CASE_PROP, &match_case);
+ properties->match_case = g_value_get_boolean (&match_case);
+
+ ephy_dialog_get_value (dialog, AUTOWRAP_PROP, &wrap);
+ properties->wrap = g_value_get_boolean (&wrap);
+
+ properties->entire_word = FALSE;
+ properties->search_frames = TRUE;
+
+ find_dialog->priv->properties = properties;
+}
+
+void
+find_close_button_clicked_cb (GtkWidget *button,
+ EphyDialog *dialog)
+{
+ ephy_dialog_destruct (dialog);
+ g_object_unref (dialog);
+}
+
+void find_next_button_clicked_cb (GtkWidget *button,
+ EphyDialog *dialog)
+{
+ find_dialog_go_next (FIND_DIALOG(dialog), TRUE);
+}
+
+void
+find_prev_button_clicked_cb (GtkWidget *button,
+ EphyDialog *dialog)
+{
+ find_dialog_go_prev (FIND_DIALOG(dialog), TRUE);
+}
+
+void
+find_entry_activate_cb (GtkWidget *editable,
+ EphyDialog *dialog)
+{
+ find_dialog_go_next (FIND_DIALOG(dialog), TRUE);
+ find_update_nav (dialog);
+}
+
+void
+find_entry_changed_cb (GtkWidget *editable,
+ EphyDialog *dialog)
+{
+ FindDialog *find_dialog = FIND_DIALOG(dialog);
+
+ find_dialog->priv->can_go_prev = TRUE;
+ find_dialog->priv->can_go_next = TRUE;
+
+ find_get_info (dialog);
+
+ find_update_nav (dialog);
+}
+
+void
+find_check_toggled_cb (GtkWidget *toggle,
+ EphyDialog *dialog)
+{
+ FindDialog *find_dialog = FIND_DIALOG(dialog);
+
+ find_dialog->priv->can_go_prev = TRUE;
+ find_dialog->priv->can_go_next = TRUE;
+
+ find_get_info (dialog);
+
+ find_update_nav (dialog);
+}
diff --git a/embed/find-dialog.h b/embed/find-dialog.h
new file mode 100644
index 000000000..325f8a7b7
--- /dev/null
+++ b/embed/find-dialog.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef FIND_DIALOG_H
+#define FIND_DIALOG_H
+
+#include "ephy-embed-dialog.h"
+
+#include <glib-object.h>
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef struct FindDialog FindDialog;
+typedef struct FindDialogClass FindDialogClass;
+
+#define FIND_DIALOG_TYPE (find_dialog_get_type ())
+#define FIND_DIALOG(obj) (GTK_CHECK_CAST ((obj), FIND_DIALOG_TYPE, FindDialog))
+#define FIND_DIALOG_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), FIND_DIALOG, FindDialogClass))
+#define IS_FIND_DIALOG(obj) (GTK_CHECK_TYPE ((obj), FIND_DIALOG_TYPE))
+#define IS_FIND_DIALOG_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), FIND_DIALOG))
+
+typedef struct FindDialogPrivate FindDialogPrivate;
+
+struct FindDialog
+{
+ EphyEmbedDialog parent;
+ FindDialogPrivate *priv;
+};
+
+struct FindDialogClass
+{
+ EphyEmbedDialogClass parent_class;
+
+ void (* search) (FindDialog *dialog);
+};
+
+GType find_dialog_get_type (void);
+
+EphyDialog *find_dialog_new (EphyEmbed *embed);
+
+EphyDialog *find_dialog_new_with_parent (GtkWidget *window,
+ EphyEmbed *embed);
+
+
+gboolean find_dialog_can_go_next (FindDialog *dialog);
+
+gboolean find_dialog_can_go_prev (FindDialog *dialog);
+
+void find_dialog_go_next (FindDialog *dialog,
+ gboolean interactive);
+
+void find_dialog_go_prev (FindDialog *dialog,
+ gboolean interactive);
+
+G_END_DECLS
+
+#endif
+
diff --git a/embed/mozilla/.cvsignore b/embed/mozilla/.cvsignore
new file mode 100644
index 000000000..20e4cb0c8
--- /dev/null
+++ b/embed/mozilla/.cvsignore
@@ -0,0 +1,6 @@
+Makefile
+Makefile.in
+*.lo
+.deps
+.libs
+*.la
diff --git a/embed/mozilla/BaseProtocolContentHandler.cpp b/embed/mozilla/BaseProtocolContentHandler.cpp
new file mode 100644
index 000000000..741d21722
--- /dev/null
+++ b/embed/mozilla/BaseProtocolContentHandler.cpp
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2001 Philip Langdale
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "nsCOMPtr.h"
+#include "nsIURI.h"
+#include "nsIChannel.h"
+#include "nsIStorageStream.h"
+#include "nsIInputStream.h"
+#include "nsIOutputStream.h"
+#include "nsNetUtil.h"
+#include "nsIExternalProtocolService.h"
+#include "nsCExternalHandlerService.h"
+
+#include "BaseProtocolContentHandler.h"
+
+/* Implementation file */
+NS_IMPL_ISUPPORTS2 (GBaseProtocolContentHandler, nsIProtocolHandler, nsIContentHandler)
+
+GBaseProtocolContentHandler::GBaseProtocolContentHandler(const char *aScheme) :
+ GBaseProtocolHandler(aScheme)
+{
+ NS_INIT_ISUPPORTS();
+ /* member initializers and constructor code */
+ mMimeType = NS_LITERAL_CSTRING("application-x-gnome-") + mScheme;
+}
+
+GBaseProtocolContentHandler::~GBaseProtocolContentHandler()
+{
+ /* destructor code */
+}
+
+/* nsIChannel newChannel (in nsIURI aURI); */
+NS_IMETHODIMP GBaseProtocolContentHandler::NewChannel(nsIURI *aURI,
+ nsIChannel **_retval)
+{
+ nsCOMPtr<nsIStorageStream> sStream;
+ nsresult rv = NS_NewStorageStream(1, 16, getter_AddRefs(sStream));
+ if (NS_FAILED(rv)) return rv;
+
+ nsCOMPtr<nsIOutputStream> oStream;
+ rv = sStream->GetOutputStream(0, getter_AddRefs(oStream));
+
+ PRUint32 bytes;
+ oStream->Write("Dummy stream\0", 13, &bytes);
+
+ nsCOMPtr<nsIInputStream> iStream;
+ rv = sStream->NewInputStream(0, getter_AddRefs(iStream));
+ if (NS_FAILED(rv)) return rv;
+
+ nsCOMPtr<nsIChannel> channel;
+ rv = NS_NewInputStreamChannel(getter_AddRefs(channel), aURI,
+ iStream, mMimeType, NS_LITERAL_CSTRING(""), 0);
+ if (NS_FAILED(rv)) return rv;
+
+ NS_IF_ADDREF (*_retval = channel);
+ return rv;
+}
+
+NS_IMETHODIMP GBaseProtocolContentHandler::HandleContent (
+ const char * aContentType,
+ const char * aCommand,
+ nsISupports * aWindowContext,
+ nsIRequest *aRequest)
+{
+ nsresult rv = NS_OK;
+ if (!aRequest)
+ return NS_ERROR_NULL_POINTER;
+ // First of all, get the content type and make sure it is a
+ // content type we know how to handle!
+ if (mMimeType.Equals(aContentType))
+ {
+ nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
+ if(!channel) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIURI> uri;
+ rv = channel->GetURI(getter_AddRefs(uri));
+ if (NS_FAILED(rv)) return rv;
+
+ aRequest->Cancel(NS_BINDING_ABORTED);
+ if (uri)
+ {
+ nsCOMPtr<nsIExternalProtocolService> ps =
+ do_GetService (NS_EXTERNALPROTOCOLSERVICE_CONTRACTID, &rv);
+ if (NS_FAILED(rv) || !ps) return NS_ERROR_FAILURE;
+ ps->LoadUrl (uri);
+ }
+ }
+ return rv;
+}
diff --git a/embed/mozilla/BaseProtocolContentHandler.h b/embed/mozilla/BaseProtocolContentHandler.h
new file mode 100644
index 000000000..b1f5c1e71
--- /dev/null
+++ b/embed/mozilla/BaseProtocolContentHandler.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2001 Philip Langdale
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _BaseProtocolContentHandler_h_
+#define _BaseProtocolContentHandler_h_
+
+#include "BaseProtocolHandler.h"
+#include "nsIContentHandler.h"
+
+#include "nsString.h"
+
+class GBaseProtocolContentHandler : public GBaseProtocolHandler,
+ public nsIContentHandler
+{
+ public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSICONTENTHANDLER
+
+ NS_IMETHODIMP NewChannel(nsIURI *aURI, nsIChannel **_retval);
+
+ GBaseProtocolContentHandler (const char *aScheme);
+ virtual ~GBaseProtocolContentHandler();
+ /* additional members */
+ protected:
+ nsCString mMimeType;
+};
+
+#endif //_BaseProtocolContentHandler_h_
diff --git a/embed/mozilla/BaseProtocolHandler.cpp b/embed/mozilla/BaseProtocolHandler.cpp
new file mode 100644
index 000000000..728465a15
--- /dev/null
+++ b/embed/mozilla/BaseProtocolHandler.cpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2001 Philip Langdale
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "nsCOMPtr.h"
+#include "nsIComponentManager.h"
+#include "nsIURI.h"
+#include "nsNetCID.h"
+
+#include "BaseProtocolHandler.h"
+
+static NS_DEFINE_CID(kSimpleURICID, NS_SIMPLEURI_CID);
+
+/* Implementation file */
+NS_IMPL_ISUPPORTS1 (GBaseProtocolHandler, nsIProtocolHandler)
+
+GBaseProtocolHandler::GBaseProtocolHandler(const char *aScheme)
+{
+ NS_INIT_ISUPPORTS();
+ /* member initializers and constructor code */
+ mScheme.Assign(aScheme);
+}
+
+GBaseProtocolHandler::~GBaseProtocolHandler()
+{
+ /* destructor code */
+}
+
+/* readonly attribute string scheme; */
+NS_IMETHODIMP GBaseProtocolHandler::GetScheme(nsACString &aScheme)
+{
+ aScheme = mScheme;
+ return NS_OK;
+}
+
+/* readonly attribute long defaultPort; */
+NS_IMETHODIMP GBaseProtocolHandler::GetDefaultPort(PRInt32 *aDefaultPort)
+{
+ if (aDefaultPort)
+ *aDefaultPort = -1;
+ else
+ return NS_ERROR_NULL_POINTER;
+ return NS_OK;
+}
+
+/* readonly attribute short protocolFlags; */
+NS_IMETHODIMP GBaseProtocolHandler::GetProtocolFlags(PRUint32 *aProtocolFlags)
+{
+ if (aProtocolFlags)
+ *aProtocolFlags = nsIProtocolHandler::URI_STD;
+ else
+ return NS_ERROR_NULL_POINTER;
+ return NS_OK;
+}
+
+/* nsIURI newURI (in string aSpec, in nsIURI aBaseURI); */
+NS_IMETHODIMP GBaseProtocolHandler::NewURI(const nsACString &aSpec,
+ const char *aOriginCharset, nsIURI *aBaseURI,
+ nsIURI **_retval)
+{
+ nsresult rv = NS_OK;
+ nsCOMPtr <nsIURI> newUri;
+
+ rv = nsComponentManager::CreateInstance(kSimpleURICID, nsnull,
+ NS_GET_IID(nsIURI),
+ getter_AddRefs(newUri));
+
+ if (NS_SUCCEEDED(rv))
+ {
+ newUri->SetSpec(aSpec);
+ rv = newUri->QueryInterface(NS_GET_IID(nsIURI),
+ (void **) _retval);
+ }
+ return rv;
+
+}
+
+/* nsIChannel newChannel (in nsIURI aURI); */
+NS_IMETHODIMP GBaseProtocolHandler::NewChannel(nsIURI *aURI,
+ nsIChannel **_retval)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+/* boolean allowPort (in long port, in string scheme); */
+NS_IMETHODIMP GBaseProtocolHandler::AllowPort(PRInt32 port, const char *scheme,
+ PRBool *_retval)
+{
+ *_retval = PR_FALSE;
+ return NS_OK;
+}
+
diff --git a/embed/mozilla/BaseProtocolHandler.h b/embed/mozilla/BaseProtocolHandler.h
new file mode 100644
index 000000000..ab25a680d
--- /dev/null
+++ b/embed/mozilla/BaseProtocolHandler.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2001 Philip Langdale
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _BaseProtocolHandler_h_
+#define _BaseProtocolHandler_h_
+
+#include "nsIProtocolHandler.h"
+
+#include "nsString.h"
+
+class GBaseProtocolHandler : public nsIProtocolHandler
+{
+ public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIPROTOCOLHANDLER
+
+ GBaseProtocolHandler (const char *aScheme);
+ virtual ~GBaseProtocolHandler();
+ /* additional members */
+ protected:
+ nsCString mScheme;
+};
+
+#endif //_BaseProtocolHandler_h_
diff --git a/embed/mozilla/ContentHandler.cpp b/embed/mozilla/ContentHandler.cpp
new file mode 100644
index 000000000..9476a2f72
--- /dev/null
+++ b/embed/mozilla/ContentHandler.cpp
@@ -0,0 +1,671 @@
+/*
+ * Copyright (C) 2001 Philip Langdale
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * The functioning of the download architecture, as described by Philip
+ * on 28 May 2001 and updated on 28 June 2001:
+ *
+ * When mozilla runs into a file it cannot render internally or that it
+ * does not have a plugin for, it calls the
+ * nsIExternalHelperAppService. This service will then either attempt to
+ * save the file or run it with a helper app depending on what the
+ * mozilla mime database returns.
+ *
+ * nsIExternalHelperAppService then calls out to the nsIHelperAppDialog
+ * interface which handles the UI for the service. This is the interface
+ * which we have reimplemented. Therefore, with a major caveat, we have
+ * put a GNOME/GTK frontend on an unmodified mozilla backend.
+ *
+ * Now for the caveat. With respect to saving files to disk, the mozilla
+ * backend works exactly the same as it does in
+ * mozilla-the-browser. However, for dealing with helper apps, we do not
+ * use the mozilla backend at all. This is because we want to use the
+ * gnome-vfs database to retrieve helper-app info, rather than the
+ * mozilla helper app database.
+ *
+ * How it works:
+ *
+ * a) The user clicks on a link or follows a redirect to a file of a type
+ * that mozilla cannot handle. Mozilla passes the link to the
+ * ExternalHelperAppService which in turn calls the Show() method of
+ * nsIHelperAppDialog.
+ *
+ * b) In our implementation of Show() we first compare the passed mime
+ * type to epiphany's mime list. If the mime type is in the list, we then
+ * lookup the Action associated with the mime type. Currently, the
+ * possible mime-actions are:
+ *
+ * Save to Disk
+ * Run with Helper App
+ * Ask User
+ *
+ * The default action is Ask User, and if the mime-type is not in our
+ * list, this is what will be assumed.
+ *
+ * c) If Ask User is the chosen action, a dialog will be shown to the
+ * user allowing the user to choose from the other two possible actions
+ * as well as a checkbox to let the user set the default action to the
+ * chosen action for the future.
+ *
+ * d-1) The "Save to Disk" action. We first check epiphany preferences to
+ * see if the user wants to use the built-in mozilla downloader, gtm or
+ * a command-line executed downloader.
+ *
+ * d-2a) The built-in downloader. This action is handled by the mozilla
+ * backend. Our nsIHelperAppDialog does the same thing that the
+ * mozilla-the-browser one does, which is to call the SaveToDisk() method
+ * of nsIExternalHelperAppService. This in turn calls the
+ * PromptForSaveToFile() method of nsIHelperAppDialog putting the ball
+ * back in our court.
+ *
+ * d-2b) Now, if epiphany is configured to always ask for a download
+ * directory, it will pop up a file selector so that the user can select
+ * the directory and filename to save the file to. Otherwise, it will
+ * use epiphany's default download directory and proceed without
+ * interaction.
+ *
+ * d-2c) When PromptForSaveToFile() returns, nsIExternalHelperAppService
+ * will then call the ShowProgressDialog() method of
+ * nsIHelperAppDialog. This progress dialog, obviously, tracks the
+ * progress of the download. It is worth noting that mozilla starts the
+ * actual download as soon as the user clicks on the link or follows the
+ * redirect. While the user is deciding what action to take, the file is
+ * downloading. Often, for small files, the file is already downloaded
+ * when the user decides what directory to put it in. The progress dialog
+ * does not appear in these cases. Also, we currently have a small
+ * problem where our progress dialog times the download from the point
+ * the dialog appears, not from the time the download starts. This is due
+ * to the timestamp that is passed to us is just plain weird, and I
+ * haven't worked out how to turn it into a useable time. The fact that
+ * the download starts early means that the file is actually downloaded
+ * to a temp file and only at the end is it moved to it's final location.
+ *
+ * d-3a) The two external downloader options. These options are
+ * handled completely by epiphany. The first thing that we do is call the
+ * Cancel() method of nsIExternalHelperAppService to cancel the mozilla
+ * download. We then pass the url to our own LaunchExternalDownloader()
+ * method. This method will ask for a download directory as appropriate
+ * as with the "Save to disk" action.
+ *
+ * d-3b) Finally, depending on whether GTM or a command line handler was
+ * selected in prefs, the external handler will be called with the url
+ * passed and the directory selected.
+ *
+ * e-1) The "Run with Helper App" action. This action is currently only
+ * working with a minimal implementation. First, we explicitly call
+ * ShowProgressDialog() so the user knows that the file is being
+ * downloaded. We also need this so that we only run the helper after the
+ * file is completely downloaded. The file will download to temp location
+ * that it would be moved from if the action was "Save to Disk". We have
+ * to call ShowProgressDialog() ourselves because we are not using
+ * mozilla's helper mechanism which would usually make the call for us.
+ *
+ * e-2) If there is a default helper app in our mime database and alwaysAsk
+ * is false, epiphany will run the default helper automatically. Otherwise it
+ * will pop up a helper chooser dialog which lists the helpers that gnome-vfs
+ * knows about as well as providing a GnomeFileEntry to allow the user to
+ * select and arbitrary application. The default value of the GnomeFileEntry
+ * is the helper stored in our database if one exits.
+ *
+ * f) General notes. We cannot use this infrastructure to override
+ * native mozilla types. mozilla will attempt to render these types and
+ * never call out to us. We are at the end of the chain as the handler of
+ * last resort, so native and plugin types will never reach us. This also
+ * means that a file with an incorrect mime-type ( eg: .tar.bz2 marked as
+ * text/plain ) will be incorrectly rendered by mozilla. We cannot help
+ * this.
+ *
+ * Despite the apparent user-side similarity with explicit downloads by
+ * a shift-click or context-menu item, there is actually none at all.
+ * Explicit downloads are handled by the nsIStreamTransfer manager which
+ * we use as is. Currently the progress dialog for the stream transfer
+ * manager is un-overridable, so it appears in XUL. This will change in
+ * due course.
+ *
+ * Matt would like the modifiy the progress dialog so each file currently
+ * being downloaded becomes a clist entry in a master dialog rather than
+ * causing a separate progress dialog. a lot of progress dialogs gets
+ * really messy.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+extern "C" {
+#include "libgnomevfs/gnome-vfs-mime-handlers.h"
+}
+
+#include "ephy-embed-shell.h"
+#include "ephy-prefs.h"
+#include "eel-gconf-extensions.h"
+#include "ephy-glade.h"
+#include "ephy-string.h"
+#include "ephy-gui.h"
+#include "ephy-embed-utils.h"
+#include "ephy-file-helpers.h"
+#include "ProgressListener.h"
+#include "ContentHandler.h"
+
+#include <gtk/gtkentry.h>
+#include <gtk/gtktogglebutton.h>
+#include <gtk/gtkprogress.h>
+#include <gtk/gtkoptionmenu.h>
+#include <libgnome/gnome-exec.h>
+#include <libgnome/gnome-i18n.h>
+#include <libgnome/gnome-config.h>
+#include <libgnome/gnome-util.h>
+#include <libgnomevfs/gnome-vfs-mime.h>
+
+#include "FilePicker.h"
+#include "MozillaPrivate.h"
+
+#include "nsCRT.h"
+#include "nsCOMPtr.h"
+#include "nsIFactory.h"
+#include "nsISupportsArray.h"
+#include "nsIServiceManager.h"
+#include "nsWeakReference.h"
+#include "nsXPComFactory.h"
+
+#include "nsString.h"
+#include "nsIURI.h"
+#include "nsIURL.h"
+#include "nsIMIMEInfo.h"
+#include "nsIChannel.h"
+#include "nsIFTPChannel.h"
+#include "nsILocalFile.h"
+#include "nsIPrefService.h"
+#include "nsIDOMWindow.h"
+#include "nsIDOMWindowInternal.h"
+
+class GContentHandler;
+class GDownloadProgressListener;
+struct MimeAskActionDialog;
+struct HelperAppChooserDialog;
+
+extern "C"
+void mime_ask_dialog_save_clicked_cb (GtkButton *button,
+ MimeAskActionDialog *dialog);
+extern "C"
+void mime_ask_dialog_open_clicked_cb (GtkButton *button,
+ MimeAskActionDialog *dialog);
+extern "C"
+gint mime_ask_dialog_cancel_clicked_cb (GtkButton *button,
+ MimeAskActionDialog *dialog);
+
+/*
+ * MimeAskActionDialog: the representation of dialogs used to ask
+ * about actions on MIME types
+ */
+struct MimeAskActionDialog
+{
+ MimeAskActionDialog(GContentHandler *aContentHandler,
+ GtkWidget *aParentWidget,
+ const char *aMimeType);
+ ~MimeAskActionDialog();
+
+ GContentHandler *mContentHandler;
+ GladeXML *mGXml;
+ GtkWidget *mParent;
+ GtkWidget *mAppMenu;
+
+ GnomeVFSMimeApplication *mDefaultApp;
+};
+
+/* Implementation file */
+NS_IMPL_ISUPPORTS1(GContentHandler, nsIHelperAppLauncherDialog)
+
+GContentHandler::GContentHandler() : mUri(nsnull),
+ mMimeType(nsnull),
+ mDownloadCanceled(PR_FALSE),
+ mHelperProgress(PR_FALSE)
+{
+ NS_INIT_ISUPPORTS();
+ /* member initializers and constructor code */
+}
+
+GContentHandler::~GContentHandler()
+{
+ /* destructor code */
+ g_free (mUri);
+ g_free (mMimeType);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// begin nsIHelperAppLauncher impl
+////////////////////////////////////////////////////////////////////////////////
+
+/* void show (in nsIHelperAppLauncher aLauncher, in nsISupports aContext); */
+NS_IMETHODIMP GContentHandler::Show(nsIHelperAppLauncher *aLauncher,
+ nsISupports *aContext)
+{
+ nsresult rv;
+
+ mLauncher = aLauncher;
+ mContext = aContext;
+ rv = Init ();
+
+ MIMEAskAction ();
+
+ return NS_OK;
+}
+
+/* nsILocalFile promptForSaveToFile (in nsISupports aWindowContext, in wstring aDefaultFile, in wstring aSuggestedFileExtension); */
+NS_IMETHODIMP GContentHandler::
+ PromptForSaveToFile(nsISupports *aWindowContext,
+ const PRUnichar *aDefaultFile,
+ const PRUnichar *aSuggestedFileExtension,
+ nsILocalFile **_retval)
+{
+ nsresult rv;
+
+ mContext = aWindowContext;
+
+ nsCOMPtr<nsIDOMWindowInternal> windowInternal =
+ do_QueryInterface (aWindowContext);
+
+ nsCOMPtr<nsILocalFile> saveDir;
+ char *dirName;
+
+ /* FIXME persist download dir */
+ dirName = g_strdup (g_get_home_dir());
+
+ saveDir = do_CreateInstance (NS_LOCAL_FILE_CONTRACTID);
+ saveDir->InitWithPath (NS_ConvertUTF8toUCS2(dirName));
+ g_free (dirName);
+
+ nsCOMPtr <nsILocalFile> saveFile (do_CreateInstance(NS_LOCAL_FILE_CONTRACTID));
+
+ PRInt16 okToSave = nsIFilePicker::returnCancel;
+
+ if (okToSave == nsIFilePicker::returnCancel)
+ {
+ nsCOMPtr<nsIFilePicker> filePicker =
+ do_CreateInstance (G_FILEPICKER_CONTRACTID);
+
+ const nsAString &title = NS_ConvertUTF8toUCS2(_("Select the destination filename"));
+
+ filePicker->Init (windowInternal,
+ PromiseFlatString(title).get(),
+ nsIFilePicker::modeSave);
+ filePicker->SetDefaultString (aDefaultFile);
+ filePicker->SetDisplayDirectory (saveDir);
+
+ filePicker->Show (&okToSave);
+
+ if (okToSave == nsIFilePicker::returnOK)
+ {
+ filePicker->GetFile (getter_AddRefs(saveFile));
+ }
+ }
+
+ if (okToSave == nsIFilePicker::returnCancel)
+ return NS_ERROR_FAILURE;
+ else
+ {
+ nsCOMPtr<nsIFile> directory;
+ rv = saveFile->GetParent (getter_AddRefs(directory));
+
+ NS_IF_ADDREF (*_retval = saveFile);
+ return NS_OK;
+ }
+}
+
+/* void showProgressDialog (in nsIHelperAppLauncher aLauncher, in nsISupports aContext); */
+NS_METHOD GContentHandler::ShowProgressDialog(nsIHelperAppLauncher *aLauncher,
+ nsISupports *aContext)
+{
+ g_print ("GContentHandler::ShowProgressDialog is depreciated!\n");
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// begin local public methods impl
+////////////////////////////////////////////////////////////////////////////////
+
+NS_METHOD GContentHandler::FindHelperApp (void)
+{
+ if (mUrlHelper)
+ {
+ return LaunchHelperApp ();
+ }
+ else
+ {
+ if (NS_SUCCEEDED(SynchroniseMIMEInfo()))
+ {
+ return mLauncher->LaunchWithApplication(nsnull, PR_FALSE);
+ }
+ else
+ {
+ return NS_ERROR_FAILURE;
+ }
+ }
+}
+
+NS_METHOD GContentHandler::LaunchHelperApp (void)
+{
+ if (mMimeType)
+ {
+ nsresult rv;
+ nsCOMPtr<nsIExternalHelperAppService> helperService =
+ do_GetService (NS_EXTERNALHELPERAPPSERVICE_CONTRACTID);
+
+ nsCOMPtr<nsPIExternalAppLauncher> appLauncher =
+ do_QueryInterface (helperService, &rv);
+ if (NS_SUCCEEDED(rv))
+ {
+ appLauncher->DeleteTemporaryFileOnExit(mTempFile);
+ }
+
+ nsString uFileName;
+ mTempFile->GetPath(uFileName);
+ const nsCString &aFileName = NS_ConvertUCS2toUTF8(uFileName);
+
+ const nsCString &document = (mUrlHelper) ? mUrl : aFileName;
+
+ char *param = g_strdup (document.get());
+ ephy_file_launch_application (mHelperApp->command,
+ param,
+ mHelperApp->requires_terminal);
+
+ if(mUrlHelper) mLauncher->Cancel();
+
+ g_free (param);
+ }
+ else
+ {
+ mLauncher->Cancel ();
+ }
+
+ return NS_OK;
+}
+
+NS_METHOD GContentHandler::ShowHelperProgressDialog (void)
+{
+ mHelperProgress = PR_TRUE;
+ return ShowProgressDialog (mLauncher,mContext);
+}
+
+NS_METHOD GContentHandler::GetLauncher (nsIHelperAppLauncher * *_retval)
+{
+ NS_IF_ADDREF (*_retval = mLauncher);
+ return NS_OK;
+}
+
+NS_METHOD GContentHandler::GetContext (nsISupports * *_retval)
+{
+ NS_IF_ADDREF (*_retval = mContext);
+ return NS_OK;
+}
+
+static gboolean
+application_support_scheme (GnomeVFSMimeApplication *app, const nsCString &aScheme)
+{
+ GList *l;
+
+ g_return_val_if_fail (app != NULL, FALSE);
+ g_return_val_if_fail (!aScheme.IsEmpty(), FALSE);
+
+ if (app->expects_uris != GNOME_VFS_MIME_APPLICATION_ARGUMENT_TYPE_URIS)
+ return FALSE;
+
+ for (l = app->supported_uri_schemes; l != NULL; l = l->next)
+ {
+ char *uri_scheme = (char *)l->data;
+ g_return_val_if_fail (uri_scheme != NULL, FALSE);
+ if (aScheme.Equals(uri_scheme)) return TRUE;
+ }
+
+ return FALSE;
+}
+
+NS_METHOD GContentHandler::SetHelperApp(GnomeVFSMimeApplication *aHelperApp,
+ PRBool alwaysUse)
+{
+ mHelperApp = aHelperApp;
+ mUrlHelper = application_support_scheme (aHelperApp, mScheme);
+
+ return NS_OK;
+}
+
+NS_METHOD GContentHandler::SynchroniseMIMEInfo (void)
+{
+ nsresult rv;
+ nsCOMPtr<nsIMIMEInfo> mimeInfo;
+ rv = mLauncher->GetMIMEInfo(getter_AddRefs(mimeInfo));
+ if(NS_FAILED(rv)) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsILocalFile> helperFile;
+ rv = NS_NewNativeLocalFile(nsDependentCString(mHelperApp->command),
+ PR_TRUE,
+ getter_AddRefs(helperFile));
+ if(NS_FAILED(rv)) return NS_ERROR_FAILURE;
+
+ rv = mimeInfo->SetPreferredApplicationHandler(helperFile);
+ if(NS_FAILED(rv)) return NS_ERROR_FAILURE;
+
+ nsMIMEInfoHandleAction mimeInfoAction;
+ mimeInfoAction = nsIMIMEInfo::alwaysAsk;
+
+ if(mHelperApp->requires_terminal) //Information passing kludge!
+ {
+ rv = mimeInfo->SetApplicationDescription
+ (NS_LITERAL_STRING("runInTerminal").get());
+ if(NS_FAILED(rv)) return NS_ERROR_FAILURE;
+ }
+
+ rv = mimeInfo->SetPreferredAction(mimeInfoAction);
+ if(NS_FAILED(rv)) return NS_ERROR_FAILURE;
+
+ return NS_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// begin local private methods impl
+////////////////////////////////////////////////////////////////////////////////
+NS_METHOD GContentHandler::Init (void)
+{
+ nsresult rv;
+
+ nsCOMPtr<nsIMIMEInfo> MIMEInfo;
+ rv = mLauncher->GetMIMEInfo (getter_AddRefs(MIMEInfo));
+ rv = MIMEInfo->GetMIMEType (&mMimeType);
+
+ rv = mLauncher->GetDownloadInfo(getter_AddRefs(mUri),
+ &mTimeDownloadStarted,
+ getter_AddRefs(mTempFile));
+ rv = mUri->GetSpec (mUrl);
+ rv = mUri->GetScheme (mScheme);
+#if 0
+ /* GetSource seems redundant and isn't in 0.9 This code is here while
+ it remains unclear what GetSource is for. --phil */
+ nsCOMPtr<nsIURI> uri;
+ rv = mLauncher->GetSource(getter_AddRefs(uri));
+ rv = uri->GetSpec (mUrl);
+#endif
+ ProcessMimeInfo ();
+
+ return NS_OK;
+}
+
+NS_METHOD GContentHandler::ProcessMimeInfo (void)
+{
+ if (mMimeType == NULL ||
+ !nsCRT::strcmp(mMimeType, "application/octet-stream"))
+ {
+ nsresult rv;
+ nsCOMPtr<nsIURL> url = do_QueryInterface(mUri, &rv);
+ if (NS_SUCCEEDED(rv) && url)
+ {
+ nsCAutoString uriFileName;
+ url->GetFileName(uriFileName);
+ mMimeType = g_strdup
+ (gnome_vfs_mime_type_from_name
+ (uriFileName.get()));
+ }
+ else
+ mMimeType = g_strdup ("application/octet-stream");
+ }
+
+ return NS_OK;
+}
+
+NS_METHOD GContentHandler::MIMEAskAction (void)
+{
+ nsCOMPtr<nsIDOMWindow> parent = do_QueryInterface (mContext);
+ GtkWidget *parentWidget = MozillaFindGtkParent (parent);
+
+ new MimeAskActionDialog(this, parentWidget, mMimeType);
+
+ return NS_OK;
+}
+
+//------------------------------------------------------------------------------
+
+NS_DEF_FACTORY (GContentHandler, GContentHandler);
+
+/**
+ * NS_NewContentHandlerFactory:
+ */
+nsresult NS_NewContentHandlerFactory(nsIFactory** aFactory)
+{
+ NS_ENSURE_ARG_POINTER(aFactory);
+ *aFactory = nsnull;
+
+ nsGContentHandlerFactory *result = new nsGContentHandlerFactory;
+ if (result == NULL)
+ {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+
+ NS_ADDREF(result);
+ *aFactory = result;
+
+ return NS_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// begin MIMEAskActionDialog methods.
+////////////////////////////////////////////////////////////////////////////////
+
+MimeAskActionDialog::MimeAskActionDialog(GContentHandler *aContentHandler,
+ GtkWidget *aParentWidget,
+ const char *aMimeType) :
+ mContentHandler(aContentHandler),
+ mParent(aParentWidget)
+{
+ GtkWidget *label;
+ GtkWidget *dialogWidget;
+ const char *description;
+ char ltext[255]; //philipl: Fixed length buffer == potential security problem...
+
+ mGXml = ephy_glade_widget_new ("epiphany.glade", "mime_ask_action_dialog",
+ &dialogWidget, this);
+ mAppMenu = glade_xml_get_widget (mGXml, "mime_ask_dialog_app_menu");
+
+ mDefaultApp = gnome_vfs_mime_get_default_application(aMimeType);
+
+ GtkWidget *aMimeIcon = glade_xml_get_widget (mGXml,
+ "mime_ask_action_icon");
+ gtk_image_set_from_file(GTK_IMAGE(aMimeIcon),
+ gnome_vfs_mime_get_icon(aMimeType));
+
+ description = gnome_vfs_mime_get_description (aMimeType);
+ if (!description) description = aMimeType;
+
+ g_snprintf (ltext, 255, "<b>%s</b>", description);
+ label = glade_xml_get_widget (mGXml, "mime_ask_action_description");
+ gtk_label_set_markup (GTK_LABEL (label), ltext);
+
+ gtk_window_set_transient_for (GTK_WINDOW (dialogWidget),
+ GTK_WINDOW (aParentWidget));
+
+ gtk_widget_show(dialogWidget);
+}
+
+MimeAskActionDialog::~MimeAskActionDialog()
+{
+#if 0
+ if(mApps)
+ gnome_vfs_mime_application_list_free(mApps);
+#endif
+
+ gtk_widget_destroy(glade_xml_get_widget(mGXml, "mime_ask_action_dialog"));
+ g_object_unref(G_OBJECT(mGXml));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// begin MIMEAskActionDialog callbacks.
+////////////////////////////////////////////////////////////////////////////////
+
+extern "C" void
+mime_ask_dialog_save_clicked_cb (GtkButton *button, MimeAskActionDialog *dialog)
+{
+ gtk_widget_hide (glade_xml_get_widget (dialog->mGXml,
+ "mime_ask_action_dialog"));
+
+ nsresult rv;
+ nsCOMPtr<nsIHelperAppLauncher> launcher;
+ rv = dialog->mContentHandler->GetLauncher (getter_AddRefs(launcher));
+
+ launcher->SaveToDisk (nsnull,PR_FALSE);
+
+ delete dialog;
+}
+
+static void
+mime_ask_dialog_download_cancel (MimeAskActionDialog *dialog)
+{
+ nsresult rv;
+ nsCOMPtr<nsIHelperAppLauncher> launcher;
+ rv = dialog->mContentHandler->GetLauncher (getter_AddRefs(launcher));
+
+ launcher->Cancel ();
+
+ delete dialog;
+}
+
+extern "C" void
+mime_ask_dialog_open_clicked_cb (GtkButton *button, MimeAskActionDialog *dialog)
+{
+ nsresult rv;
+ nsCOMPtr<nsIHelperAppLauncher> launcher;
+ rv = dialog->mContentHandler->GetLauncher (getter_AddRefs(launcher));
+ GnomeVFSMimeApplication *app = dialog->mDefaultApp;
+
+ if (app)
+ {
+ dialog->mContentHandler->SetHelperApp (app, FALSE);
+ dialog->mContentHandler->FindHelperApp ();
+ delete dialog;
+ }
+ else
+ {
+ mime_ask_dialog_download_cancel (dialog);
+ ephy_embed_utils_nohandler_dialog_run (dialog->mParent);
+ }
+}
+
+extern "C" gint
+mime_ask_dialog_cancel_clicked_cb (GtkButton *button,
+ MimeAskActionDialog *dialog)
+{
+ mime_ask_dialog_download_cancel (dialog);
+ return 0; /* FIXME: philipl, is this the right thing to return? */
+}
diff --git a/embed/mozilla/ContentHandler.h b/embed/mozilla/ContentHandler.h
new file mode 100644
index 000000000..6ae61f657
--- /dev/null
+++ b/embed/mozilla/ContentHandler.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2000 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __ContentHandler_h
+#define __ContentHandler_h
+
+#include "mozilla-embed-shell.h"
+
+#include <libgnomevfs/gnome-vfs-mime-handlers.h>
+#include "nsIHelperAppLauncherDialog.h"
+#include "nsIExternalHelperAppService.h"
+#include "nsCExternalHandlerService.h"
+#include "nsIWebProgressListener.h"
+
+#include "nsString.h"
+#include "nsIURI.h"
+#include "nsILocalFile.h"
+
+#include "nsCOMPtr.h"
+#include "nsISupports.h"
+#include "nsError.h"
+
+typedef enum
+{
+ ACTION_NONE,
+ ACTION_SAVEFORHELPER,
+ ACTION_OBJECT_NOTIFY
+} DownloadAction;
+
+#define G_CONTENTHANDLER_CID \
+{ /* 16072c4a-23a6-4996-9beb-9335c06bbeae */ \
+ 0x16072c4a, \
+ 0x23a6, \
+ 0x4996, \
+ {0x9b, 0xeb, 0x93, 0x35, 0xc0, 0x6b, 0xbe, 0xae} \
+}
+
+class nsIFactory;
+
+class GContentHandler : public nsIHelperAppLauncherDialog
+{
+ public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIHELPERAPPLAUNCHERDIALOG
+
+ GContentHandler();
+ virtual ~GContentHandler();
+
+ NS_METHOD FindHelperApp (void);
+ NS_METHOD LaunchHelperApp (void);
+ NS_METHOD ShowHelperProgressDialog (void);
+
+ NS_METHOD GetLauncher (nsIHelperAppLauncher * *_retval);
+ NS_METHOD GetContext (nsISupports * *_retval);
+ NS_METHOD SetHelperApp(GnomeVFSMimeApplication *mHelperApp,
+ PRBool alwaysUse);
+ NS_METHOD SynchroniseMIMEInfo (void);
+
+ private:
+ /* additional members */
+ NS_METHOD Init (void);
+ NS_METHOD ProcessMimeInfo (void);
+ NS_METHOD MIMEAskAction (void);
+
+ nsCOMPtr<nsIHelperAppLauncher> mLauncher;
+ nsCOMPtr<nsISupports> mContext;
+
+ nsCOMPtr<nsIURI> mUri;
+ PRInt64 mTimeDownloadStarted;
+ nsCOMPtr<nsIFile> mTempFile;
+
+ char *mMimeType;
+ PRBool mUrlHelper;
+ GnomeVFSMimeApplication *mHelperApp;
+
+ nsCString mUrl;
+ nsCString mScheme;
+
+ PRBool mDownloadCanceled;
+ PRBool mHelperProgress;
+
+ nsCOMPtr<nsIWebProgressListener> mListener;
+};
+
+extern nsresult NS_NewContentHandlerFactory(nsIFactory** aFactory);
+
+#endif
diff --git a/embed/mozilla/EphyEventListener.cpp b/embed/mozilla/EphyEventListener.cpp
new file mode 100644
index 000000000..de696bf1e
--- /dev/null
+++ b/embed/mozilla/EphyEventListener.cpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2000 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <nsCOMPtr.h>
+
+#include "EphyEventListener.h"
+#include "nsIDOMNode.h"
+#include "nsIDOMElement.h"
+#include "nsString.h"
+#include "nsUnicharUtils.h"
+#include "nsIDOMDocument.h"
+#include "nsIURI.h"
+#include "nsIDocument.h"
+#include "nsIDOMEventTarget.h"
+#include "nsIDOMEvent.h"
+
+EphyEventListener::EphyEventListener(void)
+{
+ NS_INIT_ISUPPORTS();
+ mOwner = nsnull;
+}
+
+EphyEventListener::~EphyEventListener()
+{
+}
+
+NS_IMPL_ISUPPORTS1(EphyEventListener, nsIDOMEventListener)
+
+nsresult
+EphyEventListener::Init(EphyEmbed *aOwner)
+{
+ mOwner = aOwner;
+ return NS_OK;
+}
+
+nsresult
+EphyEventListener::HandleFaviconLink (nsIDOMNode *node)
+{
+ nsresult result;
+
+ nsCOMPtr<nsIDOMElement> linkElement;
+ linkElement = do_QueryInterface (node);
+ if (!linkElement) return NS_ERROR_FAILURE;
+
+ NS_NAMED_LITERAL_STRING(attr_rel, "rel");
+ nsAutoString value;
+ result = linkElement->GetAttribute (attr_rel, value);
+ if (NS_FAILED(result)) return NS_ERROR_FAILURE;
+
+ if (value.Equals(NS_LITERAL_STRING("SHORTCUT ICON"),
+ nsCaseInsensitiveStringComparator()) ||
+ value.Equals(NS_LITERAL_STRING("ICON"),
+ nsCaseInsensitiveStringComparator()))
+ {
+ NS_NAMED_LITERAL_STRING(attr_href, "href");
+ nsAutoString value;
+ result = linkElement->GetAttribute (attr_href, value);
+ if (NS_FAILED (result) || value.IsEmpty())
+ return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIDOMDocument> domDoc;
+ result = node->GetOwnerDocument(getter_AddRefs(domDoc));
+ if (NS_FAILED(result) || !domDoc) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIDocument> doc = do_QueryInterface (domDoc);
+ if(!doc) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIURI> uri;
+ result = doc->GetDocumentURL(getter_AddRefs(uri));
+ if (NS_FAILED (result)) return NS_ERROR_FAILURE;
+
+ const nsACString &link = NS_ConvertUCS2toUTF8(value);
+ nsCAutoString favicon_url;
+ result = uri->Resolve (link, favicon_url);
+ if (NS_FAILED (result)) return NS_ERROR_FAILURE;
+
+ char *url = g_strdup (favicon_url.get());
+ g_signal_emit_by_name (mOwner, "ge_favicon", url);
+ g_free (url);
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+EphyEventListener::HandleEvent(nsIDOMEvent* aDOMEvent)
+{
+ nsCOMPtr<nsIDOMEventTarget> eventTarget;
+
+ aDOMEvent->GetTarget(getter_AddRefs(eventTarget));
+
+ nsresult result;
+ nsCOMPtr<nsIDOMNode> node = do_QueryInterface(eventTarget, &result);
+ if (NS_FAILED(result) || !node) return NS_ERROR_FAILURE;
+
+ HandleFaviconLink (node);
+
+ return NS_OK;
+}
diff --git a/embed/mozilla/EphyEventListener.h b/embed/mozilla/EphyEventListener.h
new file mode 100644
index 000000000..32f84e904
--- /dev/null
+++ b/embed/mozilla/EphyEventListener.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2000 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EPHY_EVENT_LISTENER_H
+#define EPHY_EVENT_LISTENER_H
+
+#include "ephy-embed.h"
+
+#include <nsIDOMEventListener.h>
+
+class EphyEventListener : public nsIDOMEventListener
+{
+public:
+ EphyEventListener();
+ virtual ~EphyEventListener();
+
+ nsresult Init(EphyEmbed *aOwner);
+
+ NS_DECL_ISUPPORTS
+
+ // nsIDOMEventListener
+
+ NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent);
+
+private:
+ EphyEmbed *mOwner;
+
+ nsresult HandleFaviconLink (nsIDOMNode *node);
+};
+
+#endif
diff --git a/embed/mozilla/EphyWrapper.cpp b/embed/mozilla/EphyWrapper.cpp
new file mode 100644
index 000000000..ade9e67b2
--- /dev/null
+++ b/embed/mozilla/EphyWrapper.cpp
@@ -0,0 +1,1384 @@
+/*
+ * Copyright (C) 2000 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "EphyWrapper.h"
+#include "GlobalHistory.h"
+#include "ProgressListener.h"
+#include "PrintProgressListener.h"
+#include "ephy-embed.h"
+#include "ephy-string.h"
+
+#include <gtkmozembed_internal.h>
+#include <unistd.h>
+
+#include "nsIContentViewer.h"
+#include "nsIPermissionManager.h"
+#include "nsIGlobalHistory.h"
+#include "nsIDocShellHistory.h"
+#include "nsIWebBrowserFind.h"
+#include "nsIWebBrowserFocus.h"
+#include "nsIDocument.h"
+#include "nsISHEntry.h"
+#include "nsISHistoryInternal.h"
+#include "nsIHistoryEntry.h"
+#include "nsIWebBrowserPrint.h"
+#include "nsIURI.h"
+#include "nsIPresShell.h"
+#include "nsIMarkupDocumentViewer.h"
+#include "nsIComponentManager.h"
+#include "nsIDOMElement.h"
+#include "nsIDOMNodeList.h"
+#include "nsIScriptGlobalObject.h"
+#include "nsIScriptContext.h"
+
+#include "nsIDOMWindowInternal.h"
+#include "nsICharsetConverterManager.h"
+#include "nsICharsetConverterManager2.h"
+#include "nsIInterfaceRequestor.h"
+#include "nsIFocusController.h"
+#include "nsIWebBrowserPersist.h"
+#include "nsCWebBrowserPersist.h"
+#include "nsNetUtil.h"
+#include "nsIChromeEventHandler.h"
+#include "nsIClipboardCommands.h"
+#include "nsIDOMDocumentStyle.h"
+#include "nsIDocShellTreeItem.h"
+#include "nsIDocShellTreeNode.h"
+#include "nsIDocShellTreeOwner.h"
+#include "nsIHTMLContentContainer.h"
+#include "nsICSSLoader.h"
+#include "nsICSSStyleSheet.h"
+#include "nsICSSLoaderObserver.h"
+#include "nsIStyleSet.h"
+#include "nsIDocumentObserver.h"
+#include "nsCWebBrowser.h"
+#include "nsReadableUtils.h"
+#include "nsUnicharUtils.h"
+#include "nsIDOMNSHTMLDocument.h"
+#include "nsIDOMHTMLDocument.h"
+#include "nsIDOMHTMLCollection.h"
+#include "nsIDOMHTMLElement.h"
+#include "nsIDOMHTMLImageElement.h"
+#include "nsIDOMHTMLFormElement.h"
+#include "nsIDOMHTMLAnchorElement.h"
+#include "caps/nsIPrincipal.h"
+#include "nsIDeviceContext.h"
+#include "nsIPresContext.h"
+#include "ContentHandler.h"
+#include "nsITypeAheadFind.h"
+#include "nsSupportsPrimitives.h"
+#include "EphyEventListener.h"
+
+EphyWrapper::EphyWrapper ()
+{
+}
+
+EphyWrapper::~EphyWrapper ()
+{
+}
+
+nsresult EphyWrapper::Init (GtkMozEmbed *mozembed)
+{
+ nsresult result;
+
+ gtk_moz_embed_get_nsIWebBrowser (mozembed,
+ getter_AddRefs(mWebBrowser));
+ if (!mWebBrowser) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIDocShell> DocShell;
+ result = GetDocShell (getter_AddRefs(DocShell));
+ if (NS_FAILED(result) || !DocShell) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIDocShellHistory> dsHistory = do_QueryInterface (DocShell);
+ if (!dsHistory) return NS_ERROR_FAILURE;
+
+ static NS_DEFINE_CID(kGlobalHistoryCID, GALEON_GLOBALHISTORY_CID);
+
+ nsCOMPtr<nsIFactory> GHFactory;
+ result = NS_NewGlobalHistoryFactory(getter_AddRefs(GHFactory));
+ if (NS_FAILED(result)) return NS_ERROR_FAILURE;
+
+ result = nsComponentManager::RegisterFactory(kGlobalHistoryCID,
+ "Global history",
+ NS_GLOBALHISTORY_CONTRACTID,
+ GHFactory,
+ PR_TRUE);
+
+ nsCOMPtr<nsIGlobalHistory> inst =
+ do_GetService(NS_GLOBALHISTORY_CONTRACTID, &result);
+
+ mEventListener = new EphyEventListener();
+ mEventListener->Init (EPHY_EMBED (mozembed));
+ GetListener();
+ AttachListeners();
+
+ return dsHistory->SetGlobalHistory(inst);
+}
+
+void
+EphyWrapper::GetListener (void)
+{
+ if (mEventReceiver) return;
+
+ nsCOMPtr<nsIDOMWindow> domWindowExternal;
+ mWebBrowser->GetContentDOMWindow(getter_AddRefs(domWindowExternal));
+
+ nsCOMPtr<nsIDOMWindowInternal> domWindow;
+ domWindow = do_QueryInterface(domWindowExternal);
+
+ nsCOMPtr<nsPIDOMWindow> piWin(do_QueryInterface(domWindow));
+ if (!piWin) return;
+
+ nsCOMPtr<nsIChromeEventHandler> chromeHandler;
+ piWin->GetChromeEventHandler(getter_AddRefs(chromeHandler));
+
+ mEventReceiver = do_QueryInterface(chromeHandler);
+}
+
+void
+EphyWrapper::AttachListeners(void)
+{
+ if (!mEventReceiver || mListenersAttached)
+ return;
+
+ nsCOMPtr<nsIDOMEventTarget> target;
+ target = do_QueryInterface (mEventReceiver);
+
+ target->AddEventListener(NS_LITERAL_STRING("DOMLinkAdded"), mEventListener, PR_FALSE);
+
+ mListenersAttached = PR_TRUE;
+}
+
+void
+EphyWrapper::DetachListeners(void)
+{
+ if (!mListenersAttached || !mEventReceiver)
+ return;
+
+ nsCOMPtr<nsIDOMEventTarget> target;
+ target = do_QueryInterface (mEventReceiver);
+
+ target->RemoveEventListener(NS_LITERAL_STRING("DOMLinkAdded"), mEventListener, PR_FALSE);
+}
+
+nsresult EphyWrapper::GetDocShell (nsIDocShell **aDocShell)
+{
+ nsCOMPtr<nsIDocShellTreeItem> browserAsItem;
+ browserAsItem = do_QueryInterface(mWebBrowser);
+ if (!browserAsItem) return NS_ERROR_FAILURE;
+
+ // get the owner for that item
+ nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
+ browserAsItem->GetTreeOwner(getter_AddRefs(treeOwner));
+ if (!treeOwner) return NS_ERROR_FAILURE;
+
+ // get the primary content shell as an item
+ nsCOMPtr<nsIDocShellTreeItem> contentItem;
+ treeOwner->GetPrimaryContentShell(getter_AddRefs(contentItem));
+ if (!contentItem) return NS_ERROR_FAILURE;
+
+ // QI that back to a docshell
+ nsCOMPtr<nsIDocShell> DocShell;
+ DocShell = do_QueryInterface(contentItem);
+ if (!DocShell) return NS_ERROR_FAILURE;
+
+ *aDocShell = DocShell.get();
+
+ NS_IF_ADDREF(*aDocShell);
+
+ return NS_OK;
+}
+nsresult EphyWrapper::Print (nsIPrintSettings *options, PRBool preview)
+{
+ nsresult result;
+
+ nsCOMPtr<nsIWebBrowserPrint> print(do_GetInterface(mWebBrowser, &result));
+ if (NS_FAILED(result) || !print) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIDOMWindow> DOMWindow;
+ result = mWebBrowser->GetContentDOMWindow (getter_AddRefs(DOMWindow));
+ if (NS_FAILED(result) || !DOMWindow) return NS_ERROR_FAILURE;
+
+ if (!preview)
+ {
+ GPrintListener *listener = new GPrintListener();
+ result = print->Print (options, listener);
+ }
+ else
+ {
+ result = print->PrintPreview(options, nsnull, nsnull);
+ }
+
+ return result;
+}
+
+nsresult EphyWrapper::PrintPreviewClose (void)
+{
+ nsresult rv;
+ PRBool isPreview = PR_FALSE;
+
+ nsCOMPtr<nsIWebBrowserPrint> print(do_GetInterface(mWebBrowser, &rv));
+ if (NS_FAILED(rv) || !print) return NS_ERROR_FAILURE;
+
+ rv = print->GetDoingPrintPreview(&isPreview);
+ if (isPreview == PR_TRUE)
+ {
+ rv = print->ExitPrintPreview();
+ }
+
+ return rv;
+}
+
+nsresult EphyWrapper::PrintPreviewNumPages (int *numPages)
+{
+ nsresult rv;
+
+ nsCOMPtr<nsIWebBrowserPrint> print(do_GetInterface(mWebBrowser, &rv));
+ if (NS_FAILED(rv) || !print) return NS_ERROR_FAILURE;
+
+ rv = print->GetPrintPreviewNumPages(numPages);
+ return rv;
+}
+
+nsresult EphyWrapper::PrintPreviewNavigate(PRInt16 navType, PRInt32 pageNum)
+{
+ nsresult rv;
+
+ nsCOMPtr<nsIWebBrowserPrint> print(do_GetInterface(mWebBrowser, &rv));
+ if (NS_FAILED(rv) || !print) return NS_ERROR_FAILURE;
+
+ rv = print->PrintPreviewNavigate(navType, pageNum);
+ return rv;
+}
+
+nsresult EphyWrapper::GetPrintSettings (nsIPrintSettings **options)
+{
+ nsresult result;
+ nsCOMPtr<nsIWebBrowserPrint> print(do_GetInterface(mWebBrowser, &result));
+ if (NS_FAILED(result) || !print) return NS_ERROR_FAILURE;
+
+ return print->GetGlobalPrintSettings(options);
+}
+
+nsresult EphyWrapper::GetSHistory (nsISHistory **aSHistory)
+{
+ nsresult result;
+
+ nsCOMPtr<nsIDocShell> DocShell;
+ result = GetDocShell (getter_AddRefs(DocShell));
+ if (NS_FAILED(result) || !DocShell) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIWebNavigation> ContentNav = do_QueryInterface (DocShell,
+ &result);
+ if (!ContentNav) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsISHistory> SessionHistory;
+ result = ContentNav->GetSessionHistory (getter_AddRefs (SessionHistory));
+ if (!SessionHistory) return NS_ERROR_FAILURE;
+
+ *aSHistory = SessionHistory.get();
+ NS_IF_ADDREF (*aSHistory);
+
+ return NS_OK;
+}
+
+nsresult EphyWrapper::Destroy ()
+{
+ DetachListeners ();
+
+ mWebBrowser = nsnull;
+ mChromeNav = nsnull;
+
+ return NS_OK;
+}
+
+nsresult EphyWrapper::GoToHistoryIndex (PRInt16 index)
+{
+ nsresult result;
+
+ nsCOMPtr<nsIDocShell> DocShell;
+ result = GetDocShell (getter_AddRefs(DocShell));
+ if (NS_FAILED(result) || !DocShell) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIWebNavigation> ContentNav = do_QueryInterface (DocShell,
+ &result);
+ if (!ContentNav) return NS_ERROR_FAILURE;
+
+ return ContentNav->GotoIndex (index);
+}
+
+nsresult EphyWrapper::SetZoom (float aZoom, PRBool reflow)
+{
+ nsresult result;
+
+ nsCOMPtr<nsIDocShell> DocShell;
+ result = GetDocShell (getter_AddRefs(DocShell));
+ if (NS_FAILED(result) || !DocShell) return NS_ERROR_FAILURE;
+
+ if (reflow)
+ {
+ nsCOMPtr<nsIContentViewer> contentViewer;
+ result = DocShell->GetContentViewer (getter_AddRefs(contentViewer));
+ if (!NS_SUCCEEDED (result) || !contentViewer) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIMarkupDocumentViewer> mdv = do_QueryInterface(contentViewer,
+ &result);
+ if (NS_FAILED(result) || !mdv) return NS_ERROR_FAILURE;
+
+ return mdv->SetTextZoom (aZoom);
+ }
+ else
+ {
+ SetZoomOnDocshell (aZoom, DocShell);
+
+ nsCOMPtr<nsIDocShellTreeNode> docShellNode(do_QueryInterface(DocShell));
+ if (docShellNode)
+ {
+ PRInt32 i;
+ PRInt32 n;
+ docShellNode->GetChildCount(&n);
+ for (i=0; i < n; i++)
+ {
+ nsCOMPtr<nsIDocShellTreeItem> child;
+ docShellNode->GetChildAt(i, getter_AddRefs(child));
+ nsCOMPtr<nsIDocShell> childAsShell(do_QueryInterface(child));
+ if (childAsShell)
+ {
+ return SetZoomOnDocshell (aZoom, childAsShell);
+ }
+ }
+ }
+ }
+
+ return NS_OK;
+}
+
+nsresult EphyWrapper::SetZoomOnDocshell (float aZoom, nsIDocShell *DocShell)
+{
+ nsresult result;
+
+ nsCOMPtr<nsIPresContext> PresContext;
+ result = DocShell->GetPresContext (getter_AddRefs(PresContext));
+ if (NS_FAILED(result)) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIDeviceContext> DeviceContext;
+ result = PresContext->GetDeviceContext (getter_AddRefs(DeviceContext));
+
+ return DeviceContext->SetTextZoom (aZoom);
+}
+
+nsresult EphyWrapper::GetZoom (float *aZoom)
+{
+ nsresult result;
+
+ nsCOMPtr<nsIDocShell> DocShell;
+ result = GetDocShell (getter_AddRefs(DocShell));
+ if (NS_FAILED(result) || !DocShell) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIContentViewer> contentViewer;
+ result = DocShell->GetContentViewer (getter_AddRefs(contentViewer));
+ if (!NS_SUCCEEDED (result) || !contentViewer) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIMarkupDocumentViewer> mdv = do_QueryInterface(contentViewer,
+ &result);
+ if (NS_FAILED(result) || !mdv) return NS_ERROR_FAILURE;
+
+ return mdv->GetTextZoom (aZoom);
+}
+
+nsresult EphyWrapper::GetFocusedDOMWindow (nsIDOMWindow **aDOMWindow)
+{
+ nsresult rv;
+
+ nsCOMPtr<nsIWebBrowserFocus> focus = do_GetInterface(mWebBrowser, &rv);
+ if (NS_FAILED(rv) || !focus) return NS_ERROR_FAILURE;
+
+ rv = focus->GetFocusedWindow (aDOMWindow);
+ if (NS_FAILED(rv))
+ rv = mWebBrowser->GetContentDOMWindow (aDOMWindow);
+ return rv;
+}
+
+nsresult EphyWrapper::GetDOMWindow (nsIDOMWindow **aDOMWindow)
+{
+ nsresult rv;
+
+ rv = mWebBrowser->GetContentDOMWindow (aDOMWindow);
+
+ return rv;
+}
+
+nsresult EphyWrapper::GetDOMDocument (nsIDOMDocument **aDOMDocument)
+{
+ nsresult result;
+
+ /* Use the current target document */
+ if (mTargetDocument)
+ {
+ *aDOMDocument = mTargetDocument.get();
+
+ NS_IF_ADDREF(*aDOMDocument);
+
+ return NS_OK;
+ }
+
+ /* Use the focused document */
+ nsCOMPtr<nsIDOMWindow> DOMWindow;
+ result = GetFocusedDOMWindow (getter_AddRefs(DOMWindow));
+ if (NS_SUCCEEDED(result) && DOMWindow)
+ {
+ return DOMWindow->GetDocument (aDOMDocument);
+ }
+
+ /* Use the main document */
+ return GetMainDOMDocument (aDOMDocument);
+}
+
+nsresult EphyWrapper::GetMainDOMDocument (nsIDOMDocument **aDOMDocument)
+{
+ nsresult result;
+
+ nsCOMPtr<nsIDocShell> DocShell;
+ result = GetDocShell (getter_AddRefs(DocShell));
+ if (NS_FAILED(result) || !DocShell) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIContentViewer> contentViewer;
+ result = DocShell->GetContentViewer (getter_AddRefs(contentViewer));
+ if (!NS_SUCCEEDED (result) || !contentViewer) return NS_ERROR_FAILURE;
+
+ return contentViewer->GetDOMDocument (aDOMDocument);
+}
+
+nsresult EphyWrapper::GetSHInfo (PRInt32 *count, PRInt32 *index)
+{
+ nsresult result;
+
+ nsCOMPtr<nsISHistory> SessionHistory;
+ result = GetSHistory (getter_AddRefs(SessionHistory));
+ if (NS_FAILED(result) || ! SessionHistory) return NS_ERROR_FAILURE;
+
+ SessionHistory->GetCount (count);
+ SessionHistory->GetIndex (index);
+
+ return NS_OK;
+}
+
+nsresult EphyWrapper::GetSHTitleAtIndex (PRInt32 index, PRUnichar **title)
+{
+ nsresult result;
+
+ nsCOMPtr<nsISHistory> SessionHistory;
+ result = GetSHistory (getter_AddRefs(SessionHistory));
+ if (NS_FAILED(result) || ! SessionHistory) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIHistoryEntry> he;
+ result = SessionHistory->GetEntryAtIndex (index, PR_FALSE,
+ getter_AddRefs (he));
+ if (!NS_SUCCEEDED(result) || (!he)) return NS_ERROR_FAILURE;
+
+ result = he->GetTitle (title);
+ if (!NS_SUCCEEDED(result) || (!title)) return NS_ERROR_FAILURE;
+
+ return NS_OK;
+}
+
+nsresult EphyWrapper::GetSHUrlAtIndex (PRInt32 index, nsCString &url)
+{
+ nsresult result;
+
+ nsCOMPtr<nsISHistory> SessionHistory;
+ result = GetSHistory (getter_AddRefs(SessionHistory));
+ if (NS_FAILED(result) || ! SessionHistory) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIHistoryEntry> he;
+ result = SessionHistory->GetEntryAtIndex (index, PR_FALSE,
+ getter_AddRefs (he));
+ if (NS_FAILED(result) || (!he)) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIURI> uri;
+ result = he->GetURI (getter_AddRefs(uri));
+ if (NS_FAILED(result) || (!uri)) return NS_ERROR_FAILURE;
+
+ result = uri->GetSpec(url);
+ if (NS_FAILED(result) || url.IsEmpty()) return NS_ERROR_FAILURE;
+
+ return NS_OK;
+}
+
+nsresult EphyWrapper::Find (const PRUnichar *search_string,
+ PRBool interactive,
+ PRBool matchcase, PRBool search_backwards,
+ PRBool search_wrap_around,
+ PRBool search_for_entire_word,
+ PRBool search_in_frames,
+ PRBool *didFind)
+{
+ if (!interactive)
+ {
+ nsresult rv;
+ nsCOMPtr<nsITypeAheadFind> tAFinder
+ (do_GetService(NS_TYPEAHEADFIND_CONTRACTID, &rv));
+ if (NS_SUCCEEDED(rv))
+ {
+ nsCOMPtr<nsIDOMWindow> aFocusedWindow;
+ rv = GetFocusedDOMWindow(getter_AddRefs(aFocusedWindow));
+ if (NS_SUCCEEDED(rv))
+ {
+ nsSupportsInterfacePointerImpl windowPtr;
+ windowPtr.SetData(aFocusedWindow);
+
+ tAFinder->FindNext(search_backwards, &windowPtr);
+
+ nsCOMPtr<nsISupports> retValue;
+ rv = windowPtr.GetData(getter_AddRefs(retValue));
+ if (NS_SUCCEEDED(rv) && !retValue)
+ {
+ *didFind = PR_TRUE;
+ return NS_OK;
+ }
+ }
+ }
+
+ }
+
+ nsCOMPtr<nsIWebBrowserFind> finder (do_GetInterface(mWebBrowser));
+
+ finder->SetSearchString (search_string);
+ finder->SetFindBackwards (search_backwards);
+ finder->SetWrapFind (search_wrap_around);
+ finder->SetEntireWord (search_for_entire_word);
+ finder->SetMatchCase (matchcase);
+ finder->SetSearchFrames (search_in_frames);
+ return finder->FindNext(didFind);
+}
+
+nsresult EphyWrapper::GetWebNavigation(nsIWebNavigation **aWebNavigation)
+{
+ nsresult result;
+
+ nsCOMPtr<nsIDOMWindow> DOMWindow;
+ result = GetFocusedDOMWindow (getter_AddRefs(DOMWindow));
+ if (NS_FAILED(result) || !DOMWindow) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIScriptGlobalObject> scriptGlobal = do_QueryInterface(DOMWindow);
+ if (!scriptGlobal) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIDocShell> docshell;
+ if (NS_FAILED(scriptGlobal->GetDocShell(getter_AddRefs(docshell))))
+ return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIWebNavigation> wn = do_QueryInterface (docshell, &result);
+ if (!wn || !NS_SUCCEEDED (result)) return NS_ERROR_FAILURE;
+
+ NS_IF_ADDREF(*aWebNavigation = wn);
+ return NS_OK;
+}
+
+nsresult EphyWrapper::ReloadDocument ()
+{
+ nsresult result;
+
+ nsCOMPtr<nsIWebNavigation> wn;
+ result = GetWebNavigation(getter_AddRefs(wn));
+ if (!wn || !NS_SUCCEEDED (result)) return NS_ERROR_FAILURE;
+
+ result = wn->Reload (nsIWebNavigation::LOAD_FLAGS_BYPASS_CACHE |
+ nsIWebNavigation::LOAD_FLAGS_BYPASS_PROXY);
+ if (!NS_SUCCEEDED (result)) return NS_ERROR_FAILURE;
+
+ return NS_OK;
+}
+
+nsresult EphyWrapper::LoadDocument(nsISupports *aPageDescriptor,
+ PRUint32 aDisplayType)
+{
+ nsresult rv;
+
+ nsCOMPtr<nsIWebNavigation> wn;
+ rv = GetWebNavigation(getter_AddRefs(wn));
+ if (!wn || !NS_SUCCEEDED(rv)) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIWebPageDescriptor> wpd = do_QueryInterface(wn, &rv);
+ if (!wpd || !NS_SUCCEEDED(rv)) return NS_ERROR_FAILURE;
+
+ return wpd->LoadPage(aPageDescriptor, aDisplayType);
+}
+
+nsresult EphyWrapper::GetPageDescriptor(nsISupports **aPageDescriptor)
+{
+ nsresult rv;
+
+ nsCOMPtr<nsIWebNavigation> wn;
+ rv = GetWebNavigation(getter_AddRefs(wn));
+ if (!wn || !NS_SUCCEEDED(rv)) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIWebPageDescriptor> wpd = do_QueryInterface(wn, &rv);
+ if (!wpd || !NS_SUCCEEDED(rv)) return NS_ERROR_FAILURE;
+
+ return wpd->GetCurrentDescriptor(aPageDescriptor);
+}
+
+nsresult EphyWrapper::GetMainDocumentUrl (nsCString &url)
+{
+ nsresult result;
+
+ nsCOMPtr<nsIDOMDocument> DOMDocument;
+
+ result = GetMainDOMDocument (getter_AddRefs(DOMDocument));
+ if (NS_FAILED(result) || !DOMDocument) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIDocument> doc = do_QueryInterface(DOMDocument);
+ if(!doc) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIURI> uri;
+ doc->GetDocumentURL(getter_AddRefs(uri));
+
+ return uri->GetSpec (url);
+}
+
+nsresult EphyWrapper::GetDocumentUrl (nsCString &url)
+{
+ nsresult result;
+
+ nsCOMPtr<nsIDOMDocument> DOMDocument;
+
+ result = GetDOMDocument (getter_AddRefs(DOMDocument));
+ if (NS_FAILED(result) || !DOMDocument) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIDocument> doc = do_QueryInterface(DOMDocument);
+ if(!doc) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIURI> uri;
+ doc->GetDocumentURL(getter_AddRefs(uri));
+
+ uri->GetSpec (url);
+
+ return NS_OK;
+}
+
+nsresult EphyWrapper::GetDocumentTitle (char **title)
+{
+ nsresult result;
+
+ nsCOMPtr<nsIDOMDocument> DOMDocument;
+
+ result = GetDOMDocument (getter_AddRefs(DOMDocument));
+ if (NS_FAILED(result) || !DOMDocument) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIDocument> doc = do_QueryInterface(DOMDocument);
+ if(!doc) return NS_ERROR_FAILURE;
+
+ const nsString* t;
+ t = doc->GetDocumentTitle();
+
+ *title = g_strdup (NS_ConvertUCS2toUTF8(*t).get());
+
+ return NS_OK;
+}
+
+nsresult EphyWrapper::CopyHistoryTo (EphyWrapper *dest)
+{
+ nsresult result;
+ int count,index;
+
+ nsCOMPtr<nsIDocShell> DocShell;
+ result = GetDocShell (getter_AddRefs(DocShell));
+ if (NS_FAILED(result) || !DocShell) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIWebNavigation> wn_src = do_QueryInterface (DocShell,
+ &result);
+ if (!wn_src) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsISHistory> h_src;
+ result = wn_src->GetSessionHistory (getter_AddRefs (h_src));
+ if (!NS_SUCCEEDED(result) || (!h_src)) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIDocShell> destDocShell;
+ result = dest->GetDocShell (getter_AddRefs(destDocShell));
+ if (NS_FAILED(result) || !DocShell) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIWebNavigation> wn_dest = do_QueryInterface (destDocShell,
+ &result);
+ if (!wn_dest) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsISHistory> h_dest;
+ result = wn_dest->GetSessionHistory (getter_AddRefs (h_dest));
+ if (!NS_SUCCEEDED (result) || (!h_dest)) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsISHistoryInternal> hi_dest = do_QueryInterface (h_dest);
+ if (!hi_dest) return NS_ERROR_FAILURE;
+
+ h_src->GetCount (&count);
+ h_src->GetIndex (&index);
+
+ if (count) {
+ nsCOMPtr<nsIHistoryEntry> he;
+ nsCOMPtr<nsISHEntry> she;
+
+ for (PRInt32 i = 0; i < count; i++) {
+
+ result = h_src->GetEntryAtIndex (i, PR_FALSE,
+ getter_AddRefs (he));
+ if (!NS_SUCCEEDED(result) || (!he))
+ return NS_ERROR_FAILURE;
+
+ she = do_QueryInterface (he);
+ if (!she) return NS_ERROR_FAILURE;
+
+ result = hi_dest->AddEntry (she, PR_TRUE);
+ if (!NS_SUCCEEDED(result) || (!she))
+ return NS_ERROR_FAILURE;
+ }
+
+ result = wn_dest->GotoIndex(index);
+ if (!NS_SUCCEEDED(result)) return NS_ERROR_FAILURE;
+ }
+
+ return NS_OK;
+}
+
+nsresult EphyWrapper::ForceCharacterSet (char *charset)
+{
+ nsresult result;
+
+ nsCOMPtr<nsIDocShell> DocShell;
+ result = GetDocShell (getter_AddRefs(DocShell));
+ if (NS_FAILED(result) || !DocShell) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIContentViewer> contentViewer;
+ result = DocShell->GetContentViewer (getter_AddRefs(contentViewer));
+ if (!NS_SUCCEEDED (result) || !contentViewer) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIMarkupDocumentViewer> mdv = do_QueryInterface(contentViewer,
+ &result);
+ if (NS_FAILED(result) || !mdv) return NS_ERROR_FAILURE;
+
+ result = mdv->SetForceCharacterSet (NS_ConvertUTF8toUCS2(charset).get());
+
+ return result;
+}
+
+nsresult EphyWrapper::CanCutSelection(PRBool *result)
+{
+ nsCOMPtr<nsIClipboardCommands> clipboard (do_GetInterface(mWebBrowser));
+ return clipboard->CanCutSelection (result);
+}
+
+nsresult EphyWrapper::CanCopySelection(PRBool *result)
+{
+ nsCOMPtr<nsIClipboardCommands> clipboard (do_GetInterface(mWebBrowser));
+ return clipboard->CanCopySelection (result);
+}
+
+nsresult EphyWrapper::CanPaste(PRBool *result)
+{
+ nsCOMPtr<nsIClipboardCommands> clipboard (do_GetInterface(mWebBrowser));
+ return clipboard->CanPaste (result);
+}
+
+nsresult EphyWrapper::CutSelection(void)
+{
+ nsCOMPtr<nsIClipboardCommands> clipboard (do_GetInterface(mWebBrowser));
+ return clipboard->CutSelection ();
+}
+
+nsresult EphyWrapper::CopySelection(void)
+{
+ nsCOMPtr<nsIClipboardCommands> clipboard (do_GetInterface(mWebBrowser));
+ return clipboard->CopySelection ();
+}
+
+nsresult EphyWrapper::Paste(void)
+{
+ nsCOMPtr<nsIClipboardCommands> clipboard (do_GetInterface(mWebBrowser));
+ return clipboard->Paste ();
+}
+
+nsresult EphyWrapper::GetLinkInterfaceItems (GList **list)
+{
+#ifdef NOT_PORTED
+ nsresult result;
+ PRUint32 links_count;
+
+ /* we accept these rel=.. elements, specified by the w3c */
+ const gchar *rel_types[] = {
+ "START", "NEXT", "PREV", "PREVIOUS", "CONTENTS", "TOC", "INDEX",
+ "GLOSSARY", "COPYRIGHT", "CHAPTER", "SECTION",
+ "SUBSECTION", "APPENDIX", "HELP", "TOP", "SEARCH", "MADE",
+ "BOOKMARK", "HOME",
+ NULL /* terminator, must be last */
+ };
+
+ nsCOMPtr<nsIDOMDocument> DOMDocument;
+ result = GetMainDOMDocument (getter_AddRefs(DOMDocument));
+ if (NS_FAILED(result) || !DOMDocument) return NS_ERROR_FAILURE;
+
+ /* get list of link elements*/
+ NS_NAMED_LITERAL_STRING(strname, "LINK");
+
+ nsCOMPtr<nsIDOMNodeList> links;
+ result = aDOMDocument->GetElementsByTagName (strname,
+ getter_AddRefs (links));
+ if (NS_FAILED (result)) return NS_ERROR_FAILURE;
+
+ result = links->GetLength (&links_count);
+ if (NS_FAILED (result)) return NS_ERROR_FAILURE;
+
+ for (PRUint32 i = 0; i < links_count; i++)
+ {
+ /* get to the link element */
+ nsCOMPtr<nsIDOMNode> link;
+ result = links->Item (i, getter_AddRefs (link));
+ if (NS_FAILED (result)) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIDOMElement> linkElement;
+ linkElement = do_QueryInterface (aLink);
+ if (!linkElement) return NS_ERROR_FAILURE;
+
+ /* get rel=.. element */
+ NS_NAMED_LITERAL_STRING(attr_rel, "rel");
+ nsAutoString value;
+ linkElement->GetAttribute (attr_rel, value);
+
+ if (value.IsEmpty())
+ {
+ NS_NAMED_LITERAL_STRING(attr_rev, "rev");
+ linkElement->GetAttribute (attr_rev, value);
+ if (value.IsEmpty()) continue;
+ }
+
+ nsCString relstr = NS_ConvertUCS2toUTF8(value);
+ ToUpperCase(relstr);
+
+ /* check for elements we want */
+ for (gint j = 0; (rel_types[j] != NULL); j++)
+ {
+ if (strcmp (relstr.get(), rel_types[j]) == 0)
+ {
+ /* found one! */
+ LinkInterfaceItem *lti =
+ g_new0 (LinkInterfaceItem, 1);
+
+ /* fill in struct */
+ lti->type = (LinkInterfaceItemType) j;
+
+ /* get href=.. element */
+ NS_NAMED_LITERAL_STRING(attr_href, "href");
+ nsAutoString value;
+ linkElement->GetAttribute (attr_href, value);
+
+ if (value.IsEmpty())
+ {
+ g_free (lti);
+ continue;
+ }
+
+ /* resolve uri */
+ nsCOMPtr<nsIDocument> doc =
+ do_QueryInterface (aDOMDocument);
+ if(!doc) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIURI> uri;
+ doc->GetDocumentURL(getter_AddRefs(uri));
+
+ const nsACString &link = NS_ConvertUCS2toUTF8(value);
+ nsCAutoString href;
+ result = uri->Resolve (link, href);
+ if (NS_FAILED (result)) return NS_ERROR_FAILURE;
+ lti->href = g_strdup (href.get());
+
+ /* append to list of items */
+ *list = g_list_append (*list, lti);
+
+ /* get optional title=... element */
+ NS_NAMED_LITERAL_STRING(attr_title, "title");
+ linkElement->GetAttribute (attr_title, value);
+ if (value.IsEmpty()) continue;
+
+ const nsACString &title = NS_ConvertUCS2toUTF8 (value);
+ lti->title = gul_string_strip_newline (PromiseFlatCString(title).get());
+ }
+ }
+ }
+#endif
+ return NS_OK;
+}
+
+nsresult EphyWrapper::GetRealURL (nsCString &ret)
+{
+ nsresult result;
+
+ nsCOMPtr<nsIDocShell> DocShell;
+ result = GetDocShell (getter_AddRefs(DocShell));
+ if (NS_FAILED(result) || !DocShell) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIWebNavigation> ContentNav = do_QueryInterface (DocShell,
+ &result);
+ if (!ContentNav) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIURI> uri;
+ result = ContentNav->GetCurrentURI (getter_AddRefs(uri));
+ if (!NS_SUCCEEDED(result) || (!uri)) return NS_ERROR_FAILURE;
+
+ result = uri->GetSpec(ret);
+ if (!NS_SUCCEEDED(result) || ret.IsEmpty()) return NS_ERROR_FAILURE;
+
+ return NS_OK;
+}
+
+nsresult EphyWrapper::SelectAll (void)
+{
+ nsCOMPtr<nsIClipboardCommands> clipboard (do_GetInterface(mWebBrowser));
+ return clipboard->SelectAll ();
+}
+
+nsresult EphyWrapper::ScrollUp (void)
+{
+ nsresult result;
+
+ nsCOMPtr<nsIDOMWindow> DOMWindow;
+ result = GetFocusedDOMWindow (getter_AddRefs(DOMWindow));
+ if (NS_FAILED(result) || !DOMWindow) return NS_ERROR_FAILURE;
+
+ DOMWindow->ScrollByLines(-1);
+
+ return NS_OK;
+}
+
+nsresult EphyWrapper::ScrollDown (void)
+{
+ nsresult result;
+
+ nsCOMPtr<nsIDOMWindow> DOMWindow;
+ result = GetFocusedDOMWindow (getter_AddRefs(DOMWindow));
+ if (NS_FAILED(result) || !DOMWindow) return NS_ERROR_FAILURE;
+
+ DOMWindow->ScrollByLines(1);
+
+ return NS_OK;
+}
+
+nsresult EphyWrapper::ScrollLeft (void)
+{
+ nsresult result;
+
+ nsCOMPtr<nsIDOMWindow> DOMWindow;
+ result = GetFocusedDOMWindow (getter_AddRefs(DOMWindow));
+ if (NS_FAILED(result) || !DOMWindow) return NS_ERROR_FAILURE;
+
+ DOMWindow->ScrollBy(-16, 0);
+
+ return NS_OK;
+}
+
+nsresult EphyWrapper::ScrollRight (void)
+{
+ nsresult result;
+
+ nsCOMPtr<nsIDOMWindow> DOMWindow;
+ result = GetFocusedDOMWindow (getter_AddRefs(DOMWindow));
+ if (NS_FAILED(result) || !DOMWindow) return NS_ERROR_FAILURE;
+
+ DOMWindow->ScrollBy(16, 0);
+
+ return NS_OK;
+}
+
+nsresult EphyWrapper::FineScroll (int horiz, int vert)
+{
+ nsresult result;
+
+ nsCOMPtr<nsIDOMWindow> DOMWindow;
+ result = GetFocusedDOMWindow (getter_AddRefs(DOMWindow));
+ if (NS_FAILED(result) || !DOMWindow) return NS_ERROR_FAILURE;
+
+ DOMWindow->ScrollBy(horiz, vert);
+
+ return NS_OK;
+}
+
+nsresult EphyWrapper::GetLastModified (gchar **ret)
+{
+ nsresult result;
+
+ nsCOMPtr<nsIDOMDocument> DOMDocument;
+
+ result = GetDOMDocument (getter_AddRefs(DOMDocument));
+ if (NS_FAILED(result) || !DOMDocument) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIDOMNSHTMLDocument> doc = do_QueryInterface(DOMDocument);
+ if(!doc) return NS_ERROR_FAILURE;
+
+ nsAutoString value;
+ doc->GetLastModified(value);
+
+ *ret = g_strdup (NS_ConvertUCS2toUTF8(value).get());
+
+ return NS_OK;
+}
+
+nsresult EphyWrapper::GetImages (GList **ret)
+{
+#ifdef NOT_PORTED
+ nsresult result;
+ GHashTable *hash = g_hash_table_new (g_str_hash, g_str_equal);
+
+ nsCOMPtr<nsIDOMDocument> DOMDocument;
+
+ result = GetDOMDocument (getter_AddRefs(DOMDocument));
+ if (NS_FAILED(result) || !DOMDocument) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIDOMHTMLDocument> doc = do_QueryInterface(DOMDocument);
+ if(!doc) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIDOMHTMLCollection> col;
+ doc->GetImages(getter_AddRefs(col));
+
+ PRUint32 count, i;
+ col->GetLength(&count);
+ for (i = 0; i < count; i++)
+ {
+ nsCOMPtr<nsIDOMNode> node;
+ col->Item(i, getter_AddRefs(node));
+ if (!node) continue;
+
+ nsCOMPtr<nsIDOMHTMLElement> element;
+ element = do_QueryInterface(node);
+ if (!element) continue;
+
+ nsCOMPtr<nsIDOMHTMLImageElement> img;
+ img = do_QueryInterface(element);
+ if (!img) continue;
+
+ ImageListItem *item = g_new0 (ImageListItem, 1);
+
+ nsAutoString tmp;
+ result = img->GetSrc (tmp);
+ if (NS_SUCCEEDED(result))
+ {
+ const nsACString &c = NS_ConvertUCS2toUTF8(tmp);
+ if (g_hash_table_lookup (hash, PromiseFlatCString(c).get()))
+ {
+ g_free (item);
+ continue;
+ }
+ item->url = g_strdup (c.get());
+ g_hash_table_insert (hash, item->url,
+ GINT_TO_POINTER (TRUE));
+ }
+ result = img->GetAlt (tmp);
+ if (NS_SUCCEEDED(result))
+ {
+ const nsACString &c = NS_ConvertUCS2toUTF8(tmp);
+ item->alt = gul_string_strip_newline (PromiseFlatCString(c).get());
+ }
+ result = element->GetTitle (tmp);
+ if (NS_SUCCEEDED(result))
+ {
+ const nsACString &c = NS_ConvertUCS2toUTF8(tmp);
+ item->title = gul_string_strip_newline (PromiseFlatCString(c).get());
+ }
+ result = img->GetWidth (&(item->width));
+ result = img->GetHeight (&(item->height));
+
+ *ret = g_list_append (*ret, item);
+ }
+
+ g_hash_table_destroy (hash);
+#endif
+ return NS_OK;
+}
+
+nsresult EphyWrapper::GetForms (GList **ret)
+{
+#ifdef NOT_PORTED
+ nsresult result;
+
+ nsCOMPtr<nsIDOMDocument> DOMDocument;
+
+ result = GetDOMDocument (getter_AddRefs(DOMDocument));
+ if (NS_FAILED(result) || !DOMDocument) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIDOMHTMLDocument> doc = do_QueryInterface(DOMDocument);
+ if(!doc) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIDOMHTMLCollection> col;
+ doc->GetForms(getter_AddRefs(col));
+
+ PRUint32 count, i;
+ col->GetLength(&count);
+ for (i = 0; i < count; i++)
+ {
+ nsCOMPtr<nsIDOMNode> node;
+ col->Item(i, getter_AddRefs(node));
+ if (!node) continue;
+
+ nsCOMPtr<nsIDOMHTMLElement> element;
+ element = do_QueryInterface(node);
+ if (!element) continue;
+
+ nsCOMPtr<nsIDOMHTMLFormElement> form;
+ form = do_QueryInterface(element);
+ if (!form) continue;
+
+ FormListItem *item = g_new0 (FormListItem, 1);
+
+ nsAutoString tmp;
+ result = form->GetAction (tmp);
+ if (NS_SUCCEEDED(result))
+ {
+ nsCOMPtr<nsIDocument> doc =
+ do_QueryInterface (aDOMDocument);
+ if(!doc) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIURI> uri;
+ doc->GetDocumentURL(getter_AddRefs(uri));
+
+ const nsACString &s = NS_ConvertUTF8toUCS2(tmp);
+ nsCAutoString c;
+ result = uri->Resolve (c, s);
+
+ item->action = s.Length() ? g_strdup (s.get()) : g_strdup (c.get());
+ }
+ result = form->GetMethod (tmp);
+ if (NS_SUCCEEDED(result))
+ {
+ const nsACString &c = NS_ConvertUTF8toUCS2(tmp);
+ item->method = g_strdup (PromiseFlatCString(c).get());
+ }
+ result = form->GetName (tmp);
+ if (NS_SUCCEEDED(result))
+ {
+ const nsACString &c = NS_ConvertUTF8toUCS2(tmp);
+ item->name = g_strdup (PromiseFlatCString(c).get());
+ }
+
+ *ret = g_list_append (*ret, item);
+ }
+#endif
+ return NS_OK;
+}
+
+nsresult EphyWrapper::GetLinks (GList **ret)
+{
+#ifdef NOT_PORTED
+ nsresult result;
+
+ nsCOMPtr<nsIDOMDocument> DOMDocument;
+ result = GetMainDOMDocument (getter_AddRefs(DOMDocument));
+ if (NS_FAILED(result) || !DOMDocument) return NS_ERROR_FAILURE;
+
+ /* first, get a list of <link> elements */
+ PRUint32 links_count;
+
+ NS_NAMED_LITERAL_STRING(strname, "LINK");
+
+ nsCOMPtr<nsIDOMNodeList> links;
+ result = DOMDocument->GetElementsByTagName (strname,
+ getter_AddRefs (links));
+ if (NS_FAILED (result)) return NS_ERROR_FAILURE;
+
+ result = aLinks->GetLength (&links_count);
+ if (NS_FAILED (result)) return NS_ERROR_FAILURE;
+
+ for (PRUint32 i = 0; i < links_count; i++)
+ {
+ nsCOMPtr<nsIDOMNode> link;
+ result = links->Item (i, getter_AddRefs (link));
+ if (NS_FAILED (result)) continue;
+
+ nsCOMPtr<nsIDOMElement> linkElement;
+ linkElement = do_QueryInterface (link);
+ if (!linkElement) continue;
+
+ NS_NAMED_LITERAL_STRING(attr_href, "href");
+ nsAutoString value;
+ linkElement->GetAttribute (attr_href, value);
+ if (value.IsEmpty()) continue;
+
+ const nsACString &link = NS_ConvertUCS2toUTF8(value);
+
+ if (link.IsEmpty()) continue;
+
+ nsCOMPtr<nsIDocument> doc =
+ do_QueryInterface (aDOMDocument);
+ if(!doc) continue;
+
+ nsCOMPtr<nsIURI> uri;
+ doc->GetDocumentURL(getter_AddRefs(uri));
+
+ nsCAutoString tmp;
+ result = uri->Resolve (link, tmp);
+
+ LinkListItem *i = g_new0 (LinkListItem, 1);
+
+ if (!tmp.IsEmpty())
+ {
+ i->url = g_strdup (tmp.get());
+ }
+ else
+ {
+ i->url = g_strdup (link.get());
+ }
+
+ NS_NAMED_LITERAL_STRING(attr_title, "title");
+ linkElement->GetAttribute (attr_title, value);
+ if (!value.IsEmpty())
+ {
+ const nsACString &s = NS_ConvertUCS2toUTF8(value);
+ i->title = gul_string_strip_newline (PromiseFlatCString(s).get());
+ }
+
+ NS_NAMED_LITERAL_STRING(attr_rel, "rel");
+ linkElement->GetAttribute (attr_rel, value);
+ if (!value.IsEmpty())
+ {
+ const nsACString &s = NS_ConvertUCS2toUTF8(value);
+ i->rel = g_strdup (PromiseFlatCString(s).get());
+ g_strdown (i->rel);
+ }
+ if (!i->rel || strlen (i->rel) == 0)
+ {
+ NS_NAMED_LITERAL_STRING(attr_rev, "rev");
+ linkElement->GetAttribute (attr_rev, value);
+ if (!value.IsEmpty())
+ {
+ const nsACString &s = NS_ConvertUCS2toUTF8(value);
+ i->rel = g_strdup (PromiseFlatCString(s).get());
+ g_strdown (i->rel);
+ }
+ }
+
+ *ret = g_list_append (*ret, i);
+ }
+
+ /* next, get a list of anchors */
+ nsCOMPtr<nsIDOMHTMLDocument> doc = do_QueryInterface(aDOMDocument);
+ if(!doc) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIDOMHTMLCollection> col;
+ doc->GetLinks(getter_AddRefs(col));
+
+ PRUint32 count, i;
+ col->GetLength(&count);
+ for (i = 0; i < count; i++)
+ {
+ nsCOMPtr<nsIDOMNode> node;
+ col->Item(i, getter_AddRefs(node));
+ if (!node) continue;
+
+ nsCOMPtr<nsIDOMHTMLElement> element;
+ element = do_QueryInterface(node);
+ if (!element) continue;
+
+ nsCOMPtr<nsIDOMHTMLAnchorElement> lnk;
+ lnk = do_QueryInterface(element);
+ if (!lnk) continue;
+
+ LinkListItem *i = g_new0 (LinkListItem, 1);
+
+ nsAutoString tmp;
+
+ result = lnk->GetHref (tmp);
+ if (NS_SUCCEEDED(result))
+ {
+ const nsACString &c = NS_ConvertUCS2toUTF8(tmp);
+ i->url = g_strdup (PromiseFlatCString(c).get());
+ }
+
+ result = lnk->GetRel (tmp);
+ if (NS_SUCCEEDED(result))
+ {
+ const nsACString &c = NS_ConvertUCS2toUTF8(tmp);
+ i->rel = g_strdup (PromiseFlatCString(c).get());
+ g_strdown (i->rel);
+ }
+
+ if (!i->rel || strlen (i->rel) == 0)
+ {
+ result = lnk->GetRev (tmp);
+ if (NS_SUCCEEDED(result))
+ {
+ const nsACString &c = NS_ConvertUCS2toUTF8(tmp);
+ i->rel = g_strdup (PromiseFlatCString(c).get());
+ g_strdown (i->rel);
+ }
+ }
+
+ i->title = mozilla_get_link_text (node);
+ if (i->title == NULL)
+ {
+ result = element->GetTitle (tmp);
+ if (NS_SUCCEEDED(result))
+ {
+ const nsACString &c = NS_ConvertUCS2toUTF8(tmp);
+ i->title = gul_string_strip_newline (PromiseFlatCString(c).get());
+ }
+ }
+
+
+ *ret = g_list_append (*ret, i);
+ }
+#endif
+ return NS_OK;
+}
+
+nsresult EphyWrapper::EvaluateJS (char *script)
+{
+ nsresult rv;
+
+ nsCOMPtr<nsIDOMWindow> DOMWindow;
+ rv = mWebBrowser->GetContentDOMWindow(getter_AddRefs(DOMWindow));
+
+ nsCOMPtr<nsIScriptGlobalObject> globalObject;
+ globalObject = do_QueryInterface (DOMWindow);
+ if (!globalObject) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIScriptContext> context;
+ rv = globalObject->GetContext(getter_AddRefs(context));
+ if (NS_FAILED(rv) || !context) {
+ return NS_ERROR_FAILURE;
+ }
+
+ context->SetProcessingScriptTag(PR_TRUE);
+
+ PRBool isUndefined;
+ nsAutoString ret;
+ const nsAString &aScript = NS_ConvertUTF8toUCS2(script);
+ context->EvaluateString(aScript, nsnull, nsnull, nsnull,
+ 0, nsnull,
+ ret, &isUndefined);
+
+ context->SetProcessingScriptTag(PR_FALSE);
+
+ return NS_OK;
+}
+
+nsresult EphyWrapper::PushTargetDocument (nsIDOMDocument *domDoc)
+{
+ mTargetDocument = domDoc;
+
+ return NS_OK;
+}
+
+nsresult EphyWrapper::PopTargetDocument ()
+{
+ mTargetDocument = nsnull;
+
+ return NS_OK;
+}
diff --git a/embed/mozilla/EphyWrapper.h b/embed/mozilla/EphyWrapper.h
new file mode 100644
index 000000000..04379546c
--- /dev/null
+++ b/embed/mozilla/EphyWrapper.h
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2000 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EPHY_WRAPPER_H
+#define EPHY_WRAPPER_H
+
+#include "nsIDocShell.h"
+#include "ProgressListener.h"
+#include "nsIWebNavigation.h"
+#include "nsIWebPageDescriptor.h"
+#include "nsISHistory.h"
+#include "nsIWebBrowser.h"
+#include "nsIWebProgressListener.h"
+#include "nsCOMPtr.h"
+#include "nsIDOMEventReceiver.h"
+#include "nsIDOMDocument.h"
+#include "nsPIDOMWindow.h"
+#include <gtkmozembed.h>
+
+#include "nsIPrintSettings.h"
+
+class EphyEventListener;
+
+class EphyWrapper
+{
+public:
+ EphyWrapper();
+ ~EphyWrapper();
+
+ nsresult Init (GtkMozEmbed *mozembed);
+ nsresult Destroy (void);
+
+ nsresult SetZoom (float aTextZoom, PRBool reflow);
+ nsresult GetZoom (float *aTextZoom);
+
+ nsresult Print (nsIPrintSettings *options, PRBool preview);
+ nsresult GetPrintSettings (nsIPrintSettings * *options);
+ nsresult PrintPreviewClose (void);
+ nsresult PrintPreviewNumPages (int *numPages);
+ nsresult PrintPreviewNavigate(PRInt16 navType, PRInt32 pageNum);
+
+ nsresult Find (const PRUnichar *search_string,
+ PRBool matchcase, PRBool interactive,
+ PRBool search_backwards, PRBool search_wrap_around,
+ PRBool search_for_entire_word, PRBool search_in_frames,
+ PRBool *didFind);
+
+ nsresult GetMainDocumentUrl (nsCString &url);
+ nsresult GetDocumentUrl (nsCString &url);
+ nsresult GetDocumentTitle (char **title);
+
+ nsresult ReloadDocument ();
+ nsresult LoadDocument(nsISupports *aPageDescriptor, PRUint32 aDisplayType);
+ nsresult GetPageDescriptor(nsISupports **aPageDescriptor);
+
+ nsresult GetSHInfo (PRInt32 *count, PRInt32 *index);
+ nsresult GetSHTitleAtIndex (PRInt32 index, PRUnichar **title);
+ nsresult GetSHUrlAtIndex (PRInt32 index, nsCString &url);
+
+ nsresult CopyHistoryTo (EphyWrapper *embed);
+
+ nsresult GoToHistoryIndex (PRInt16 index);
+
+ nsresult ForceCharacterSet (char *charset);
+
+ nsresult CanCutSelection(PRBool *result);
+
+ nsresult CanCopySelection(PRBool *result);
+
+ nsresult CanPaste(PRBool *result);
+
+ nsresult CutSelection(void);
+
+ nsresult CopySelection(void);
+
+ nsresult Paste(void);
+
+ nsresult Activate ();
+ nsresult Deactivate ();
+
+ nsresult GetMainDOMDocument (nsIDOMDocument **aDOMDocument);
+
+ nsresult GetLinkInterfaceItems (GList **list);
+
+ nsresult GetRealURL (nsCString &ret);
+
+ nsresult SelectAll (void);
+
+ nsresult ScrollUp (void);
+ nsresult ScrollDown (void);
+ nsresult ScrollLeft (void);
+ nsresult ScrollRight (void);
+
+ nsresult FineScroll (int horiz, int vert);
+
+ nsresult GetLastModified (gchar **ret);
+ nsresult GetImages (GList **ret);
+ nsresult GetForms (GList **ret);
+ nsresult GetLinks (GList **ret);
+ nsresult EvaluateJS (char *script);
+
+ nsresult PushTargetDocument (nsIDOMDocument *domDoc);
+ nsresult PopTargetDocument ();
+
+ nsresult GetDOMDocument (nsIDOMDocument **aDOMDocument);
+ nsresult GetDOMWindow (nsIDOMWindow **aDOMWindow);
+
+ nsCOMPtr<nsIWebBrowser> mWebBrowser;
+
+ nsCOMPtr<nsIWebNavigation> mChromeNav;
+
+ GtkMozEmbed *mGtkMozEmbed;
+private:
+ nsCOMPtr<nsIDOMDocument> mTargetDocument;
+ nsCOMPtr<nsIWebProgressListener> mProgress;
+ nsCOMPtr<nsIDOMEventReceiver> mEventReceiver;
+ EphyEventListener *mEventListener;
+ PRBool mListenersAttached;
+
+ void GetListener (void);
+ void AttachListeners (void);
+ void DetachListeners (void);
+ nsresult SetZoomOnDocshell (float aZoom, nsIDocShell *DocShell);
+ nsresult GetDocShell (nsIDocShell **aDocShell);
+ nsresult GetCSSBackground (nsIDOMNode *node, nsAutoString& url);
+ nsresult GetFocusedDOMWindow (nsIDOMWindow **aDOMWindow);
+ nsresult GetSHistory (nsISHistory **aSHistory);
+ nsresult GetPIDOMWindow(nsPIDOMWindow **aPIWin);
+ nsresult GetWebNavigation(nsIWebNavigation **aWebNavigation);
+};
+
+#endif
diff --git a/embed/mozilla/EventContext.cpp b/embed/mozilla/EventContext.cpp
new file mode 100644
index 000000000..9d4e312b6
--- /dev/null
+++ b/embed/mozilla/EventContext.cpp
@@ -0,0 +1,669 @@
+/*
+ * Copyright (C) 2000 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "EventContext.h"
+#include "nsIDOMEventTarget.h"
+#include "nsIDocument.h"
+#include "nsIDOMHTMLInputElement.h"
+#include "nsIDOMHTMLObjectElement.h"
+#include "nsIInterfaceRequestor.h"
+#include "nsIDOMHTMLImageElement.h"
+#include "nsIDOMElement.h"
+#include "nsIDOMXULDocument.h"
+#include "nsIURI.h"
+#include "nsIDOMNSDocument.h"
+#include "nsReadableUtils.h"
+#include "nsUnicharUtils.h"
+#include "nsGUIEvent.h"
+#include "nsIDOMNSEvent.h"
+#include "nsIDOMCharacterData.h"
+#include "nsIDOMHTMLButtonElement.h"
+#include "nsIDOMHTMLLabelElement.h"
+#include "nsIDOMHTMLLegendElement.h"
+#include "nsIDOMHTMLTextAreaElement.h"
+#include <gdk/gdkkeysyms.h>
+#include "nsIPrivateDOMEvent.h"
+#include "nsIDOMNSUIEvent.h"
+
+#define KEY_CODE 256
+
+EventContext::EventContext ()
+{
+}
+
+EventContext::~EventContext ()
+{
+}
+
+nsresult EventContext::Init (nsIDOMEvent *event, EphyWrapper *wrapper)
+{
+ mEvent = event;
+ mWrapper = wrapper;
+ mDOMDocument = nsnull;
+
+ return NS_OK;
+}
+
+nsresult EventContext::GetEventContext (nsIDOMEventTarget *EventTarget,
+ EphyEmbedEvent *info)
+{
+ nsresult rv;
+
+ mEmbedEvent = info;
+
+ info->context = EMBED_CONTEXT_DOCUMENT;
+
+ nsCOMPtr<nsIDOMNode> node = do_QueryInterface(EventTarget, &rv);
+ if (NS_FAILED(rv) || !node) return NS_ERROR_FAILURE;
+
+ /* Is page xul ? then do not display context menus
+ * FIXME I guess there is an easier way ... */
+ /* From philipl: This test needs to be here otherwise we
+ * arrogantly assume we can QI to a HTMLElement, which is
+ * not true for xul content. */
+
+ nsCOMPtr<nsIDOMDocument> domDoc;
+ rv = node->GetOwnerDocument(getter_AddRefs(domDoc));
+ if (NS_FAILED(rv) || !domDoc) return NS_ERROR_FAILURE;
+
+ mDOMDocument = domDoc;
+
+ nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc, &rv);
+ if (NS_FAILED(rv) || !doc) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIDOMXULDocument> xul_document = do_QueryInterface(domDoc);
+ if (xul_document)
+ {
+ info->context = EMBED_CONTEXT_NONE;
+ return NS_ERROR_FAILURE;
+ }
+
+ // Now we know that the page isn't a xul window, we can try and
+ // do something useful with it.
+
+ PRUint16 type;
+ rv = node->GetNodeType(&type);
+ if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIDOMHTMLElement> element = do_QueryInterface(node);
+ if ((nsIDOMNode::ELEMENT_NODE == type) && element)
+ {
+ nsAutoString tag;
+ rv = element->GetTagName(tag);
+ if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
+
+ if (tag.Equals(NS_LITERAL_STRING("img"),
+ nsCaseInsensitiveStringComparator()))
+ {
+ info->context |= EMBED_CONTEXT_IMAGE;
+
+ nsAutoString img;
+ nsCOMPtr <nsIDOMHTMLImageElement> image =
+ do_QueryInterface(node, &rv);
+ if (NS_FAILED(rv) || !image) return NS_ERROR_FAILURE;
+
+ rv = image->GetSrc (img);
+ if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
+ SetStringProperty ("image", img);
+
+ rv = image->GetAlt (img);
+ if (NS_SUCCEEDED(rv))
+ {
+ SetStringProperty ("image_alt", img);
+ }
+
+ rv = image->GetLongDesc (img);
+ if (NS_SUCCEEDED(rv) && !img.IsEmpty())
+ {
+ nsCAutoString imglongdesc;
+ const nsACString &src = NS_ConvertUCS2toUTF8(img);
+
+ nsCOMPtr<nsIURI> uri;
+ doc->GetDocumentURL(getter_AddRefs(uri));
+
+ rv = uri->Resolve (src, imglongdesc);
+
+ SetStringProperty ("image_long_desc",
+ NS_ConvertUTF8toUCS2(imglongdesc));
+ }
+
+ int imgwidth, imgheight;
+ rv = image->GetWidth (&imgwidth);
+ rv = image->GetHeight (&imgheight);
+ SetIntProperty ("image_width", imgwidth);
+ SetIntProperty ("image_height", imgheight);
+
+ rv = element->GetTitle (img);
+ if (NS_SUCCEEDED(rv))
+ {
+ SetStringProperty ("image_title",
+ img);
+ }
+ }
+ else if (tag.Equals(NS_LITERAL_STRING("input"),
+ nsCaseInsensitiveStringComparator()))
+ {
+ nsCOMPtr<nsIDOMElement> element;
+ element = do_QueryInterface (node);
+ if (!element) return NS_ERROR_FAILURE;
+
+ NS_NAMED_LITERAL_STRING(attr, "type");
+ nsAutoString value;
+ element->GetAttribute (attr, value);
+
+ if (value.Equals(NS_LITERAL_STRING("image"),
+ nsCaseInsensitiveStringComparator()))
+ {
+ info->context |= EMBED_CONTEXT_IMAGE;
+ nsCOMPtr<nsIDOMHTMLInputElement> input;
+ input = do_QueryInterface (node);
+ if (!input) return NS_ERROR_FAILURE;
+
+ nsAutoString img;
+ rv = input->GetSrc (img);
+ if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
+
+ nsCAutoString cImg;
+ const nsACString &src = NS_ConvertUCS2toUTF8(img);
+
+ nsCOMPtr<nsIURI> uri;
+ doc->GetDocumentURL(getter_AddRefs(uri));
+ rv = uri->Resolve (src, cImg);
+ SetStringProperty ("image",
+ NS_ConvertUTF8toUCS2(cImg));
+
+ if (NS_FAILED (rv)) return NS_ERROR_FAILURE;
+ }
+ else if (!value.Equals(NS_LITERAL_STRING("radio"),
+ nsCaseInsensitiveStringComparator()) &&
+ !value.Equals(NS_LITERAL_STRING("submit"),
+ nsCaseInsensitiveStringComparator()) &&
+ !value.Equals(NS_LITERAL_STRING("reset"),
+ nsCaseInsensitiveStringComparator()) &&
+ !value.Equals(NS_LITERAL_STRING("hidden"),
+ nsCaseInsensitiveStringComparator()) &&
+ !value.Equals(NS_LITERAL_STRING("button"),
+ nsCaseInsensitiveStringComparator()) &&
+ !value.Equals(NS_LITERAL_STRING("checkbox"),
+ nsCaseInsensitiveStringComparator()))
+ {
+ info->context |= EMBED_CONTEXT_INPUT;
+ }
+ }
+ else if (tag.Equals(NS_LITERAL_STRING("textarea"),
+ nsCaseInsensitiveStringComparator()))
+ {
+ info->context |= EMBED_CONTEXT_INPUT;
+ }
+ else if (tag.Equals(NS_LITERAL_STRING("object"),
+ nsCaseInsensitiveStringComparator()))
+ {
+ nsCOMPtr<nsIDOMHTMLObjectElement> object;
+ object = do_QueryInterface (node);
+ if (!element) return NS_ERROR_FAILURE;
+
+ nsAutoString value;
+ object->GetType(value);
+
+ //Forming a substring and confirming it's contents
+ //is quicker than doing a Find on the full string
+ //and then checking that "image/" is at the beginning
+ if (Substring(value, 0, 6).Equals(NS_LITERAL_STRING("image/"),
+ nsCaseInsensitiveStringComparator()))
+ {
+ info->context |= EMBED_CONTEXT_IMAGE;
+
+ nsAutoString img;
+
+ rv = object->GetData (img);
+ if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
+
+ nsCAutoString cImg;
+ const nsACString &src = NS_ConvertUCS2toUTF8(img);
+
+ nsCOMPtr<nsIURI> uri;
+ doc->GetDocumentURL(getter_AddRefs(uri));
+ rv = uri->Resolve (src, cImg);
+ SetStringProperty ("image",
+ NS_ConvertUTF8toUCS2(cImg));
+
+ if (NS_FAILED (rv)) return NS_ERROR_FAILURE;
+ }
+ else
+ {
+ info->context = EMBED_CONTEXT_NONE;
+ return NS_OK;
+ }
+ }
+ }
+
+ /* Is page framed ? */
+ PRBool framed;
+ IsPageFramed (node, &framed);
+ SetIntProperty ("framed_page", framed);
+
+ /* Bubble out, looking for items of interest */
+ while (node)
+ {
+ nsCOMPtr <nsIDOMElement> dom_elem = do_QueryInterface(node);
+ if (dom_elem)
+ {
+ NS_NAMED_LITERAL_STRING(nspace, "http://www.w3.org/1999/xlink");
+ NS_NAMED_LITERAL_STRING(localname_type, "type");
+
+ nsAutoString value;
+ dom_elem->GetAttributeNS (nspace, localname_type, value);
+
+ if (value.Equals(NS_LITERAL_STRING("simple"),
+ nsCaseInsensitiveStringComparator()))
+ {
+ info->context |= EMBED_CONTEXT_LINK;
+ NS_NAMED_LITERAL_STRING (localname_href, "href");
+ dom_elem->GetAttributeNS (nspace, localname_href, value);
+
+ SetStringProperty ("link", value);
+ }
+ }
+
+ PRUint16 type;
+ rv = node->GetNodeType(&type);
+ if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
+
+ element = do_QueryInterface(node);
+ if ((nsIDOMNode::ELEMENT_NODE == type) && element)
+ {
+ nsAutoString tag;
+ rv = element->GetTagName(tag);
+ if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
+
+ /* Link */
+ if (tag.Equals(NS_LITERAL_STRING("a"),
+ nsCaseInsensitiveStringComparator()))
+ {
+ nsCOMPtr <nsIDOMHTMLAnchorElement> anchor =
+ do_QueryInterface(node);
+ nsAutoString tmp;
+ rv = anchor->GetHref (tmp);
+ if (NS_FAILED(rv))
+ return NS_ERROR_FAILURE;
+
+ if (Substring(tmp, 0, 7).Equals(NS_LITERAL_STRING("mailto:"),
+ nsCaseInsensitiveStringComparator()))
+ {
+ info->context |= EMBED_CONTEXT_EMAIL_LINK;
+ const nsAString &address = Substring(tmp, 7, tmp.Length()-7);
+ SetStringProperty ("email", address);
+ }
+
+ if (anchor && !tmp.IsEmpty())
+ {
+ info->context |= EMBED_CONTEXT_LINK;
+
+ SetStringProperty ("link", tmp);
+ rv = anchor->GetHreflang (tmp);
+ if (NS_SUCCEEDED(rv))
+ SetStringProperty ("link_lang", tmp);
+ rv = anchor->GetTarget (tmp);
+ if (NS_SUCCEEDED(rv))
+ SetStringProperty ("link_target", tmp);
+ rv = anchor->GetRel (tmp);
+ if (NS_SUCCEEDED(rv))
+ SetStringProperty ("link_rel", tmp);
+ rv = anchor->GetRev (tmp);
+ if (NS_SUCCEEDED(rv))
+ SetStringProperty ("link_rev", tmp);
+ rv = element->GetTitle (tmp);
+ if (NS_SUCCEEDED(rv))
+ SetStringProperty ("link_title", tmp);
+ rv = anchor->GetType (tmp);
+ if (NS_SUCCEEDED(rv))
+ SetStringProperty ("link_type", tmp);
+
+ if (tmp.Equals(NS_LITERAL_STRING("text/smartbookmark"),
+ nsCaseInsensitiveStringComparator()))
+ {
+ SetIntProperty ("link_is_smart", TRUE);
+
+ nsCOMPtr<nsIDOMNode> childNode;
+ node->GetFirstChild (getter_AddRefs(childNode));
+ if (childNode)
+ {
+ nsCOMPtr <nsIDOMHTMLImageElement> image =
+ do_QueryInterface(childNode, &rv);
+
+ if (image)
+ {
+ nsAutoString img;
+ rv = image->GetSrc (img);
+ if (!NS_FAILED(rv))
+ {
+ SetStringProperty ("image", img);
+ }
+ }
+ }
+ }
+#ifdef NOT_PORTED
+ /* Get the text of the link */
+ info->linktext = mozilla_get_link_text (node);
+#endif
+ }
+
+ }
+ else if (tag.Equals(NS_LITERAL_STRING("option"),
+ nsCaseInsensitiveStringComparator()))
+ {
+ info->context = EMBED_CONTEXT_NONE;
+ return NS_OK;
+ }
+ if (tag.Equals(NS_LITERAL_STRING("area"),
+ nsCaseInsensitiveStringComparator()))
+ {
+ info->context |= EMBED_CONTEXT_LINK;
+ nsCOMPtr <nsIDOMHTMLAreaElement> area =
+ do_QueryInterface(node, &rv);
+ if (NS_SUCCEEDED(rv) && area)
+ {
+ nsAutoString href;
+ rv = area->GetHref (href);
+ if (NS_FAILED(rv))
+ return NS_ERROR_FAILURE;
+
+ SetStringProperty ("link", href);
+ }
+ }
+ else if (tag.Equals(NS_LITERAL_STRING("textarea"),
+ nsCaseInsensitiveStringComparator()) ||
+ tag.Equals(NS_LITERAL_STRING("input"),
+ nsCaseInsensitiveStringComparator()))
+ {
+ info->context |= EMBED_CONTEXT_INPUT;
+ }
+
+ nsCOMPtr<nsIDOMElement> domelement;
+ domelement = do_QueryInterface (node);
+ if (!domelement) return NS_ERROR_FAILURE;
+
+ PRBool has_background = PR_FALSE;
+
+ NS_NAMED_LITERAL_STRING(attr, "background");
+ nsAutoString value;
+ domelement->GetAttribute (attr, value);
+
+ if (!value.IsEmpty())
+ {
+ nsCAutoString bgimg;
+ const nsACString &tmp =
+ NS_ConvertUCS2toUTF8(value);
+
+ nsCOMPtr<nsIURI> uri;
+ doc->GetDocumentURL(getter_AddRefs(uri));
+ rv = uri->Resolve (tmp, bgimg);
+ if (NS_FAILED (rv))
+ return NS_ERROR_FAILURE;
+ SetStringProperty ("background_image",
+ NS_ConvertUTF8toUCS2(bgimg));
+ }
+ else
+ {
+ nsCOMPtr<nsIDOMHTMLBodyElement> bgelement;
+ bgelement = do_QueryInterface (node);
+ if (bgelement)
+ {
+ nsAutoString value;
+ bgelement->GetBackground (value);
+
+ if (!value.IsEmpty())
+ {
+ nsCAutoString bgimg;
+ const nsACString &tmp =
+ NS_ConvertUCS2toUTF8(value);
+
+ nsIURI *uri;
+ doc->GetBaseURL(uri);
+ rv = uri->Resolve
+ (tmp, bgimg);
+ SetStringProperty ("background_image",
+ NS_ConvertUTF8toUCS2(bgimg));
+ if (NS_FAILED (rv))
+ return NS_ERROR_FAILURE;
+ has_background = PR_TRUE;
+ }
+ }
+ }
+
+ if (!has_background)
+ {
+ nsAutoString cssurl;
+ rv = GetCSSBackground (node, cssurl);
+ if (NS_SUCCEEDED (rv))
+ {
+ nsCAutoString bgimg;
+ const nsACString &tmp =
+ NS_ConvertUCS2toUTF8(cssurl);
+
+ nsIURI *uri;
+ doc->GetBaseURL(uri);
+ rv = uri->Resolve
+ (tmp, bgimg);
+ SetStringProperty ("background_image",
+ NS_ConvertUTF8toUCS2(bgimg));
+ if (NS_FAILED (rv))
+ return NS_ERROR_FAILURE;
+ }
+ }
+ }
+
+ nsCOMPtr<nsIDOMNode> parentNode;
+ node->GetParentNode (getter_AddRefs(parentNode));
+ node = parentNode;
+ }
+
+ return NS_OK;
+}
+
+nsresult EventContext::GetCSSBackground (nsIDOMNode *node, nsAutoString& url)
+{
+ nsresult result;
+
+ nsCOMPtr<nsIDOMElementCSSInlineStyle> style;
+ style = do_QueryInterface (node);
+ if (!style) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIDOMCSSStyleDeclaration> decl;
+ result = style->GetStyle (getter_AddRefs(decl));
+ if (NS_FAILED(result)) return NS_ERROR_FAILURE;
+
+ nsAutoString value;
+ NS_NAMED_LITERAL_STRING(prop_bgi, "background-image");
+ decl->GetPropertyValue (prop_bgi, value);
+
+ if (value.IsEmpty())
+ {
+ NS_NAMED_LITERAL_STRING(prop_bg, "background");
+ decl->GetPropertyValue (prop_bg, value);
+ if (value.IsEmpty())
+ {
+ NS_NAMED_LITERAL_STRING(prop_bgr, "background-repeat");
+ decl->GetPropertyValue (prop_bgr, value);
+ if (value.IsEmpty())
+ return NS_ERROR_FAILURE;
+ }
+ }
+
+ PRInt32 start, end;
+ nsAutoString cssurl;
+
+ NS_NAMED_LITERAL_STRING(startsub, "url(");
+ NS_NAMED_LITERAL_STRING(endsub, ")");
+
+ start = value.Find (startsub) + 4;
+ end = value.Find (endsub);
+
+ if (start == -1 || end == -1)
+ return NS_ERROR_FAILURE;
+
+ url.Assign(Substring (value, start, end - start));
+
+ return NS_OK;
+}
+
+nsresult EventContext::GetMouseEventInfo (EphyEmbedEvent *info)
+{
+ nsresult result;
+ DOMTimeStamp ts;
+ nsIDOMMouseEvent *aMouseEvent = (nsIDOMMouseEvent*)mEvent;
+
+ aMouseEvent->GetButton ((PRUint16*)&info->mouse_button);
+ aMouseEvent->GetScreenX ((PRInt32*)&info->mouse_x);
+ aMouseEvent->GetScreenY ((PRInt32*)&info->mouse_y);
+
+ aMouseEvent->GetTimeStamp(&ts);
+ info->timestamp = ts;
+
+ /* be sure we are not clicking on the scroolbars */
+
+ nsCOMPtr<nsIDOMNSEvent> nsEvent = do_QueryInterface(aMouseEvent, &result);
+ if (NS_FAILED(result) || !nsEvent) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIDOMEventTarget> OriginalTarget;
+ result = nsEvent->GetOriginalTarget(getter_AddRefs(OriginalTarget));
+ if (NS_FAILED(result) || !OriginalTarget) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIDOMNode> OriginalNode = do_QueryInterface(OriginalTarget);
+ if (!OriginalNode) return NS_ERROR_FAILURE;
+
+ nsAutoString nodename;
+ OriginalNode->GetNodeName(nodename);
+
+ if (nodename.Equals(NS_LITERAL_STRING("xul:scrollbarbutton"),
+ nsCaseInsensitiveStringComparator()) ||
+ nodename.Equals(NS_LITERAL_STRING("xul:thumb"),
+ nsCaseInsensitiveStringComparator()) ||
+ nodename.Equals(NS_LITERAL_STRING("xul:vbox"),
+ nsCaseInsensitiveStringComparator()) ||
+ nodename.Equals(NS_LITERAL_STRING("xul:spacer"),
+ nsCaseInsensitiveStringComparator()) ||
+ nodename.Equals(NS_LITERAL_STRING("xul:slider"),
+ nsCaseInsensitiveStringComparator()))
+ return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIDOMEventTarget> EventTarget;
+ result = aMouseEvent->GetTarget(getter_AddRefs(EventTarget));
+ if (NS_FAILED(result) || !EventTarget) return NS_ERROR_FAILURE;
+
+ result = GetEventContext (EventTarget, info);
+ if (NS_FAILED(result)) return result;
+
+ /* Get the modifier */
+
+ PRBool mod_key;
+
+ info->modifier = 0;
+
+ aMouseEvent->GetAltKey(&mod_key);
+ if (mod_key) info->modifier |= GDK_MOD1_MASK;
+
+ aMouseEvent->GetShiftKey(&mod_key);
+ if (mod_key) info->modifier |= GDK_SHIFT_MASK;
+
+ aMouseEvent->GetMetaKey(&mod_key);
+ if (mod_key) info->modifier |= GDK_Meta_L;
+
+ aMouseEvent->GetCtrlKey(&mod_key);
+ if (mod_key) info->modifier |= GDK_CONTROL_MASK;
+
+ return NS_OK;
+}
+
+nsresult EventContext::IsPageFramed (nsIDOMNode *node, PRBool *Framed)
+{
+ nsresult result;
+
+ nsCOMPtr<nsIDOMDocument> mainDocument;
+ result = mWrapper->GetMainDOMDocument (getter_AddRefs(mainDocument));
+ if (NS_FAILED(result) || !mainDocument) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIDOMDocument> nodeDocument;
+ result = node->GetOwnerDocument (getter_AddRefs(nodeDocument));
+ if (NS_FAILED(result) || !nodeDocument) return NS_ERROR_FAILURE;
+
+ *Framed = (mainDocument != nodeDocument);
+
+ return NS_OK;
+}
+
+nsresult EventContext::GetTargetDocument (nsIDOMDocument **domDoc)
+{
+ if (!mDOMDocument) return NS_ERROR_FAILURE;
+
+ *domDoc = mDOMDocument.get();
+
+ NS_IF_ADDREF(*domDoc);
+
+ return NS_OK;
+}
+
+nsresult EventContext::SetIntProperty (const char *name, int value)
+{
+
+ GValue *val = g_new0 (GValue, 1);
+
+ g_value_init (val, G_TYPE_INT);
+
+ g_value_set_int (val, value);
+
+ ephy_embed_event_set_property (mEmbedEvent,
+ g_strdup (name),
+ val);
+
+ return NS_OK;
+}
+
+nsresult EventContext::SetStringProperty (const char *name, const char *value)
+{
+ GValue *val = g_new0 (GValue, 1);
+
+ g_value_init (val, G_TYPE_STRING);
+
+ g_value_set_string (val, value);
+
+ ephy_embed_event_set_property (mEmbedEvent,
+ g_strdup (name),
+ val);
+
+ return NS_OK;
+}
+
+nsresult EventContext::SetStringProperty (const char *name, const nsAString &value)
+{
+ GValue *val = g_new0 (GValue, 1);;
+ char *tmp;
+
+ tmp = ToNewCString (NS_ConvertUCS2toUTF8(value));
+
+ g_value_init (val, G_TYPE_STRING);
+
+ g_value_set_string (val, tmp);
+
+ ephy_embed_event_set_property (mEmbedEvent,
+ g_strdup (name),
+ val);
+ nsMemory::Free (tmp);
+
+ return NS_OK;
+}
diff --git a/embed/mozilla/EventContext.h b/embed/mozilla/EventContext.h
new file mode 100644
index 000000000..432bd1f53
--- /dev/null
+++ b/embed/mozilla/EventContext.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2000 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EVENT_CONTEXT_H
+#define EVENT_CONTEXT_H
+
+#include "nsIDOMMouseEvent.h"
+#include "nsIDOMKeyEvent.h"
+#include "nsIDOMEvent.h"
+#include "nsIDOMNode.h"
+#include "nsString.h"
+#include "nsIDOMHTMLAnchorElement.h"
+#include "nsIDOMNSHTMLElement.h"
+#include "nsIDOMHTMLAreaElement.h"
+#include "nsIDOMHTMLBodyElement.h"
+#include "nsIDOMElementCSSInlineStyle.h"
+#include "nsIDOMCSSStyleDeclaration.h"
+#include "nsIDOMDocument.h"
+#include "EphyWrapper.h"
+
+#include "ephy-embed.h"
+#include "ephy-embed-event.h"
+
+class EventContext
+{
+public:
+ EventContext();
+ ~EventContext();
+
+ nsresult Init (nsIDOMEvent *event, EphyWrapper *wrapper);
+
+ nsresult GetMouseEventInfo (EphyEmbedEvent *info);
+ nsresult GetTargetDocument (nsIDOMDocument **domDoc);
+
+private:
+ nsIDOMEvent *mEvent;
+ EphyWrapper *mWrapper;
+ nsCOMPtr<nsIDOMDocument> mDOMDocument;
+
+ nsresult GetEventContext (nsIDOMEventTarget *EventTarget,
+ EphyEmbedEvent *info);
+ nsresult GetCSSBackground (nsIDOMNode *node, nsAutoString& url);
+ nsresult IsPageFramed (nsIDOMNode *node, PRBool *Framed);
+ nsresult SetIntProperty (const char *name, int value);
+ nsresult SetStringProperty (const char *name, const char *value);
+ nsresult SetStringProperty (const char *name, const nsAString &value);
+ EphyEmbedEvent *mEmbedEvent;
+};
+
+#endif
diff --git a/embed/mozilla/ExternalProtocolService.cpp b/embed/mozilla/ExternalProtocolService.cpp
new file mode 100644
index 000000000..728cd0f5c
--- /dev/null
+++ b/embed/mozilla/ExternalProtocolService.cpp
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2001 Philip Langdale
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <gtk/gtk.h>
+#include <libgnome/gnome-exec.h>
+#include <libgnome/gnome-i18n.h>
+#include <libgnome/gnome-url.h>
+
+#include <nsString.h>
+#include <nsXPIDLString.h>
+#include <nsCOMPtr.h>
+#include <nsIURI.h>
+#include <nsIDOMWindow.h>
+#include <nsIWindowWatcher.h>
+#include <nsIServiceManager.h>
+#include <nsXPComFactory.h>
+
+#include "ephy-prefs.h"
+#include "eel-gconf-extensions.h"
+
+#include "ExternalProtocolService.h"
+
+#define WINDOWWATCHER_CONTRACTID "@mozilla.org/embedcomp/window-watcher;1"
+
+/* Implementation file */
+NS_IMPL_ISUPPORTS1(GExternalProtocolService, nsIExternalProtocolService)
+
+GExternalProtocolService::GExternalProtocolService()
+{
+ NS_INIT_ISUPPORTS();
+ /* member initializers and constructor code */
+}
+
+GExternalProtocolService::~GExternalProtocolService()
+{
+ /* destructor code */
+}
+
+/* boolean externalProtocolHandlerExists (in string aProtocolScheme); */
+NS_IMETHODIMP GExternalProtocolService::
+ ExternalProtocolHandlerExists(const char *aProtocolScheme,
+ PRBool *_retval)
+{
+ /* build the config key */
+ char *key = g_strconcat ("/desktop/gnome/url-handlers/",
+ aProtocolScheme,
+ "/command", NULL);
+
+ char *tmp = eel_gconf_get_string(key);
+ g_free (key);
+
+ *_retval = (tmp != NULL);
+ g_free (tmp);
+
+ return NS_OK;
+}
+
+/* void loadUrl (in nsIURI aURL); */
+NS_IMETHODIMP GExternalProtocolService::LoadUrl(nsIURI *aURL)
+{
+ nsCAutoString cSpec;
+ aURL->GetSpec (cSpec);
+ nsCAutoString cScheme;
+ aURL->GetScheme (cScheme);
+
+ if (cScheme.Equals("http"))
+ {
+ nsresult rv;
+ nsCOMPtr<nsIWindowWatcher> ww;
+ ww = do_GetService(WINDOWWATCHER_CONTRACTID, &rv);
+ if (NS_SUCCEEDED(rv))
+ {
+ nsCOMPtr<nsIDOMWindow> newWin;
+ rv = ww->OpenWindow(nsnull, cSpec.get(),
+ nsnull, nsnull, nsnull,
+ getter_AddRefs(newWin));
+ if (NS_SUCCEEDED(rv)) return NS_OK;
+ }
+ }
+
+ /* build the config key */
+ const nsCAutoString key(NS_LITERAL_CSTRING("/desktop/gnome/url-handlers/") +
+ cScheme + NS_LITERAL_CSTRING("/command"));
+
+ /* find it */
+ char *result = eel_gconf_get_string(key.get());
+ if (result)
+ {
+ gnome_url_show(cSpec.get(), NULL);
+ g_free (result);
+ return NS_OK;
+ }
+
+ /* no luck, so offer the user the option of trying the
+ * default handler -- we don't do this automatically in
+ * case the default handler is erroneously set to epiphany */
+ result = eel_gconf_get_string("/desktop/gnome/url-handlers/unknown/command");
+
+ /* check there is a default */
+ {
+ GtkWidget *dialog;
+
+ /* throw the error */
+ dialog = gtk_message_dialog_new (NULL, (GtkDialogFlags)0,
+ GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
+ _("Galeon cannot handle this protocol,\n"
+ "and no GNOME default handler is set"));
+ gtk_dialog_run (GTK_DIALOG(dialog));
+ gtk_widget_destroy (dialog);
+
+ /* don't let mozilla try blindly */
+ return NS_ERROR_FAILURE;
+ }
+ g_free (result);
+
+ /* offer the choice */
+ GtkWidget *dialog = gtk_message_dialog_new (NULL, (GtkDialogFlags)0,
+ GTK_MESSAGE_QUESTION,
+ GTK_BUTTONS_YES_NO,
+ _("The protocol specified "
+ "is not recognised.\n\n"
+ "Would you like to try "
+ "the GNOME default?"));
+
+ int ret = gtk_dialog_run (GTK_DIALOG(dialog));
+ gtk_widget_destroy (dialog);
+
+ if (ret == 0)
+ {
+ gnome_url_show(cSpec.get(), NULL);
+ return NS_OK;
+ }
+ else
+ {
+ return NS_ERROR_FAILURE;
+ }
+
+ return NS_OK;
+}
+
+NS_DEF_FACTORY (GExternalProtocolService, GExternalProtocolService);
+
+/**
+ * NS_NewExternalProtocolServiceFactory:
+ */
+nsresult NS_NewExternalProtocolServiceFactory(nsIFactory** aFactory)
+{
+ NS_ENSURE_ARG_POINTER(aFactory);
+ *aFactory = nsnull;
+
+ nsGExternalProtocolServiceFactory *result = new nsGExternalProtocolServiceFactory;
+ if (result == NULL)
+ {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+
+ NS_ADDREF(result);
+ *aFactory = result;
+
+ return NS_OK;
+}
diff --git a/embed/mozilla/ExternalProtocolService.h b/embed/mozilla/ExternalProtocolService.h
new file mode 100644
index 000000000..3c49d61e7
--- /dev/null
+++ b/embed/mozilla/ExternalProtocolService.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2001 Philip Langdale
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __ExternalProtocolService_h__
+#define __ExternalProtocolService_h__
+
+#include "nsError.h"
+#include "nsCExternalHandlerService.h"
+#include "nsIExternalProtocolService.h"
+
+class GExternalProtocolService : public nsIExternalProtocolService
+{
+ public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIEXTERNALPROTOCOLSERVICE
+
+ GExternalProtocolService();
+ virtual ~GExternalProtocolService();
+ /* additional members */
+};
+
+#define G_EXTERNALPROTOCOLSERVICE_CID \
+{ /* d2a2f743-f126-4f1f-8921-d4e50490f112 */ \
+ 0xd2a2f743, \
+ 0xf126, \
+ 0x4f1f, \
+ {0x89, 0x21, 0xd4, 0xe5, 0x04, 0x90, 0xf1, 0x12} \
+}
+#define G_EXTERNALPROTOCOLSERVICE_CLASSNAME "Galeon's ExternalProtocolService"
+
+class nsIFactory;
+
+extern nsresult NS_NewExternalProtocolServiceFactory(nsIFactory** aFactory);
+
+#endif // __ExternalProtocolService_h__
diff --git a/embed/mozilla/FilePicker.cpp b/embed/mozilla/FilePicker.cpp
new file mode 100644
index 000000000..baae069ef
--- /dev/null
+++ b/embed/mozilla/FilePicker.cpp
@@ -0,0 +1,505 @@
+/*
+ * Copyright (C) 2001 Philip Langdale
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/* Things to be aware of:
+ *
+ * This filepicker, like the mozilla one, does not make an attempt
+ * to verify the validity of the initial directory you pass it.
+ * It does check that the user doesn't give it a garbage path
+ * during use, but it is the caller's responsibility to give a
+ * sensible initial path.
+ *
+ * At the current moment, we instantiate the filepicker directly
+ * in our contenthandler where there is path verification code
+ * and else where through our C wrapper, which also does verification.
+ * If, at a future date, you need to instantiate filepicker without
+ * using the C wrapper, please verify the initial path. See
+ * ContentHandler for a way to do this.
+ */
+
+#include "ephy-string.h"
+#include "ephy-gui.h"
+#include "eel-gconf-extensions.h"
+
+#include <gtk/gtkmain.h>
+#include <gtk/gtksignal.h>
+#include <gtk/gtkmenu.h>
+#include <gtk/gtkmenuitem.h>
+#include <gtk/gtkcheckbutton.h>
+#include <gtk/gtktogglebutton.h>
+#include <gtk/gtkfilesel.h>
+#include <gtk/gtkhbbox.h>
+#include <gtk/gtkoptionmenu.h>
+#include <gtk/gtkmessagedialog.h>
+#include <libgnome/gnome-i18n.h>
+
+#include "nsIFilePicker.h"
+
+#include "nsCRT.h"
+#include "nsCOMPtr.h"
+#include "nsIFactory.h"
+#include "nsISupportsArray.h"
+#include "nsIServiceManager.h"
+#include "nsXPComFactory.h"
+
+#include "nsString.h"
+#include "nsXPIDLString.h"
+#include "nsIPrefService.h"
+#include "nsIURI.h"
+#include "nsIFileURL.h"
+#include "nsIChannel.h"
+#include "nsIFileChannel.h"
+#include "nsNetCID.h"
+#include "nsILocalFile.h"
+#include "nsIPromptService.h"
+#include "nsReadableUtils.h"
+
+#include <libgnome/gnome-util.h>
+
+#include "FilePicker.h"
+#include "MozillaPrivate.h"
+
+void filePicker_save_content_cb(GtkToggleButton *aButton,
+ GFilePicker *aFilePicker);
+
+/* Implementation file */
+NS_IMPL_ISUPPORTS1(GFilePicker, nsIFilePicker)
+
+GFilePicker::GFilePicker(PRBool showContentCheck, FileFormat *fileFormats) :
+ mSaveContent(PR_FALSE)
+{
+ NS_INIT_ISUPPORTS();
+ /* member initializers and constructor code */
+
+ mShowContentCheck = showContentCheck;
+ mFileFormats = fileFormats;
+ mFile = do_CreateInstance (NS_LOCAL_FILE_CONTRACTID);
+ mDisplayDirectory = do_CreateInstance (NS_LOCAL_FILE_CONTRACTID);
+ mDisplayDirectory->InitWithNativePath(nsDependentCString(g_get_home_dir()));
+}
+
+GFilePicker::~GFilePicker()
+{
+ /* destructor code */
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// begin nsIFilePicker impl
+////////////////////////////////////////////////////////////////////////////////
+
+/* void init (in nsIDOMWindowInternal parent, in wstring title, in short mode); */
+NS_IMETHODIMP GFilePicker::Init(nsIDOMWindowInternal *aParent,
+ const PRUnichar *aTitle, PRInt16 aMode)
+{
+ mParent = do_QueryInterface(aParent);
+ mParentWidget = MozillaFindGtkParent(mParent);
+ mTitle = NS_ConvertUCS2toUTF8(aTitle);
+ mMode = aMode;
+
+ return NS_OK;
+}
+
+/* void appendFilters (in long filterMask); */
+NS_IMETHODIMP GFilePicker::AppendFilters(PRInt32 aFilterMask)
+{
+ //This function cannot be implemented due to the crippled
+ //nature of GtkFileSelection, but NS_ERROR_NOT_IMPLEMENTED
+ //is interpreted as a terminal error by some callers.
+ return NS_OK;
+}
+
+/* void appendFilter (in wstring title, in wstring filter); */
+NS_IMETHODIMP GFilePicker::AppendFilter(const PRUnichar *aTitle,
+ const PRUnichar *aFilter)
+{
+ //GtkFileSelection is crippled, so we can't provide a short-list
+ //of filters to choose from. We provide minimal functionality
+ //by using the most recent AppendFilter call as the active filter.
+ mFilter = NS_ConvertUCS2toUTF8(aFilter);
+ return NS_OK;
+}
+
+/* attribute long filterIndex; */
+NS_IMETHODIMP GFilePicker::GetFilterIndex(PRInt32 *aFilterIndex)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+NS_IMETHODIMP GFilePicker::SetFilterIndex(PRInt32 aFilterIndex)
+{
+ return NS_OK;
+}
+
+/* attribute wstring defaultString; */
+NS_IMETHODIMP GFilePicker::GetDefaultString(PRUnichar * *aDefaultString)
+{
+ *aDefaultString = ToNewUnicode(NS_ConvertUTF8toUCS2(mDefaultString));
+ return NS_OK;
+}
+NS_IMETHODIMP GFilePicker::SetDefaultString(const PRUnichar *aDefaultString)
+{
+ if (aDefaultString)
+ mDefaultString = NS_ConvertUCS2toUTF8(aDefaultString);
+ else
+ mDefaultString = "";
+ return NS_OK;
+}
+
+/* attribute wstring defaultExtension; */
+// Again, due to the crippled file selector, we can't really
+// do anything here.
+NS_IMETHODIMP GFilePicker::GetDefaultExtension(PRUnichar * *aDefaultExtension)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+NS_IMETHODIMP GFilePicker::SetDefaultExtension(const PRUnichar *aDefaultExtension)
+{
+ return NS_OK;
+}
+
+/* attribute nsILocalFile displayDirectory; */
+NS_IMETHODIMP GFilePicker::GetDisplayDirectory(nsILocalFile * *aDisplayDirectory)
+{
+ NS_IF_ADDREF(*aDisplayDirectory = mDisplayDirectory);
+ return NS_OK;
+}
+NS_IMETHODIMP GFilePicker::SetDisplayDirectory(nsILocalFile * aDisplayDirectory)
+{
+ mDisplayDirectory = aDisplayDirectory;
+ return NS_OK;
+}
+
+/* readonly attribute nsILocalFile file; */
+NS_IMETHODIMP GFilePicker::GetFile(nsILocalFile * *aFile)
+{
+ NS_IF_ADDREF(*aFile = mFile);
+ return NS_OK;
+}
+
+/* readonly attribute nsIFileURL fileURL; */
+NS_IMETHODIMP GFilePicker::GetFileURL(nsIFileURL * *aFileURL)
+{
+ nsCOMPtr<nsIFileURL> fileURL =
+ do_CreateInstance(NS_STANDARDURL_CONTRACTID);
+ fileURL->SetFile(mFile);
+ NS_IF_ADDREF(*aFileURL = fileURL);
+ return NS_OK;
+}
+
+/* readonly attribute nsISimpleEnumerator files; */
+NS_IMETHODIMP GFilePicker::GetFiles(nsISimpleEnumerator * *aFiles)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+/* short show (); */
+NS_IMETHODIMP GFilePicker::Show(PRInt16 *_retval)
+{
+ mFileSelector = gtk_file_selection_new(mTitle.get());
+
+ nsCAutoString cFileName;
+ if(mMode == nsIFilePicker::modeGetFolder)
+ cFileName.Assign("");
+ else
+ cFileName = mDefaultString;
+
+ nsCAutoString cDirName;
+ mDisplayDirectory->GetNativePath(cDirName);
+
+ nsCAutoString cFullPath;
+ cFullPath.Assign(cDirName + NS_LITERAL_CSTRING("/") + cFileName);
+ gtk_file_selection_set_filename(GTK_FILE_SELECTION(mFileSelector),
+ cFullPath.get());
+
+ if (!mFilter.IsEmpty())
+ {
+ gtk_file_selection_complete(GTK_FILE_SELECTION(mFileSelector),
+ mFilter.get());
+ }
+
+ if (mParentWidget)
+ gtk_window_set_transient_for(GTK_WINDOW(mFileSelector),
+ GTK_WINDOW(mParentWidget));
+
+ if (mShowContentCheck)
+ {
+ GtkWidget *bbox = gtk_hbutton_box_new ();
+ gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox),
+ GTK_BUTTONBOX_END);
+ gtk_box_set_spacing(GTK_BOX(bbox), 0);
+ gtk_box_pack_end(GTK_BOX(GTK_FILE_SELECTION(mFileSelector)->action_area),
+ bbox, TRUE, TRUE, 0);
+
+ GtkWidget *saveContent =
+ gtk_check_button_new_with_label(_("Save with content"));
+ g_signal_connect(G_OBJECT(saveContent),
+ "clicked",
+ G_CALLBACK(filePicker_save_content_cb),
+ (gpointer)this);
+
+ gtk_box_pack_start(GTK_BOX(bbox), saveContent,
+ FALSE, FALSE, 0);
+
+ gtk_widget_show_all(bbox);
+ }
+
+ if (mFileFormats)
+ {
+ mFormatChooser = gtk_option_menu_new();
+ GtkMenu *options = GTK_MENU(gtk_menu_new());
+
+ FileFormat *current = mFileFormats;
+ while (current->description != NULL)
+ {
+ /* FIXME: the label should include the extensions too */
+ gchar *label = current->description;
+ GtkWidget *item = gtk_menu_item_new_with_label(label);
+ gtk_widget_show(item);
+ gtk_menu_shell_append(GTK_MENU_SHELL(options), item);
+ current++;
+ }
+ gtk_option_menu_set_menu(GTK_OPTION_MENU(mFormatChooser),
+ GTK_WIDGET(options));
+ gtk_widget_show(mFormatChooser);
+ gtk_box_pack_start(GTK_BOX(GTK_FILE_SELECTION (mFileSelector)->action_area),
+ mFormatChooser,
+ FALSE, TRUE, 0);
+ }
+ else
+ {
+ mFormatChooser = NULL;
+ }
+
+ if (mMode == nsIFilePicker::modeGetFolder)
+ {
+ gtk_widget_set_sensitive(GTK_FILE_SELECTION(mFileSelector)
+ ->file_list, FALSE);
+ }
+
+ gtk_window_set_modal(GTK_WINDOW(mFileSelector), TRUE);
+
+ gint retVal = gtk_dialog_run(GTK_DIALOG(mFileSelector));
+
+ if (retVal == GTK_RESPONSE_OK)
+ {
+ HandleFilePickerResult(_retval);
+ }
+ else
+ {
+ *_retval = returnCancel;
+ }
+
+ gtk_widget_hide(mFileSelector);
+ gtk_widget_destroy(mFileSelector);
+
+ return NS_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// begin local public methods impl
+////////////////////////////////////////////////////////////////////////////////
+
+NS_METHOD GFilePicker::InitWithGtkWidget (GtkWidget *aParentWidget,
+ const char *aTitle, PRInt16 aMode)
+{
+ mParentWidget = aParentWidget;
+
+ mTitle = nsDependentCString(aTitle);
+
+ mMode = mMode;
+
+ mFile = do_CreateInstance (NS_LOCAL_FILE_CONTRACTID);
+
+ return NS_OK;
+}
+
+NS_METHOD GFilePicker::SanityCheck (PRBool *retIsSane)
+{
+ *retIsSane = PR_TRUE;
+
+ PRBool dirExists, fileExists = PR_TRUE;
+
+ if (mDisplayDirectory)
+ {
+ mDisplayDirectory->Exists (&dirExists);
+ }
+ else
+ {
+ dirExists = PR_FALSE;
+ }
+
+ if (mMode == nsIFilePicker::modeOpen)
+ {
+ mFile->Exists (&fileExists);
+ }
+
+ if (!dirExists || !fileExists)
+ {
+ GtkWidget *errorDialog = gtk_message_dialog_new (
+ NULL,
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ _("The specified path does not exist."));
+
+ if (mParentWidget)
+ gtk_window_set_transient_for(GTK_WINDOW(errorDialog),
+ GTK_WINDOW(mFileSelector));
+
+ gtk_window_set_modal (GTK_WINDOW(errorDialog), TRUE);
+ gtk_dialog_run (GTK_DIALOG(errorDialog));
+ *retIsSane = PR_FALSE;
+ return NS_OK;
+ }
+
+ PRBool correctType;
+ char *errorText;
+ if (mMode == nsIFilePicker::modeGetFolder)
+ {
+ mDisplayDirectory->IsDirectory (&correctType);
+ errorText = g_strdup (_("A file was selected when a "
+ "folder was expected."));
+ }
+ else
+ {
+ mFile->IsFile (&correctType);
+ errorText = g_strdup (_("A folder was selected when a "
+ "file was expected."));
+ }
+
+ if(!correctType)
+ {
+ GtkWidget *errorDialog = gtk_message_dialog_new (
+ NULL,
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ errorText);
+
+ if (mParentWidget)
+ gtk_window_set_transient_for(GTK_WINDOW(errorDialog),
+ GTK_WINDOW(mFileSelector));
+
+ gtk_window_set_modal (GTK_WINDOW(errorDialog), TRUE);
+ gtk_dialog_run (GTK_DIALOG(errorDialog));
+ *retIsSane = PR_FALSE;
+ }
+ g_free (errorText);
+
+ return NS_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// begin local private methods impl
+////////////////////////////////////////////////////////////////////////////////
+
+NS_METHOD GFilePicker::HandleFilePickerResult(PRInt16 *retval)
+{
+ *retval = returnCancel;
+ nsresult rv;
+
+ const char *fileName = gtk_file_selection_get_filename(GTK_FILE_SELECTION(mFileSelector));
+
+ if (!fileName || strlen(fileName) == 0) return NS_ERROR_FAILURE;
+
+ if (mMode == nsIFilePicker::modeSave)
+ {
+ if (!ephy_gui_confirm_overwrite_file (mFileSelector,
+ fileName))
+ {
+ return NS_OK;
+ }
+ }
+
+ const nsACString &cFileName = nsDependentCString(fileName);
+ mFile->InitWithNativePath(cFileName);
+
+ if (mMode == nsIFilePicker::modeGetFolder)
+ {
+ mDisplayDirectory->InitWithNativePath(cFileName);
+ mDefaultString = "";
+ }
+ else
+ {
+ nsCOMPtr<nsIFile> directory;
+ mFile->GetParent(getter_AddRefs(directory));
+ mDisplayDirectory = do_QueryInterface(directory);
+ mFile->GetNativeLeafName(mDefaultString);
+ }
+
+ PRBool passesSanityCheck;
+ rv = SanityCheck(&passesSanityCheck);
+ if (NS_SUCCEEDED(rv) && !passesSanityCheck) return NS_ERROR_FAILURE;
+
+ if (mFormatChooser)
+ {
+ gint i = 0;
+ GtkWidget *menu = gtk_option_menu_get_menu
+ (GTK_OPTION_MENU(mFormatChooser));
+ GList *iterator = GTK_MENU_SHELL(menu)->children;
+ GtkWidget *selected = gtk_menu_get_active (GTK_MENU(menu));
+
+ while (iterator)
+ {
+ if (iterator->data == selected)
+ {
+ mSelectedFileFormat = i;
+ break;
+ }
+ iterator = iterator->next;
+ i++;
+ }
+ }
+
+ *retval = mSaveContent ? returnOKSaveContent : returnOK;
+ return NS_OK;
+}
+
+//------------------------------------------------------------------------------
+
+NS_DEF_FACTORY (GFilePicker, GFilePicker);
+
+/**
+ * NS_NewFilePickerFactory:
+ */
+nsresult NS_NewFilePickerFactory(nsIFactory** aFactory)
+{
+ NS_ENSURE_ARG_POINTER(aFactory);
+ *aFactory = nsnull;
+
+ nsGFilePickerFactory *result = new nsGFilePickerFactory;
+ if (result == NULL)
+ {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+
+ NS_ADDREF(result);
+ *aFactory = result;
+
+ return NS_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// begin FileSelector callbacks.
+////////////////////////////////////////////////////////////////////////////////
+
+void filePicker_save_content_cb(GtkToggleButton *aButton,
+ GFilePicker *aFilePicker)
+{
+ aFilePicker->mSaveContent = gtk_toggle_button_get_active (aButton) ?
+ PR_TRUE : PR_FALSE;
+}
diff --git a/embed/mozilla/FilePicker.h b/embed/mozilla/FilePicker.h
new file mode 100644
index 000000000..93c025637
--- /dev/null
+++ b/embed/mozilla/FilePicker.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2001 Philip Langdale
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef FILE_PICKER_H
+#define FILE_PICKER_H
+
+#include "nsIFilePicker.h"
+#include "nsError.h"
+#include "nsIDOMWindow.h"
+#include "nsIDOMWindowInternal.h"
+#include "nsCOMPtr.h"
+#include "nsString.h"
+#include "nsILocalFile.h"
+#include <gtk/gtktogglebutton.h>
+#include "ephy-embed-shell.h"
+
+#define G_FILEPICKER_CID \
+{ /* 3636dc79-0b42-4bad-8a3f-ae15d3671d17 */ \
+ 0x3636dc79, \
+ 0x0b42, \
+ 0x4bad, \
+ {0x8a, 0x3f, 0xae, 0x15, 0xd3, 0x67, 0x1d, 0x17} \
+}
+
+#define G_FILEPICKER_CONTRACTID "@mozilla.org/filepicker;1"
+#define G_FILEPICKER_CLASSNAME "Galeon's File Picker Implementation"
+
+class nsIFactory;
+
+extern nsresult NS_NewFilePickerFactory(nsIFactory** aFactory);
+
+/* Header file */
+class GFilePicker : public nsIFilePicker
+{
+ friend void filePicker_save_content_cb(GtkToggleButton *aButton,
+ GFilePicker *aFilePicker);
+ public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIFILEPICKER
+ enum { returnOK = nsIFilePicker::returnOK,
+ returnCancel = nsIFilePicker::returnCancel,
+ returnReplace = nsIFilePicker::returnReplace,
+ returnOKSaveContent = 256 };
+
+ GFilePicker(PRBool aShowContentCheck = PR_FALSE, FileFormat *aFileFormats = NULL);
+ virtual ~GFilePicker();
+
+ /* additional members */
+ NS_METHOD InitWithGtkWidget(GtkWidget *aParentWidget,
+ const char *aTitle, PRInt16 aMode);
+ NS_METHOD SanityCheck(PRBool *retIsSane);
+
+ PRInt16 mSelectedFileFormat;
+
+ private:
+ NS_METHOD HandleFilePickerResult(PRInt16 *retval);
+
+ nsCOMPtr<nsIDOMWindow> mParent;
+
+ nsCString mTitle;
+ nsCString mFilter;
+ nsCString mDefaultString;
+
+ nsCOMPtr<nsILocalFile> mFile;
+ nsCOMPtr<nsILocalFile> mDisplayDirectory;
+
+ PRInt16 mMode;
+
+ PRBool mShowContentCheck;
+ PRBool mSaveContent;
+
+ GtkWidget *mParentWidget;
+ GtkWidget *mFileSelector;
+ GtkWidget *mFormatChooser;
+
+ FileFormat *mFileFormats;
+};
+
+#endif
diff --git a/embed/mozilla/FtpProtocolHandler.cpp b/embed/mozilla/FtpProtocolHandler.cpp
new file mode 100644
index 000000000..a9b299095
--- /dev/null
+++ b/embed/mozilla/FtpProtocolHandler.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2001 Philip Langdale
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "nsIFactory.h"
+#include "nsXPComFactory.h"
+
+#include "BaseProtocolContentHandler.h"
+
+class GFtpProtocolHandler : public GBaseProtocolContentHandler
+{
+ public:
+ NS_DECL_ISUPPORTS
+ GFtpProtocolHandler() : GBaseProtocolContentHandler("ftp")
+ {NS_INIT_ISUPPORTS();};
+ virtual ~GFtpProtocolHandler() {};
+ /* additional members */
+};
+
+/* Implementation file */
+NS_IMPL_ISUPPORTS2 (GFtpProtocolHandler, nsIProtocolHandler, nsIContentHandler)
+
+NS_DEF_FACTORY (GFtpProtocolHandler, GFtpProtocolHandler);
+
+/**
+ * NS_NewFtpHandlerFactory:
+ */
+nsresult NS_NewFtpHandlerFactory(nsIFactory** aFactory)
+{
+ NS_ENSURE_ARG_POINTER(aFactory);
+ *aFactory = nsnull;
+
+ nsGFtpProtocolHandlerFactory *result =
+ new nsGFtpProtocolHandlerFactory;
+ if (result == NULL)
+ {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+
+ NS_ADDREF(result);
+ *aFactory = result;
+
+ return NS_OK;
+}
diff --git a/embed/mozilla/FtpProtocolHandler.h b/embed/mozilla/FtpProtocolHandler.h
new file mode 100644
index 000000000..d305501d5
--- /dev/null
+++ b/embed/mozilla/FtpProtocolHandler.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2001 Philip Langdale
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __FtpProtocolHandler_h__
+#define __FtpProtocolHandler_h__
+
+#include "nsError.h"
+#include "nsIProtocolHandler.h"
+#include "nsCURILoader.h"
+
+#define G_FTP_PROTOCOL_CID \
+{ /* 5a48bdf4-a422-4eb4-b073-0fc3bee8e670 */ \
+ 0x5a48bdf4, \
+ 0xa422, \
+ 0x4eb4, \
+ {0xb0, 0x73, 0x0f, 0xc3, 0xbe, 0xe8, 0xe6, 0x70} \
+}
+#define G_FTP_PROTOCOL_CONTRACTID NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "ftp"
+#define G_FTP_PROTOCOL_CLASSNAME "Galeon's FTP Protocol Handler"
+#define G_FTP_CONTENT_CONTRACTID NS_CONTENT_HANDLER_CONTRACTID_PREFIX \
+ "application-x-gnome-ftp"
+#define G_FTP_CONTENT_CLASSNAME "Galeon's FTP Content Handler"
+
+#define NS_FTPPROTOCOLHANDLER_CID \
+{ \
+ 0x25029490, \
+ 0xf132, \
+ 0x11d2, \
+ {0x95, 0x88, 0x0, 0x80, 0x5f, 0x36, 0x9f, 0x95} \
+}
+#define NS_FTPPROTOCOLHANDLER_CLASSNAME "The FTP Protocol Handler"
+
+class nsIFactory;
+
+extern nsresult NS_NewFtpHandlerFactory(nsIFactory** aFactory);
+
+#endif // __FtpProtocolHandler_h__
diff --git a/embed/mozilla/GlobalHistory.cpp b/embed/mozilla/GlobalHistory.cpp
new file mode 100644
index 000000000..a559dbc10
--- /dev/null
+++ b/embed/mozilla/GlobalHistory.cpp
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2001 Philip Langdale
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "mozilla-embed-shell.h"
+
+#include "nsCOMPtr.h"
+#include "nsISupportsArray.h"
+#include "nsIFactory.h"
+#include "nsIServiceManager.h"
+#include "nsXPComFactory.h"
+#include "nsString.h"
+#include "nsReadableUtils.h"
+#include "nsIGlobalHistory.h"
+#include "nsIBrowserHistory.h"
+#include "nsIRequestObserver.h"
+
+/**
+ * class GlobalHistory:
+ *
+ */
+class MozGlobalHistory: public nsIGlobalHistory,
+ public nsIBrowserHistory
+{
+ public:
+ MozGlobalHistory ();
+ virtual ~MozGlobalHistory();
+
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIGLOBALHISTORY
+ NS_DECL_NSIBROWSERHISTORY
+
+ private:
+ EphyHistory *mGlobalHistory;
+};
+
+NS_IMPL_ADDREF(MozGlobalHistory)
+NS_IMPL_RELEASE(MozGlobalHistory)
+NS_INTERFACE_MAP_BEGIN(MozGlobalHistory)
+ NS_INTERFACE_MAP_ENTRY(nsIGlobalHistory)
+ NS_INTERFACE_MAP_ENTRY(nsIBrowserHistory)
+NS_INTERFACE_MAP_END
+
+MozGlobalHistory::MozGlobalHistory ()
+{
+ NS_INIT_ISUPPORTS();
+
+ mGlobalHistory = ephy_embed_shell_get_global_history (embed_shell);
+}
+
+MozGlobalHistory::~MozGlobalHistory ()
+{
+}
+
+/* void addPage (in string aURL); */
+NS_IMETHODIMP MozGlobalHistory::AddPage (const char *aURL)
+{
+ ephy_history_add_page (mGlobalHistory, aURL);
+
+ return NS_OK;
+}
+
+/* boolean isVisited (in string aURL); */
+NS_IMETHODIMP MozGlobalHistory::IsVisited (const char *aURL, PRBool *_retval)
+{
+ *_retval = ephy_history_is_page_visited (mGlobalHistory, aURL);
+
+ return NS_OK;
+}
+
+/* void setPageTitle (in string aURL, in wstring aTitle); */
+NS_IMETHODIMP MozGlobalHistory::SetPageTitle (const char *aURL,
+ const PRUnichar *aTitle)
+{
+ const nsACString &title = NS_ConvertUCS2toUTF8 (aTitle);
+
+ ephy_history_set_page_title (mGlobalHistory, aURL, PromiseFlatCString(title).get());
+
+ /* done */
+ return NS_OK;
+}
+
+/* void removePage (in string aURL); */
+NS_IMETHODIMP MozGlobalHistory::RemovePage(const char *aURL)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+/* void removePagesFromHost (in string aHost, in boolean aEntireDomain); */
+NS_IMETHODIMP MozGlobalHistory::RemovePagesFromHost(const char *aHost,
+ PRBool aEntireDomain)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+/* void removeAllPages (); */
+NS_IMETHODIMP MozGlobalHistory::RemoveAllPages()
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+/* readonly attribute string lastPageVisited; */
+NS_IMETHODIMP MozGlobalHistory::GetLastPageVisited(char **aLastPageVisited)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP MozGlobalHistory::HidePage(const char *url)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+
+}
+
+/* readonly attribute PRUint32 count; */
+NS_IMETHODIMP MozGlobalHistory::GetCount(PRUint32 *aCount)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+/* void startBatchUpdate (); */
+NS_IMETHODIMP MozGlobalHistory::StartBatchUpdate()
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+/* void endBatchUpdate (); */
+NS_IMETHODIMP MozGlobalHistory::EndBatchUpdate()
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+/* void markPageAsTyped (in string url); */
+NS_IMETHODIMP MozGlobalHistory::MarkPageAsTyped(const char *url)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_DEF_FACTORY (MozGlobalHistory, MozGlobalHistory);
+
+nsresult NS_NewGlobalHistoryFactory(nsIFactory** aFactory)
+{
+ NS_ENSURE_ARG_POINTER(aFactory);
+ *aFactory = nsnull;
+
+ nsMozGlobalHistoryFactory *result = new nsMozGlobalHistoryFactory;
+ if (result == NULL)
+ {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+
+ NS_ADDREF(result);
+ *aFactory = result;
+
+ return NS_OK;
+}
diff --git a/embed/mozilla/GlobalHistory.h b/embed/mozilla/GlobalHistory.h
new file mode 100644
index 000000000..5b2e615a1
--- /dev/null
+++ b/embed/mozilla/GlobalHistory.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2001 Philip Langdale
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GlobalHistory_h
+#define __GlobalHistory_h
+
+#include "nsError.h"
+
+#define GALEON_GLOBALHISTORY_CID \
+ { 0xbe0c42c1, 0x39d4, 0x4271, { 0xb7, 0x9e, 0xf7, 0xaa, 0x49, 0xeb, 0x6a, 0x15}}
+
+class nsIFactory;
+
+extern nsresult NS_NewGlobalHistoryFactory(nsIFactory** aFactory);
+
+#endif
diff --git a/embed/mozilla/IRCProtocolHandler.cpp b/embed/mozilla/IRCProtocolHandler.cpp
new file mode 100644
index 000000000..b1c4d7f68
--- /dev/null
+++ b/embed/mozilla/IRCProtocolHandler.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2001 Philip Langdale
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "nsIFactory.h"
+#include "nsXPComFactory.h"
+
+#include "BaseProtocolContentHandler.h"
+
+class GIRCProtocolHandler : public GBaseProtocolContentHandler
+{
+ public:
+ NS_DECL_ISUPPORTS
+ GIRCProtocolHandler() : GBaseProtocolContentHandler("irc")
+ {NS_INIT_ISUPPORTS();};
+ virtual ~GIRCProtocolHandler() {};
+ /* additional members */
+};
+
+/* Implementation file */
+NS_IMPL_ISUPPORTS2 (GIRCProtocolHandler, nsIProtocolHandler, nsIContentHandler)
+
+NS_DEF_FACTORY (GIRCProtocolHandler, GIRCProtocolHandler);
+
+/**
+ * NS_NewIRCHandlerFactory:
+ */
+nsresult NS_NewIRCHandlerFactory(nsIFactory** aFactory)
+{
+ NS_ENSURE_ARG_POINTER(aFactory);
+ *aFactory = nsnull;
+
+ nsGIRCProtocolHandlerFactory *result =
+ new nsGIRCProtocolHandlerFactory;
+ if (result == NULL)
+ {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+
+ NS_ADDREF(result);
+ *aFactory = result;
+
+ return NS_OK;
+}
diff --git a/embed/mozilla/IRCProtocolHandler.h b/embed/mozilla/IRCProtocolHandler.h
new file mode 100644
index 000000000..149daa121
--- /dev/null
+++ b/embed/mozilla/IRCProtocolHandler.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2001 Philip Langdale
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __IRCProtocolHandler_h__
+#define __IRCProtocolHandler_h__
+
+#include "nsError.h"
+#include "nsIProtocolHandler.h"
+#include "nsCURILoader.h"
+
+#define G_IRC_PROTOCOL_CID \
+{ /* aabe33d3-7455-4d8f-87e7-43e4541ace4e */ \
+ 0xaabe33d3, \
+ 0x7455, \
+ 0x4d8f, \
+ {0x87, 0xe7, 0x43, 0xe4, 0x54, 0x1a, 0xce, 0x4e} \
+}
+#define G_IRC_PROTOCOL_CONTRACTID NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "irc"
+#define G_IRC_PROTOCOL_CLASSNAME "Galeon's irc Protocol Handler"
+#define G_IRC_CONTENT_CONTRACTID NS_CONTENT_HANDLER_CONTRACTID_PREFIX \
+ "application-x-gnome-irc"
+#define G_IRC_CONTENT_CLASSNAME "Galeon's irc Content Handler"
+
+class nsIFactory;
+
+extern nsresult NS_NewIRCHandlerFactory(nsIFactory** aFactory);
+
+#endif // __IRCProtocolHandler_h__
diff --git a/embed/mozilla/MailtoProtocolHandler.cpp b/embed/mozilla/MailtoProtocolHandler.cpp
new file mode 100644
index 000000000..946f14aff
--- /dev/null
+++ b/embed/mozilla/MailtoProtocolHandler.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2001 Philip Langdale
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "nsIFactory.h"
+#include "nsXPComFactory.h"
+#include "nsString.h"
+#include "nsIURI.h"
+#include "nsNetUtil.h"
+#include "nsIExternalProtocolService.h"
+#include "nsCExternalHandlerService.h"
+#include "nsCRT.h"
+
+#include "BaseProtocolContentHandler.h"
+
+class GMailtoProtocolHandler : public GBaseProtocolContentHandler
+{
+ public:
+ NS_DECL_ISUPPORTS
+ GMailtoProtocolHandler() : GBaseProtocolContentHandler("mailto")
+ {NS_INIT_ISUPPORTS();};
+ virtual ~GMailtoProtocolHandler() {};
+ private:
+};
+
+/* Implementation file */
+NS_IMPL_ISUPPORTS2 (GMailtoProtocolHandler, nsIProtocolHandler, nsIContentHandler)
+
+NS_DEF_FACTORY (GMailtoProtocolHandler, GMailtoProtocolHandler);
+
+/**
+ * NS_NewMailtoHandlerFactory:
+ */
+nsresult NS_NewMailtoHandlerFactory(nsIFactory** aFactory)
+{
+ NS_ENSURE_ARG_POINTER(aFactory);
+ *aFactory = nsnull;
+
+ nsGMailtoProtocolHandlerFactory *result =
+ new nsGMailtoProtocolHandlerFactory;
+ if (result == NULL)
+ {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+
+ NS_ADDREF(result);
+ *aFactory = result;
+
+ return NS_OK;
+}
diff --git a/embed/mozilla/MailtoProtocolHandler.h b/embed/mozilla/MailtoProtocolHandler.h
new file mode 100644
index 000000000..961f42c42
--- /dev/null
+++ b/embed/mozilla/MailtoProtocolHandler.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2001 Philip Langdale
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __MailtoProtocolHandler_h__
+#define __MailtoProtocolHandler_h__
+
+#include "nsError.h"
+#include "nsIProtocolHandler.h"
+#include "nsCURILoader.h"
+
+#define G_MAILTO_PROTOCOL_CID \
+{ /* aabe33d3-7455-4d8f-87e7-43e4541ace4d */ \
+ 0xaabe33d3, \
+ 0x7455, \
+ 0x4d8f, \
+ {0x87, 0xe7, 0x43, 0xe4, 0x54, 0x1a, 0xce, 0x4d} \
+}
+#define G_MAILTO_PROTOCOL_CONTRACTID NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "mailto"
+#define G_MAILTO_PROTOCOL_CLASSNAME "Galeon's mailto Protocol Handler"
+#define G_MAILTO_CONTENT_CONTRACTID NS_CONTENT_HANDLER_CONTRACTID_PREFIX \
+ "application-x-gnome-mailto"
+#define G_MAILTO_CONTENT_CLASSNAME "Galeon's mailto Content Handler"
+
+class nsIFactory;
+
+extern nsresult NS_NewMailtoHandlerFactory(nsIFactory** aFactory);
+
+#endif // __MailtoProtocolHandler_h__
diff --git a/embed/mozilla/Makefile.am b/embed/mozilla/Makefile.am
new file mode 100644
index 000000000..ef7ef9dfa
--- /dev/null
+++ b/embed/mozilla/Makefile.am
@@ -0,0 +1,108 @@
+#MOZILLA_ACDEFINES = -include $(MOZILLA_INCLUDE_ROOT)/mozilla-config.h
+MOZILLA_ACDEFINES=-DNEW_H=\<new\>
+
+INCLUDES = \
+ -I$(top_srcdir)/lib \
+ -I$(top_srcdir)/embed \
+ -I$(top_srcdir) \
+ $(WARN_CFLAGS) \
+ $(MOZILLA_COMPONENT_CFLAGS) \
+ -I$(MOZILLA_INCLUDE_ROOT) \
+ -I$(MOZILLA_INCLUDE_ROOT)/appcomps \
+ -I$(MOZILLA_INCLUDE_ROOT)/content \
+ -I$(MOZILLA_INCLUDE_ROOT)/cookie \
+ -I$(MOZILLA_INCLUDE_ROOT)/docshell \
+ -I$(MOZILLA_INCLUDE_ROOT)/dom \
+ -I$(MOZILLA_INCLUDE_ROOT)/exthandler \
+ -I$(MOZILLA_INCLUDE_ROOT)/find \
+ -I$(MOZILLA_INCLUDE_ROOT)/gfx \
+ -I$(MOZILLA_INCLUDE_ROOT)/helperAppDlg \
+ -I$(MOZILLA_INCLUDE_ROOT)/java \
+ -I$(MOZILLA_INCLUDE_ROOT)/jsconsole \
+ -I$(MOZILLA_INCLUDE_ROOT)/layout \
+ -I$(MOZILLA_INCLUDE_ROOT)/mimetype \
+ -I$(MOZILLA_INCLUDE_ROOT)/mozxfer \
+ -I$(MOZILLA_INCLUDE_ROOT)/necko \
+ -I$(MOZILLA_INCLUDE_ROOT)/necko2 \
+ -I$(MOZILLA_INCLUDE_ROOT)/nkcache \
+ -I$(MOZILLA_INCLUDE_ROOT)/oji \
+ -I$(MOZILLA_INCLUDE_ROOT)/pref \
+ -I$(MOZILLA_INCLUDE_ROOT)/progressDlg \
+ -I$(MOZILLA_INCLUDE_ROOT)/sidebar \
+ -I$(MOZILLA_INCLUDE_ROOT)/shistory \
+ -I$(MOZILLA_INCLUDE_ROOT)/uconv \
+ -I$(MOZILLA_INCLUDE_ROOT)/uriloader \
+ -I$(MOZILLA_INCLUDE_ROOT)/unicharutil \
+ -I$(MOZILLA_INCLUDE_ROOT)/wallet \
+ -I$(MOZILLA_INCLUDE_ROOT)/webbrowserpersist \
+ -I$(MOZILLA_INCLUDE_ROOT)/webbrwsr \
+ -I$(MOZILLA_INCLUDE_ROOT)/webshell \
+ -I$(MOZILLA_INCLUDE_ROOT)/widget \
+ -I$(MOZILLA_INCLUDE_ROOT)/windowwatcher \
+ -I$(MOZILLA_INCLUDE_ROOT)/typeaheadfind \
+ $(GCONF_CFLAGS) \
+ $(EPIPHANY_DEPENDENCY_CFLAGS) \
+ -DLIB_DIR=\"$(pkglibdir)\" \
+ -DG_DISABLE_DEPRECATED \
+ -DGDK_DISABLE_DEPRECATED \
+ -DGTK_DISABLE_DEPRECATED \
+ -DGDK_PIXBUF_DISABLE_DEPRECATED \
+ -DGNOME_DISABLE_DEPRECATED \
+ -DSHARE_DIR=\"$(pkgdatadir)\" \
+ $(MOZILLA_ACDEFINES)
+
+noinst_LTLIBRARIES = libephymozillaembed.la
+
+libephymozillaembed_la_SOURCES = \
+ mozilla-embed.cpp \
+ mozilla-embed.h \
+ mozilla-embed-shell.cpp \
+ mozilla-embed-shell.h \
+ mozilla-embed-persist.cpp \
+ mozilla-embed-persist.h \
+ mozilla-prefs.cpp \
+ mozilla-prefs.h \
+ mozilla-notifiers.cpp \
+ mozilla-notifiers.h \
+ mozilla-i18n.c \
+ mozilla-i18n.h \
+ BaseProtocolHandler.cpp \
+ BaseProtocolHandler.h \
+ BaseProtocolContentHandler.cpp \
+ BaseProtocolContentHandler.h \
+ ContentHandler.cpp \
+ ContentHandler.h \
+ EventContext.cpp \
+ EventContext.h \
+ FilePicker.cpp \
+ FilePicker.h \
+ FtpProtocolHandler.cpp \
+ FtpProtocolHandler.h \
+ EphyWrapper.cpp \
+ EphyWrapper.h \
+ GlobalHistory.cpp \
+ GlobalHistory.h \
+ IRCProtocolHandler.cpp \
+ IRCProtocolHandler.h \
+ MailtoProtocolHandler.cpp \
+ MailtoProtocolHandler.h \
+ MozillaPrivate.cpp \
+ MozillaPrivate.h \
+ MozRegisterComponents.cpp \
+ MozRegisterComponents.h \
+ PrintingPromptService.cpp \
+ PrintingPromptService.h \
+ PrintProgressListener.cpp \
+ PrintProgressListener.h \
+ PromptService.cpp \
+ PromptService.h \
+ ProgressListener.cpp \
+ ProgressListener.h \
+ nsUnicharUtils.cpp \
+ nsUnicharUtils.h \
+ ExternalProtocolService.cpp \
+ ExternalProtocolService.h \
+ StartHereProtocolHandler.cpp \
+ StartHereProtocolHandler.h \
+ EphyEventListener.cpp \
+ EphyEventListener.h
diff --git a/embed/mozilla/MozRegisterComponents.cpp b/embed/mozilla/MozRegisterComponents.cpp
new file mode 100644
index 000000000..3c5e64be7
--- /dev/null
+++ b/embed/mozilla/MozRegisterComponents.cpp
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2001 Philip Langdale
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "StartHereProtocolHandler.h"
+#include "ContentHandler.h"
+#include "ExternalProtocolService.h"
+#include "FilePicker.h"
+#include "FtpProtocolHandler.h"
+#include "IRCProtocolHandler.h"
+#include "MailtoProtocolHandler.h"
+#include "PromptService.h"
+#include "PrintingPromptService.h"
+#include "ProgressListener.h"
+
+#include <nsIFactory.h>
+#include <nsIComponentManager.h>
+#include <nsCOMPtr.h>
+#include <nsILocalFile.h>
+
+#include <glib.h>
+
+static NS_DEFINE_CID(kContentHandlerCID, G_CONTENTHANDLER_CID);
+static NS_DEFINE_CID(kProtocolServiceCID, G_EXTERNALPROTOCOLSERVICE_CID);
+static NS_DEFINE_CID(kFilePickerCID, G_FILEPICKER_CID);
+static NS_DEFINE_CID(kStartHereProcotolHandlerCID, G_START_HERE_PROTOCOLHANDLER_CID);
+static NS_DEFINE_CID(knsFtpProtocolHandlerCID, NS_FTPPROTOCOLHANDLER_CID);
+static NS_DEFINE_CID(kFtpHandlerCID, G_FTP_PROTOCOL_CID);
+static NS_DEFINE_CID(kIRCHandlerCID, G_IRC_PROTOCOL_CID);
+static NS_DEFINE_CID(kMailtoHandlerCID, G_MAILTO_PROTOCOL_CID);
+static NS_DEFINE_CID(kPromptServiceCID, G_PROMPTSERVICE_CID);
+static NS_DEFINE_CID(kPrintingPromptServiceCID, G_PRINTINGPROMPTSERVICE_CID);
+static NS_DEFINE_CID(kProgressDialogCID, G_PROGRESSDIALOG_CID);
+
+//RegisterFactory is local
+NS_METHOD RegisterFactory (nsresult (aFactoryFunc)(nsIFactory** aFactory),
+ const nsCID & aClass, const char *aClassName,
+ const char *aContractID, PRBool aReplace);
+
+NS_METHOD RegisterComponent (const nsCID & aClass, const char *aClassName,
+ const char *aContractID, const char *aDLLPath,
+ PRBool aReplace);
+
+//Annoying globals to track the mozilla ftp handler so it can be restored.
+static PRBool ftpRegistered = PR_FALSE;
+static nsCOMPtr<nsIFactory> nsFtpFactory;
+
+/* FIXME why we need to use "C" here ???? */
+
+extern "C" gboolean
+mozilla_register_components (void)
+{
+ gboolean ret = TRUE;
+ nsresult rv;
+
+ rv = RegisterFactory (NS_NewProgressListenerFactory, kProgressDialogCID,
+ G_PROGRESSDIALOG_CLASSNAME,
+ NS_DOWNLOAD_CONTRACTID, PR_TRUE);
+ if (NS_FAILED(rv)) ret = FALSE;
+
+ rv = RegisterFactory (NS_NewContentHandlerFactory, kContentHandlerCID,
+ NS_IHELPERAPPLAUNCHERDLG_CLASSNAME,
+ NS_IHELPERAPPLAUNCHERDLG_CONTRACTID, PR_TRUE);
+ if (NS_FAILED(rv)) ret = FALSE;
+
+ rv = RegisterFactory (NS_NewExternalProtocolServiceFactory,
+ kProtocolServiceCID,
+ G_EXTERNALPROTOCOLSERVICE_CLASSNAME,
+ NS_EXTERNALPROTOCOLSERVICE_CONTRACTID,
+ PR_TRUE);
+ if (NS_FAILED(rv)) ret = FALSE;
+
+ rv = RegisterFactory (NS_NewFilePickerFactory, kFilePickerCID,
+ G_FILEPICKER_CLASSNAME, G_FILEPICKER_CONTRACTID,
+ PR_TRUE);
+ if (NS_FAILED(rv)) ret = FALSE;
+
+ rv = RegisterFactory (NS_NewStartHereHandlerFactory,
+ kStartHereProcotolHandlerCID,
+ G_START_HERE_PROTOCOLHANDLER_CLASSNAME,
+ G_START_HERE_PROTOCOLHANDLER_CONTRACTID,
+ PR_TRUE);
+ if (NS_FAILED(rv)) ret = FALSE;
+
+ rv = RegisterFactory (NS_NewFtpHandlerFactory, kFtpHandlerCID,
+ G_FTP_CONTENT_CLASSNAME, G_FTP_CONTENT_CONTRACTID,
+ PR_TRUE);
+ if (NS_FAILED(rv)) ret = FALSE;
+
+ rv = RegisterFactory (NS_NewIRCHandlerFactory, kIRCHandlerCID,
+ G_IRC_PROTOCOL_CLASSNAME,
+ G_IRC_PROTOCOL_CONTRACTID, PR_TRUE);
+ if (NS_FAILED(rv)) ret = FALSE;
+
+ rv = RegisterFactory (NS_NewIRCHandlerFactory, kIRCHandlerCID,
+ G_IRC_CONTENT_CLASSNAME,
+ G_IRC_CONTENT_CONTRACTID, PR_TRUE);
+ if (NS_FAILED(rv)) ret = FALSE;
+
+ rv = RegisterFactory (NS_NewPromptServiceFactory, kPromptServiceCID,
+ G_PROMPTSERVICE_CLASSNAME,
+ G_PROMPTSERVICE_CONTRACTID, PR_TRUE);
+ if (NS_FAILED(rv)) ret = FALSE;
+
+ rv = RegisterFactory (NS_NewPrintingPromptServiceFactory,
+ kPrintingPromptServiceCID,
+ G_PRINTINGPROMPTSERVICE_CLASSNAME,
+ G_PRINTINGPROMPTSERVICE_CONTRACTID, PR_TRUE);
+ if (NS_FAILED(rv)) ret = FALSE;
+
+ return ret;
+}
+
+NS_METHOD RegisterFactory (nsresult (aFactoryFunc)(nsIFactory** aFactory),
+ const nsCID & aClass, const char *aClassName,
+ const char *aContractID, PRBool aReplace)
+{
+ nsresult rv = NS_OK;
+
+ nsCOMPtr<nsIFactory> factory;
+ rv = aFactoryFunc(getter_AddRefs(factory));
+ if (NS_FAILED(rv)) return rv;
+ rv = nsComponentManager::RegisterFactory(aClass, aClassName,
+ aContractID,
+ factory, aReplace);
+ return rv;
+}
+
+NS_METHOD RegisterComponent (const nsCID & aClass, const char *aClassName,
+ const char *aContractID, const char *aDLLPath,
+ PRBool aReplace)
+{
+ nsresult rv = NS_OK;
+
+ nsCOMPtr<nsILocalFile> dllFile;
+ rv = NS_NewLocalFile (NS_ConvertUTF8toUCS2(aDLLPath), PR_TRUE, getter_AddRefs (dllFile));
+ if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
+
+ rv = nsComponentManager::RegisterComponentSpec (aClass,
+ aClassName,
+ aContractID,
+ dllFile,
+ aReplace,
+ PR_FALSE);
+ return rv;
+}
+
+/**
+ * mozilla_register_FtpProtocolHandler: Register Ftp Protocol Handler
+ */
+extern "C" gboolean
+mozilla_register_FtpProtocolHandler (void)
+{
+ if (ftpRegistered == PR_TRUE) return TRUE;
+
+ nsresult rv = NS_OK;
+
+ rv = nsComponentManager::FindFactory (knsFtpProtocolHandlerCID,
+ getter_AddRefs(nsFtpFactory));
+ if (NS_FAILED(rv)) return FALSE;
+
+ rv = RegisterFactory (NS_NewFtpHandlerFactory, kFtpHandlerCID,
+ G_FTP_PROTOCOL_CLASSNAME,
+ G_FTP_PROTOCOL_CONTRACTID, PR_TRUE);
+
+ if (NS_FAILED(rv)) return FALSE;
+
+ ftpRegistered = PR_TRUE;
+ return NS_SUCCEEDED (rv) ? TRUE : FALSE;
+}
+
+/**
+ * mozilla_unregister_FtpProtocolHandler: Unregister Ftp Protocol Handler
+ */
+extern "C" gboolean
+mozilla_unregister_FtpProtocolHandler (void)
+{
+ if (ftpRegistered == PR_FALSE) return FALSE;
+
+ nsresult rv = NS_OK;
+
+ rv = nsComponentManager::RegisterFactory(knsFtpProtocolHandlerCID,
+ NS_FTPPROTOCOLHANDLER_CLASSNAME,
+ G_FTP_PROTOCOL_CONTRACTID,
+ nsFtpFactory, PR_TRUE);
+
+ ftpRegistered = PR_FALSE;
+ return NS_SUCCEEDED (rv) ? TRUE : FALSE;
+}
+
+/**
+ * mozilla_register_MailtoProtocolHandler: Register Mailto Protocol Handler
+ */
+extern "C" gboolean
+mozilla_register_MailtoProtocolHandler (void)
+{
+ nsresult rv = NS_OK;
+
+ rv = RegisterFactory (NS_NewMailtoHandlerFactory, kMailtoHandlerCID,
+ G_MAILTO_PROTOCOL_CLASSNAME,
+ G_MAILTO_PROTOCOL_CONTRACTID, PR_TRUE);
+ if (NS_FAILED(rv)) return FALSE;
+
+ rv = RegisterFactory (NS_NewMailtoHandlerFactory, kMailtoHandlerCID,
+ G_MAILTO_CONTENT_CLASSNAME,
+ G_MAILTO_CONTENT_CONTRACTID, PR_TRUE);
+ return NS_SUCCEEDED (rv) ? TRUE : FALSE;
+}
diff --git a/embed/mozilla/MozRegisterComponents.h b/embed/mozilla/MozRegisterComponents.h
new file mode 100644
index 000000000..a263d9b74
--- /dev/null
+++ b/embed/mozilla/MozRegisterComponents.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2001 Philip Langdale
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __MozRegisterComponents_h
+#define __MozRegisterComponents_h
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+gboolean mozilla_register_components (void);
+gboolean mozilla_register_FtpProtocolHandler (void);
+gboolean mozilla_unregister_FtpProtocolHandler (void);
+gboolean mozilla_register_MailtoProtocolHandler (void);
+
+G_END_DECLS
+
+#endif // __MozRegisterComponents_h
diff --git a/embed/mozilla/MozillaPrivate.cpp b/embed/mozilla/MozillaPrivate.cpp
new file mode 100644
index 000000000..a7bc50a6c
--- /dev/null
+++ b/embed/mozilla/MozillaPrivate.cpp
@@ -0,0 +1,105 @@
+#include "MozillaPrivate.h"
+
+#include <nsIServiceManagerUtils.h>
+#include <nsIWindowWatcher.h>
+#include <nsIEmbeddingSiteWindow.h>
+#include <nsIWebBrowserChrome.h>
+#include <gtkmozembed.h>
+
+GtkWidget *MozillaFindGtkParent (nsIDOMWindow *aDOMWindow)
+{
+ nsresult result;
+
+ nsCOMPtr<nsIWindowWatcher> wwatch
+ (do_GetService("@mozilla.org/embedcomp/window-watcher;1"));
+ if (!wwatch) return nsnull;
+
+ nsCOMPtr<nsIDOMWindow> domWindow(aDOMWindow);
+ if (!domWindow)
+ {
+ result = wwatch->GetActiveWindow(getter_AddRefs(domWindow));
+ if (NS_FAILED(result) || !domWindow) return nsnull;
+ }
+
+ nsCOMPtr<nsIWebBrowserChrome> windowChrome;
+ result = wwatch->GetChromeForWindow (domWindow,
+ getter_AddRefs(windowChrome));
+ if (NS_FAILED(result)) return nsnull;
+
+ nsCOMPtr<nsIEmbeddingSiteWindow> window
+ (do_QueryInterface(windowChrome, &result));
+ if (NS_FAILED(result)) return nsnull;
+
+ GtkWidget *mozembed;
+ result = window->GetSiteWindow ((void **)&mozembed);
+ if (NS_FAILED(result)) return nsnull;
+
+ return gtk_widget_get_toplevel (GTK_WIDGET(mozembed));
+}
+
+
+NS_METHOD MozillaCollatePrintSettings (const EmbedPrintInfo *info,
+ nsIPrintSettings *options)
+{
+ const static int frame_types[] = {
+ nsIPrintSettings::kFramesAsIs,
+ nsIPrintSettings::kSelectedFrame,
+ nsIPrintSettings::kEachFrameSep
+ };
+ /* these should match the order of the radiobuttons in the dialog
+ * and the paper names in the default print provider PS*/
+ const static char *PaperSizeNames[] = {
+ "Letter","Legal","Executive","A4"
+ };
+
+
+ switch (info->pages)
+ {
+ case 0:
+ break;
+ case 1:
+ options->SetPrintRange (nsIPrintSettings::kRangeSpecifiedPageRange);
+ options->SetStartPageRange (info->from_page);
+ options->SetEndPageRange (info->to_page);
+ break;
+ case 2:
+ options->SetPrintRange (nsIPrintSettings::kRangeSelection);
+ break;
+ }
+
+ options->SetMarginTop (info->top_margin);
+ options->SetMarginBottom (info->bottom_margin);
+ options->SetMarginLeft (info->left_margin);
+ options->SetMarginRight (info->right_margin);
+
+ options->SetPrinterName(NS_LITERAL_STRING("PostScript/default").get());
+
+ options->SetHeaderStrLeft(NS_ConvertUTF8toUCS2(info->header_left_string).get());
+
+ options->SetHeaderStrCenter(NS_ConvertUTF8toUCS2(info->header_center_string).get());
+
+ options->SetHeaderStrRight(NS_ConvertUTF8toUCS2(info->header_right_string).get());
+
+ options->SetFooterStrLeft(NS_ConvertUTF8toUCS2(info->footer_left_string).get());
+
+ options->SetFooterStrCenter(NS_ConvertUTF8toUCS2(info->footer_center_string).get());
+
+ options->SetFooterStrRight(NS_ConvertUTF8toUCS2(info->footer_right_string).get());
+
+ options->SetToFileName (NS_ConvertUTF8toUCS2(info->file).get());
+
+ options->SetPrintCommand (NS_ConvertUTF8toUCS2(info->printer).get());
+
+ options->SetPrintToFile (info->print_to_file);
+
+ /* native paper size formats. Our dialog does not support custom yet */
+ options->SetPaperSize (nsIPrintSettings::kPaperSizeNativeData);
+ int tps = (info->paper >= 0 || info->paper < 4) ? info->paper : 0;
+ options->SetPaperName (NS_ConvertUTF8toUCS2(PaperSizeNames[tps]).get());
+
+ options->SetPrintInColor (info->print_color);
+ options->SetOrientation (info->orientation);
+ options->SetPrintFrameType (frame_types[info->frame_type]);
+
+ return NS_OK;
+}
diff --git a/embed/mozilla/MozillaPrivate.h b/embed/mozilla/MozillaPrivate.h
new file mode 100644
index 000000000..be9ab4905
--- /dev/null
+++ b/embed/mozilla/MozillaPrivate.h
@@ -0,0 +1,9 @@
+#include <nsIPrintSettings.h>
+#include <nsIDOMWindow.h>
+
+#include "ephy-embed.h"
+
+GtkWidget *MozillaFindGtkParent (nsIDOMWindow *aDOMWindow);
+
+NS_METHOD MozillaCollatePrintSettings (const EmbedPrintInfo *info,
+ nsIPrintSettings *settings);
diff --git a/embed/mozilla/PrintProgressListener.cpp b/embed/mozilla/PrintProgressListener.cpp
new file mode 100644
index 000000000..b4cf7b701
--- /dev/null
+++ b/embed/mozilla/PrintProgressListener.cpp
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2002 Philip Langdale
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "libgnomevfs/gnome-vfs-mime-handlers.h"
+
+/* see the FIXME below */
+#include <locale.h>
+
+#include <libgnome/gnome-exec.h>
+
+#include "PrintProgressListener.h"
+
+
+NS_IMPL_ISUPPORTS1(GPrintListener, nsIWebProgressListener)
+
+GPrintListener::GPrintListener()
+{
+ NS_INIT_ISUPPORTS();
+ mFilename = NULL;
+}
+
+GPrintListener::GPrintListener(char *filename)
+{
+ GPrintListener ();
+ mFilename = filename ? g_strdup (filename) : NULL;
+}
+
+GPrintListener::~GPrintListener()
+{
+ g_free (mFilename);
+}
+
+/* void onStateChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long aStateFlags, in unsigned long aStatus); */
+NS_IMETHODIMP GPrintListener::OnStateChange(nsIWebProgress *aWebProgress,
+ nsIRequest *aRequest,
+ PRUint32 aStateFlags,
+ PRUint32 aStatus)
+{
+ if (aStateFlags & nsIWebProgressListener::STATE_STOP)
+ {
+ GnomeVFSMimeApplication *app;
+ gchar *command;
+
+ /* FIXME(MOZILLA) ugly workaround for a mozilla problem with
+ * reseting the LC_* environment when printing */
+ setlocale(LC_ALL,"");
+ if (!mFilename) return NS_OK;
+
+ /* get the postscript handler */
+ app = gnome_vfs_mime_get_default_application
+ ("application/postscript");
+ if (app)
+ {
+ command = g_strconcat (app->command, " ",
+ mFilename, NULL);
+ gnome_execute_shell (g_get_home_dir(), command);
+ gnome_vfs_mime_application_free (app);
+ g_free (command);
+ }
+ else return NS_ERROR_FAILURE;
+ }
+ return NS_OK;
+}
+
+/* void onProgressChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long aCurSelfProgress, in long aMaxSelfProgress, in long aCurTotalProgress, in long aMaxTotalProgress); */
+NS_IMETHODIMP GPrintListener::OnProgressChange(nsIWebProgress *aWebProgress,
+ nsIRequest *aRequest,
+ PRInt32 aCurSelfProgress,
+ PRInt32 aMaxSelfProgress,
+ PRInt32 aCurTotalProgress,
+ PRInt32 aMaxTotalProgress)
+{
+ return NS_OK;
+}
+
+/* void onLocationChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsIURI location); */
+NS_IMETHODIMP GPrintListener::OnLocationChange(nsIWebProgress *aWebProgress,
+ nsIRequest *aRequest,
+ nsIURI *location)
+{
+ return NS_OK;
+}
+
+/* void onStatusChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsresult aStatus, in wstring aMessage); */
+NS_IMETHODIMP GPrintListener::OnStatusChange(nsIWebProgress *aWebProgress,
+ nsIRequest *aRequest,
+ nsresult aStatus,
+ const PRUnichar *aMessage)
+{
+ return NS_OK;
+}
+
+/* void onSecurityChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long state); */
+NS_IMETHODIMP GPrintListener::OnSecurityChange(nsIWebProgress *aWebProgress,
+ nsIRequest *aRequest,
+ PRUint32 state)
+{
+ return NS_OK;
+}
+
+
diff --git a/embed/mozilla/PrintProgressListener.h b/embed/mozilla/PrintProgressListener.h
new file mode 100644
index 000000000..82577d8ea
--- /dev/null
+++ b/embed/mozilla/PrintProgressListener.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2002 Philip Langdale
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __PrintProgressListener_h_
+#define __PrintProgressListener_h_
+
+#include "nsIWebProgressListener.h"
+
+class GPrintListener : public nsIWebProgressListener
+{
+public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIWEBPROGRESSLISTENER
+
+ GPrintListener();
+ GPrintListener(char *filename);
+ virtual ~GPrintListener();
+
+private:
+ char *mFilename;
+};
+
+#endif //__PrintProgressListener_h_
diff --git a/embed/mozilla/PrintingPromptService.cpp b/embed/mozilla/PrintingPromptService.cpp
new file mode 100644
index 000000000..6d1430ddc
--- /dev/null
+++ b/embed/mozilla/PrintingPromptService.cpp
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2002 Philip Langdale
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gtk/gtkdialog.h>
+
+#include "print-dialog.h"
+#include "ephy-embed.h"
+#include "MozillaPrivate.h"
+
+#include <nsIPrintSettings.h>
+#include <nsCOMPtr.h>
+#include <nsIFactory.h>
+#include <nsString.h>
+#include <nsIServiceManager.h>
+#include <nsXPComFactory.h>
+
+#include <nsIPrintingPromptService.h>
+
+/* Header file */
+class GPrintingPromptService : public nsIPrintingPromptService
+{
+public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIPRINTINGPROMPTSERVICE
+
+ GPrintingPromptService();
+ virtual ~GPrintingPromptService();
+ /* additional members */
+};
+
+/* Implementation file */
+NS_IMPL_ISUPPORTS1(GPrintingPromptService, nsIPrintingPromptService)
+
+GPrintingPromptService::GPrintingPromptService()
+{
+ NS_INIT_ISUPPORTS();
+ /* member initializers and constructor code */
+}
+
+GPrintingPromptService::~GPrintingPromptService()
+{
+ /* destructor code */
+}
+
+/* void showPrintDialog (in nsIDOMWindow parent, in nsIWebBrowserPrint webBrowserPrint, in nsIPrintSettings printSettings); */
+NS_IMETHODIMP GPrintingPromptService::ShowPrintDialog(nsIDOMWindow *parent, nsIWebBrowserPrint *webBrowserPrint, nsIPrintSettings *printSettings)
+{
+ EphyDialog *dialog;
+ EmbedPrintInfo *info;
+
+ GtkWidget *gtkParent = MozillaFindGtkParent(parent);
+
+ dialog = print_dialog_new_with_parent (gtkParent, NULL, &info);
+ ephy_dialog_set_modal (dialog, TRUE);
+
+ gint ret = ephy_dialog_run (dialog);
+ if(ret == GTK_RESPONSE_OK)
+ {
+ MozillaCollatePrintSettings(info, printSettings);
+ print_free_info(info);
+
+ return NS_OK;
+ }
+ else
+ return NS_ERROR_FAILURE;
+}
+
+/* void showProgress (in nsIDOMWindow parent, in nsIWebBrowserPrint webBrowserPrint, in nsIPrintSettings printSettings, in nsIObserver openDialogObserver, in boolean isForPrinting, out nsIWebProgressListener webProgressListener, out nsIPrintProgressParams printProgressParams, out boolean notifyOnOpen); */
+NS_IMETHODIMP GPrintingPromptService::ShowProgress(nsIDOMWindow *parent, nsIWebBrowserPrint *webBrowserPrint, nsIPrintSettings *printSettings, nsIObserver *openDialogObserver, PRBool isForPrinting, nsIWebProgressListener **webProgressListener, nsIPrintProgressParams **printProgressParams, PRBool *notifyOnOpen)
+{
+ printf("GPrintingPromptService::ShowProgress called\n");
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+/* void showPageSetup (in nsIDOMWindow parent, in nsIPrintSettings printSettings, in nsIObserver printObserver); */
+NS_IMETHODIMP GPrintingPromptService::ShowPageSetup(nsIDOMWindow *parent, nsIPrintSettings *printSettings,
+ nsIObserver *printObserver)
+{
+ printf("GPrintingPromptService::ShowPageSetup called\n");
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+/* void showPrinterProperties (in nsIDOMWindow parent, in wstring printerName, in nsIPrintSettings printSettings); */
+NS_IMETHODIMP GPrintingPromptService::ShowPrinterProperties(nsIDOMWindow *parent, const PRUnichar *printerName, nsIPrintSettings *printSettings)
+{
+ printf("GPrintingPromptService::ShowPrinterProperties called\n");
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_DEF_FACTORY (GPrintingPromptService, GPrintingPromptService);
+
+/**
+ * NS_NewPromptServiceFactory:
+ */
+nsresult NS_NewPrintingPromptServiceFactory(nsIFactory** aFactory)
+{
+ NS_ENSURE_ARG_POINTER(aFactory);
+ *aFactory = nsnull;
+
+ nsGPrintingPromptServiceFactory *result = new nsGPrintingPromptServiceFactory;
+ if (result == NULL)
+ {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+
+ NS_ADDREF(result);
+ *aFactory = result;
+
+ return NS_OK;
+}
diff --git a/embed/mozilla/PrintingPromptService.h b/embed/mozilla/PrintingPromptService.h
new file mode 100644
index 000000000..08024c632
--- /dev/null
+++ b/embed/mozilla/PrintingPromptService.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2000 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __PrintingPromptService_h
+#define __PrintingPromptService_h
+
+#include "nsError.h"
+
+#define G_PRINTINGPROMPTSERVICE_CID \
+{ /* 5998a2d3-88ea-4c52-b4bb-4e7abd0d35e0 */ \
+ 0x5998a2d3, \
+ 0x88ea, \
+ 0x4c52, \
+ {0xb4, 0xbb, 0x4e, 0x7a, 0xbd, 0x0d, 0x35, 0xe0} \
+}
+
+#define G_PRINTINGPROMPTSERVICE_CLASSNAME "Galeon's Printing Prompt Service"
+#define G_PRINTINGPROMPTSERVICE_CONTRACTID "@mozilla.org/embedcomp/printingprompt-service;1"
+class nsIFactory;
+
+extern nsresult NS_NewPrintingPromptServiceFactory(nsIFactory** aFactory);
+
+#endif
diff --git a/embed/mozilla/ProgressListener.cpp b/embed/mozilla/ProgressListener.cpp
new file mode 100644
index 000000000..aed42d97a
--- /dev/null
+++ b/embed/mozilla/ProgressListener.cpp
@@ -0,0 +1,718 @@
+/*
+ * Copyright (C) 2001 Philip Langdale, Matthew Aubury
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "ProgressListener.h"
+
+#include "eel-gconf-extensions.h"
+#include "ephy-file-helpers.h"
+
+#include <unistd.h>
+#include <libgnome/gnome-exec.h>
+#include <libgnome/gnome-i18n.h>
+
+#include "nsXPIDLString.h"
+#include "nsIChannel.h"
+#include "nsIFTPChannel.h"
+#include "nsIFactory.h"
+#include "nsXPComFactory.h"
+#include "nsIMIMEInfo.h"
+#include "nsCOMPtr.h"
+
+static void
+download_remove_cb (DownloaderView *dv, GProgressListener *Progress);
+static void
+download_resume_cb (DownloaderView *dv, GProgressListener *Progress);
+static void
+download_pause_cb (DownloaderView *dv, GProgressListener *Progress);
+
+NS_IMPL_ISUPPORTS4 (GProgressListener, nsIDownload, nsIWebProgressListener,
+ nsIProgressDialog, nsISupportsWeakReference)
+
+//---------------------------------------------------------------------------
+
+//---------------------------------------------------------------------------
+
+GProgressListener::GProgressListener () : mLauncher(nsnull),
+ mPersist(nsnull),
+ mHandler(nsnull),
+ mObserver(nsnull),
+ mMIMEInfo(nsnull),
+ mPercentComplete(0)
+{
+ NS_INIT_ISUPPORTS ();
+}
+
+GProgressListener::~GProgressListener ()
+{
+ /* destructor code */
+}
+
+NS_METHOD GProgressListener::InitForPersist (nsIWebBrowserPersist *aPersist,
+ nsIDOMWindow *aParent,
+ nsIURI *aURI,
+ nsIFile *aFile,
+ DownloadAction aAction,
+ EphyEmbedPersist *ephyPersist,
+ PRBool noDialog,
+ PRInt64 aTimeDownloadStarted)
+{
+ nsresult rv;
+
+ /* fill in download details */
+ mAction = aAction;
+ mParent = aParent;
+ mNoDialog = noDialog;
+ mUri = aURI;
+ mFile = aFile;
+ mPersist = aPersist;
+ mTimeDownloadStarted = aTimeDownloadStarted;
+ mEphyPersist = ephyPersist;
+
+ /* do remaining init */
+ rv = PrivateInit ();
+
+ /* pick up progress messages */
+ mPersist->SetProgressListener (this);
+
+ /* done */
+ return rv;
+}
+
+NS_METHOD GProgressListener::InitForDownload (nsIHelperAppLauncher *aLauncher,
+ nsISupports *aContext,
+ GContentHandler *aHandler,
+ DownloadAction aAction)
+{
+ nsresult rv;
+
+ mNoDialog = 0;
+
+ /* fill in download details */
+ mAction = aAction;
+ mParent = do_QueryInterface (aContext);
+ mNoDialog = PR_TRUE;
+ mHandler = aHandler;
+ mLauncher = aLauncher;
+ rv = mLauncher->GetDownloadInfo (getter_AddRefs (mUri),
+ &mTimeDownloadStarted,
+ getter_AddRefs (mFile));
+
+ /* do remaining init */
+ rv = PrivateInit ();
+
+ /* pick up progress messages */
+ mLauncher->SetWebProgressListener (this);
+
+ /* done */
+ return rv;
+}
+
+NS_METHOD GProgressListener::PrivateInit (void)
+{
+ nsresult rv;
+
+ /* setup this download */
+ mInterval = 500000; /* in microsecs == 500ms == 0.5s */
+ mPriorKRate = 0;
+ mRateChanges = 0;
+ mRateChangeLimit = 2; /* only update rate every second */
+ mCheckedCanPause = PR_FALSE;
+ mCanPause = PR_FALSE;
+ mIsPaused = PR_FALSE;
+ mAbort = PR_FALSE;
+ PRInt64 now = PR_Now ();
+ mLastUpdate = now;
+
+// mStartTime = (mTimeDownloadStarted != 0 ?
+// mTimeDownloadStarted : now);
+ mStartTime = now; //Stupid mozilla race condition
+
+ mElapsed = now - mStartTime;
+
+ if (!mNoDialog)
+ {
+ gchar *filename, *source, *dest;
+ nsAutoString uTmp;
+ nsCAutoString cTmp;
+
+ rv = mFile->GetLeafName (uTmp);
+ filename = g_strdup (NS_ConvertUCS2toUTF8(uTmp).get());
+
+ rv = mFile->GetPath (uTmp);
+ dest = g_strdup (NS_ConvertUCS2toUTF8(uTmp).get());
+
+ rv = mUri->GetSpec (cTmp);
+ source = g_strdup (cTmp.get());
+ DownloaderView *dv;
+ dv = ephy_embed_shell_get_downloader_view (embed_shell);
+ downloader_view_add_download (dv, filename, source, dest, (gpointer)this);
+ g_signal_connect (G_OBJECT (dv),
+ "download_remove",
+ G_CALLBACK (download_remove_cb),
+ this);
+ g_signal_connect (G_OBJECT (dv),
+ "download_pause",
+ G_CALLBACK (download_pause_cb),
+ this);
+ g_signal_connect (G_OBJECT (dv),
+ "download_resume",
+ G_CALLBACK (download_resume_cb),
+ this);
+ mDownloaderView = dv;
+ }
+
+ /* done */
+ return NS_OK;
+}
+
+NS_IMETHODIMP GProgressListener::Init(nsIURI *aSource,
+ nsILocalFile *aTarget,
+ const PRUnichar *aDisplayName,
+ nsIMIMEInfo *aMIMEInfo,
+ PRInt64 aStartTime,
+ nsIWebBrowserPersist *aPersist)
+{
+ mUri = aSource;
+ mFile = aTarget;
+ mTimeDownloadStarted = aStartTime;
+ mStartTime = aStartTime;
+ mPersist = aPersist;
+ mMIMEInfo = aMIMEInfo;
+ mAction = ACTION_NONE;
+ if(mMIMEInfo)
+ {
+ nsMIMEInfoHandleAction mimeAction;
+ if(NS_SUCCEEDED(mMIMEInfo->GetPreferredAction(&mimeAction)))
+ {
+ mAction = (mimeAction == nsIMIMEInfo::useHelperApp) ?
+ ACTION_SAVEFORHELPER : ACTION_NONE;
+ }
+ }
+ mNoDialog = 0;
+
+ return PrivateInit();
+}
+
+NS_IMETHODIMP GProgressListener::Open(nsIDOMWindow *aParent)
+{
+ mParent = aParent;
+ mNoDialog = 0;
+
+ return NS_OK;
+}
+
+/* attribute long long startTime; */
+NS_IMETHODIMP GProgressListener::GetStartTime(PRInt64 *aStartTime)
+{
+ *aStartTime = mStartTime;
+ return NS_OK;
+}
+
+/* attribute nsIURI source; */
+NS_IMETHODIMP GProgressListener::GetSource(nsIURI * *aSource)
+{
+ NS_IF_ADDREF(*aSource = mUri);
+ return NS_OK;
+}
+
+/* attribute nsILocalFile target; */
+NS_IMETHODIMP GProgressListener::GetTarget(nsILocalFile * *aTarget)
+{
+ nsCOMPtr<nsILocalFile> localFile = do_QueryInterface(mFile);
+ NS_IF_ADDREF(*aTarget = localFile);
+ return NS_OK;
+}
+
+NS_IMETHODIMP GProgressListener::GetMIMEInfo(nsIMIMEInfo * *aMIMEInfo)
+{
+ NS_IF_ADDREF(*aMIMEInfo = mMIMEInfo);
+ return NS_OK;
+}
+
+/* attribute nsIObserver observer; */
+NS_IMETHODIMP GProgressListener::GetObserver(nsIObserver * *aObserver)
+{
+ NS_IF_ADDREF(*aObserver = mObserver);
+ return NS_OK;
+}
+NS_IMETHODIMP GProgressListener::SetObserver(nsIObserver * aObserver)
+{
+ mObserver = aObserver;
+ return NS_OK;
+}
+
+/* attribute nsIWebProgressListener listener; */
+NS_IMETHODIMP GProgressListener::GetListener(nsIWebProgressListener * *aListener)
+{
+ *aListener = nsnull;
+ return NS_OK;
+}
+NS_IMETHODIMP GProgressListener::SetListener(nsIWebProgressListener * aListener)
+{
+ return NS_OK;
+}
+
+/* readonly attribute PRInt32 percentComplete; */
+NS_IMETHODIMP GProgressListener::GetPercentComplete(PRInt32 *aPercentComplete)
+{
+ return *aPercentComplete = mPercentComplete;
+}
+
+/* attribute wstring displayName; */
+NS_IMETHODIMP GProgressListener::GetDisplayName(PRUnichar * *aDisplayName)
+{
+ *aDisplayName = nsnull;
+ return NS_OK;
+}
+NS_IMETHODIMP GProgressListener::SetDisplayName(const PRUnichar * aDisplayName)
+{
+ return NS_OK;
+}
+
+NS_IMETHODIMP GProgressListener::GetPersist(nsIWebBrowserPersist * *aPersist)
+{
+ NS_IF_ADDREF(*aPersist = mPersist);
+ return NS_OK;
+}
+
+NS_IMETHODIMP GProgressListener::SetDialog(nsIDOMWindow *aDialog)
+{
+ return NS_OK;
+}
+
+NS_IMETHODIMP GProgressListener::GetDialog(nsIDOMWindow * *aDialog)
+{
+ *aDialog = nsnull;
+ return NS_OK;
+}
+
+/* attribute PRBool cancelDownloadOnClose; */
+NS_IMETHODIMP GProgressListener::GetCancelDownloadOnClose(PRBool *aCancelDownloadOnClose)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP GProgressListener::SetCancelDownloadOnClose(PRBool aCancelDownloadOnClose)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP GProgressListener::LaunchHandler (PersistHandlerInfo *handler)
+{
+ nsresult rv;
+ nsCOMPtr<nsIExternalHelperAppService> helperService =
+ do_GetService (NS_EXTERNALHELPERAPPSERVICE_CONTRACTID);
+
+ nsCOMPtr<nsPIExternalAppLauncher> appLauncher =
+ do_QueryInterface (helperService, &rv);
+ if (NS_SUCCEEDED(rv))
+ {
+ appLauncher->DeleteTemporaryFileOnExit(mFile);
+ }
+
+ nsAutoString uFileName;
+
+ mFile->GetPath(uFileName);
+ const nsACString &cFileName = NS_ConvertUCS2toUTF8(uFileName);
+
+ char *fname = g_strdup(PromiseFlatCString(cFileName).get());
+ ephy_file_launch_application (handler->command,
+ fname,
+ handler->need_terminal);
+ g_free (fname);
+
+ return NS_OK;
+}
+
+/*
+ * void onStateChange (in nsIWebProgress aWebProgress,
+ * in nsIRequest aRequest,
+ * in long aStateFlags,
+ * in unsigned long aStatus);
+ */
+NS_IMETHODIMP GProgressListener::OnStateChange (nsIWebProgress *aWebProgress,
+ nsIRequest *aRequest,
+ PRUint32 aStateFlags,
+ PRUint32 aStatus)
+{
+ if (mAbort) return NS_ERROR_FAILURE;
+
+ if (aStateFlags & nsIWebProgressListener::STATE_STOP)
+ {
+ switch (mAction)
+ {
+ case ACTION_SAVEFORHELPER:
+ LaunchHelperApp();
+ break;
+
+ case ACTION_NONE:
+ if (mLauncher)
+ {
+ mLauncher->CloseProgressWindow ();
+ }
+ break;
+ case ACTION_OBJECT_NOTIFY:
+
+ g_return_val_if_fail (IS_EPHY_EMBED_PERSIST (mEphyPersist),
+ NS_ERROR_FAILURE);
+
+ PersistHandlerInfo *handler;
+
+ g_object_get (mEphyPersist,
+ "handler", &handler,
+ NULL);
+
+ if (handler)
+ {
+ LaunchHandler (handler);
+ }
+
+ g_signal_emit_by_name (mEphyPersist, "completed");
+ }
+
+ if (!mNoDialog)
+ {
+ downloader_view_set_download_status (mDownloaderView,
+ DOWNLOAD_STATUS_COMPLETED,
+ (gpointer)this);
+ }
+ }
+
+ /* done */
+ return NS_OK;
+}
+
+/*
+ * void onProgressChange (in nsIWebProgress aWebProgress,
+ * in nsIRequest aRequest,
+ * in long aCurSelfProgress,
+ * in long aMaxSelfProgress,
+ * in long aCurTotalProgress,
+ * in long aMaxTotalProgress);
+ */
+NS_IMETHODIMP GProgressListener::
+ OnProgressChange (nsIWebProgress *aWebProgress,
+ nsIRequest *aRequest,
+ PRInt32 aCurSelfProgress,
+ PRInt32 aMaxSelfProgress,
+ PRInt32 aCurTotalProgress,
+ PRInt32 aMaxTotalProgress)
+{
+ if (mAbort) return NS_ERROR_FAILURE;
+
+ /* FIXME maxsize check here */
+
+ if (mNoDialog) return NS_OK;
+
+ if (!mCheckedCanPause)
+ {
+ mCheckedCanPause = PR_TRUE;
+
+ nsresult rv;
+ nsCOMPtr<nsIFTPChannel> channel =
+ do_QueryInterface (aRequest, &rv);
+
+ mCanPause = (NS_SUCCEEDED (rv) ? PR_TRUE : PR_FALSE);
+ }
+ mRequest = aRequest;
+
+ PRInt64 now = PR_Now ();
+
+ /* get out if we're updating too quickly */
+ if ((now - mLastUpdate < mInterval) &&
+ (aMaxTotalProgress != -1) &&
+ (aCurTotalProgress < aMaxTotalProgress))
+ {
+ return NS_OK;
+ }
+
+ /* compute elapsed time */
+ mLastUpdate = now;
+ mElapsed = now - mStartTime;
+
+ /* compute size done */
+ PRInt32 currentKBytes = (PRInt32)(aCurTotalProgress / 1024.0 + 0.5);
+
+ /* compute total size */
+ PRInt32 totalKBytes = (PRInt32)(aMaxTotalProgress / 1024.0 + 0.5);
+
+ /* compute progress value */
+ gfloat progress = -1;
+ if (aMaxTotalProgress > 0)
+ {
+ progress = (gfloat)aCurTotalProgress /
+ (gfloat)aMaxTotalProgress;
+ }
+
+ /* compute download rate */
+ gfloat speed = -1;
+ PRInt64 currentRate;
+ if (mElapsed)
+ {
+ currentRate = ((PRInt64)(aCurTotalProgress)) * 1000000 /
+ mElapsed;
+ }
+ else
+ {
+ currentRate = 0;
+ }
+
+ if (!mIsPaused)
+ {
+ if (currentRate)
+ {
+ PRFloat64 currentKRate = ((PRFloat64)currentRate)/1024;
+ if (currentKRate != mPriorKRate)
+ {
+ if (mRateChanges++ == mRateChangeLimit)
+ {
+ mPriorKRate = currentKRate;
+ mRateChanges = 0;
+ }
+ else
+ {
+ currentKRate = mPriorKRate;
+ }
+ }
+ else
+ {
+ mRateChanges = 0;
+ }
+
+ speed = currentKRate;
+ }
+ }
+
+ /* compute time remaining */
+ gint remaining = -1;
+ if (currentRate && (aMaxTotalProgress > 0))
+ {
+ remaining =
+ (gint)((aMaxTotalProgress - aCurTotalProgress)
+ /currentRate +.5);
+ }
+
+ downloader_view_set_download_progress (mDownloaderView,
+ mElapsed,
+ remaining,
+ speed,
+ totalKBytes,
+ currentKBytes,
+ progress,
+ mCanPause,
+ (gpointer)this);
+
+ /* done */
+ return NS_OK;
+}
+
+/* void onLocationChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsIURI location); */
+NS_IMETHODIMP GProgressListener::
+ OnLocationChange(nsIWebProgress *aWebProgress,
+ nsIRequest *aRequest, nsIURI *location)
+{
+ return NS_OK;
+}
+
+/* void onStatusChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsresult aStatus, in wstring aMessage); */
+NS_IMETHODIMP GProgressListener::
+ OnStatusChange(nsIWebProgress *aWebProgress,
+ nsIRequest *aRequest, nsresult aStatus,
+ const PRUnichar *aMessage)
+{
+ return NS_OK;
+}
+
+/* void onSecurityChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long state); */
+NS_IMETHODIMP GProgressListener::
+ OnSecurityChange(nsIWebProgress *aWebProgress,
+ nsIRequest *aRequest,
+ PRUint32 state)
+{
+ return NS_OK;
+}
+
+//---------------------------------------------------------------------------
+
+NS_METHOD GProgressListener::LaunchHelperApp (void)
+{
+ if (!mMIMEInfo)
+ return NS_ERROR_FAILURE;
+
+ nsresult rv;
+
+ nsCOMPtr<nsIFile> helperFile;
+ rv = mMIMEInfo->GetPreferredApplicationHandler(getter_AddRefs(helperFile));
+ if(NS_FAILED(rv)) return NS_ERROR_FAILURE;
+
+ nsCAutoString helperFileName;
+ rv = helperFile->GetNativePath(helperFileName);
+ if(NS_FAILED(rv)) return NS_ERROR_FAILURE;
+
+ nsMIMEInfoHandleAction mimeAction;
+ rv = mMIMEInfo->GetPreferredAction(&mimeAction);
+ if(NS_FAILED(rv)) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIExternalHelperAppService> helperService =
+ do_GetService (NS_EXTERNALHELPERAPPSERVICE_CONTRACTID, &rv);
+ if (NS_SUCCEEDED(rv))
+ {
+ nsCOMPtr<nsPIExternalAppLauncher> appLauncher =
+ do_QueryInterface (helperService, &rv);
+ if (NS_SUCCEEDED(rv))
+ {
+ appLauncher->DeleteTemporaryFileOnExit(mFile);
+ }
+ }
+
+ nsCAutoString cFileName;
+ mFile->GetNativePath(cFileName);
+ if(NS_FAILED(rv)) return NS_ERROR_FAILURE;
+
+ nsXPIDLString helperDesc;
+ rv = mMIMEInfo->GetApplicationDescription(getter_Copies(helperDesc));
+ if(NS_FAILED(rv)) return NS_ERROR_FAILURE;
+
+ gboolean terminalHelper =
+ helperDesc.Equals(NS_LITERAL_STRING("runInTerminal")) ?
+ TRUE : FALSE;
+
+ ephy_file_launch_application (helperFileName.get(),
+ cFileName.get(),
+ terminalHelper);
+
+ return NS_OK;
+}
+
+nsresult GProgressListener::Pause (void)
+{
+ nsresult rv;
+
+ if (mCanPause && !mIsPaused)
+ {
+ rv = mRequest->Suspend ();
+ if (NS_SUCCEEDED (rv))
+ {
+ mIsPaused = PR_TRUE;
+ }
+ }
+ else
+ {
+ rv = NS_ERROR_FAILURE;
+ }
+
+ return rv;
+}
+
+nsresult GProgressListener::Resume (void)
+{
+ nsresult rv;
+
+ if (mCanPause && mIsPaused)
+ {
+ rv = mRequest->Resume ();
+ if (NS_SUCCEEDED (rv))
+ {
+ mIsPaused = PR_FALSE;
+ }
+ }
+ else
+ {
+ rv = NS_ERROR_FAILURE;
+ }
+
+ return rv;
+}
+
+nsresult GProgressListener::Abort (void)
+{
+ mAction = ACTION_NONE;
+
+ if (mIsPaused)
+ {
+ Resume ();
+ }
+
+ mAbort = PR_TRUE;
+
+ if (mObserver)
+ {
+ mObserver->Observe(NS_ISUPPORTS_CAST(nsIProgressDialog*, this),
+ "oncancel", nsnull);
+ OnStateChange(nsnull, nsnull,
+ nsIWebProgressListener::STATE_STOP, 0);
+ }
+
+ if (mPersist)
+ {
+ return mPersist->CancelSave ();
+ }
+
+ if (mLauncher)
+ {
+ return mLauncher->Cancel ();
+ }
+ else
+ {
+ return NS_ERROR_FAILURE;
+ }
+}
+
+NS_DEF_FACTORY (GProgressListener, GProgressListener);
+
+/**
+ * NS_NewProgressListenerFactory:
+ */
+nsresult NS_NewProgressListenerFactory(nsIFactory** aFactory)
+{
+ NS_ENSURE_ARG_POINTER(aFactory);
+ *aFactory = nsnull;
+
+ nsGProgressListenerFactory *result = new nsGProgressListenerFactory;
+ if (result == NULL)
+ {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+
+ NS_ADDREF(result);
+ *aFactory = result;
+
+ return NS_OK;
+}
+
+static void
+download_remove_cb (DownloaderView *dv, GProgressListener *Progress)
+{
+ Progress->Abort();
+}
+
+static void
+download_resume_cb (DownloaderView *dv, GProgressListener *Progress)
+{
+ Progress->Resume();
+}
+
+static void
+download_pause_cb (DownloaderView *dv, GProgressListener *Progress)
+{
+ Progress->Pause();
+}
diff --git a/embed/mozilla/ProgressListener.h b/embed/mozilla/ProgressListener.h
new file mode 100644
index 000000000..459643194
--- /dev/null
+++ b/embed/mozilla/ProgressListener.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2001 Philip Langdale, Matthew Aubury
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef PROGRESSLISTENER2_H__
+#define PROGRESSLISTENER2_H__
+
+#include "downloader-view.h"
+#include "ephy-embed-persist.h"
+#include "ephy-embed-shell.h"
+
+#include <gtk/gtkwidget.h>
+#include "nsIWebProgressListener.h"
+#include "nsIHelperAppLauncherDialog.h"
+#include "nsIExternalHelperAppService.h"
+#include "nsCExternalHandlerService.h"
+#include "nsIWebBrowserPersist.h"
+#include "nsCOMPtr.h"
+#include "nsWeakReference.h"
+#include "nsIURI.h"
+#include "nsILocalFile.h"
+#include "nsIDOMWindow.h"
+#include "nsIRequest.h"
+#include "nsIMIMEInfo.h"
+#include "nsIDownload.h"
+#include "nsIObserver.h"
+#include "nsIProgressDialog.h"
+
+#include "ContentHandler.h"
+
+#define G_PROGRESSDIALOG_CID \
+{ /* d2a2f743-f126-4f1f-1234-d4e50490f112 */ \
+ 0xd2a2f743, \
+ 0xf126, \
+ 0x4f1f, \
+ {0x12, 0x34, 0xd4, 0xe5, 0x04, 0x90, 0xf1, 0x12} \
+}
+
+#define G_PROGRESSDIALOG_CLASSNAME "Ephy's Download Progress Dialog"
+#define G_PROGRESSDIALOG_CONTRACTID "@mozilla.org/progressdialog;1"
+
+class GProgressListener : public nsIProgressDialog,
+ public nsIWebProgressListener,
+ public nsSupportsWeakReference
+{
+ public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIWEBPROGRESSLISTENER
+ NS_DECL_NSIPROGRESSDIALOG
+ NS_DECL_NSIDOWNLOAD
+
+ GProgressListener ();
+ virtual ~GProgressListener ();
+
+ NS_METHOD InitForPersist (nsIWebBrowserPersist *aPersist,
+ nsIDOMWindow *aParent, nsIURI *aURI,
+ nsIFile *aFile,
+ DownloadAction aAction,
+ EphyEmbedPersist *ephyPersist,
+ PRBool noDialog,
+ PRInt64 aTimeDownloadStarted = 0);
+ NS_METHOD InitForDownload (nsIHelperAppLauncher *aLauncher,
+ nsISupports *aContext,
+ GContentHandler *aHandler,
+ DownloadAction aDownload);
+
+ nsresult Pause (void);
+ nsresult Resume (void);
+ nsresult Abort (void);
+
+ GTimer *mTimer;
+
+ private:
+ NS_METHOD PrivateInit (void);
+ NS_METHOD LaunchHelperApp (void);
+
+ NS_METHOD LaunchHandler (PersistHandlerInfo *handler);
+
+ nsCOMPtr<nsIHelperAppLauncher> mLauncher;
+ nsCOMPtr<nsIWebBrowserPersist> mPersist;
+ nsCOMPtr<GContentHandler> mHandler;
+ nsCOMPtr<nsIDOMWindow> mParent;
+ nsCOMPtr<nsIRequest> mRequest;
+
+ EphyEmbedPersist *mEphyPersist;
+
+ nsCOMPtr<nsIURI> mUri;
+ PRInt64 mTimeDownloadStarted;
+ nsCOMPtr<nsIFile> mFile;
+
+ PRInt64 mStartTime;
+ PRInt64 mElapsed;
+
+ PRInt64 mLastUpdate;
+ PRInt32 mInterval;
+
+ PRFloat64 mPriorKRate;
+ PRInt32 mRateChanges;
+ PRInt32 mRateChangeLimit;
+
+ PRBool mCheckedCanPause;
+ PRBool mCanPause;
+ PRBool mIsPaused;
+ gboolean mNoDialog;
+ PRBool mAbort;
+
+ DownloadAction mAction;
+
+ DownloaderView *mDownloaderView;
+
+ EphyEmbedShell *ephy_shell;
+
+ guint mTimeoutFunc;
+
+ nsCOMPtr<nsIObserver> mObserver;
+
+ nsCOMPtr<nsIMIMEInfo> mMIMEInfo;
+
+ PRInt32 mPercentComplete;
+};
+
+extern nsresult NS_NewProgressListenerFactory(nsIFactory** aFactory);
+
+#endif // PROGRESSLISTENER2_H__
+
diff --git a/embed/mozilla/PromptService.cpp b/embed/mozilla/PromptService.cpp
new file mode 100644
index 000000000..c9244dd32
--- /dev/null
+++ b/embed/mozilla/PromptService.cpp
@@ -0,0 +1,769 @@
+/*
+ * Copyright (C) 2000 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "ephy-glade.h"
+#include "PromptService.h"
+
+#include "nsCOMPtr.h"
+#include "nsIFactory.h"
+#include "nsString.h"
+#include "nsReadableUtils.h"
+#include "nsIServiceManager.h"
+#include "nsXPComFactory.h"
+#include "MozillaPrivate.h"
+
+#include "nsIPromptService.h"
+#include "nsIUnicodeEncoder.h"
+
+#include <gtk/gtkentry.h>
+#include <gtk/gtktogglebutton.h>
+#include <gtk/gtklist.h>
+#include <libgnomeui/gnome-dialog.h>
+#include <libgnome/gnome-i18n.h>
+#include <libgnome/gnome-triggers.h>
+
+/* local function prototypes */
+static void set_title (GtkWidget *dialog, const PRUnichar *title);
+static void set_label_text (GtkWidget *label, const PRUnichar *text);
+static void set_check_button_text (GtkWidget *check_button,
+ const PRUnichar *text);
+static void set_check_button (GtkWidget *button, PRBool *value);
+static void set_check_button_size_to_label (GtkWidget *check_button,
+ GtkWidget *label);
+static void set_editable (GtkWidget *entry, PRUnichar **text);
+static void get_check_button (GtkWidget *button, PRBool *value);
+static void get_editable (GtkWidget *editable, PRUnichar **text);
+
+/**
+ * class CPromptService: an GNOME implementation of prompt dialogs for
+ * Mozilla
+ */
+class CPromptService: public nsIPromptService
+{
+ public:
+ CPromptService();
+ virtual ~CPromptService();
+
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIPROMPTSERVICE
+ private:
+ nsresult AddButton (GtkWidget *dialog,
+ char type,
+ const PRUnichar *title,
+ int id);
+};
+
+NS_IMPL_ISUPPORTS1 (CPromptService, nsIPromptService)
+
+/**
+ * CPromptService::CPromptService: constructor
+ */
+CPromptService::CPromptService ()
+{
+ NS_INIT_ISUPPORTS();
+}
+
+/**
+ * CPromptService::~CPromptService: destructor
+ */
+CPromptService::~CPromptService ()
+{
+}
+
+/**
+ * CPromptService::Alert: show an alert box
+ */
+NS_IMETHODIMP CPromptService::Alert (nsIDOMWindow *parent,
+ const PRUnichar *dialogTitle,
+ const PRUnichar *text)
+{
+ GtkWidget *dialog;
+ GtkWidget *gparent;
+
+ gparent = MozillaFindGtkParent (parent);
+ const nsACString &msg = NS_ConvertUCS2toUTF8 (text);
+ dialog = gtk_message_dialog_new (GTK_WINDOW(gparent),
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_WARNING,
+ GTK_BUTTONS_OK,
+ "%s",
+ PromiseFlatCString(msg).get ());
+ set_title (dialog, dialogTitle);
+
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+
+ return NS_OK;
+}
+
+/**
+ * CPromptService::AlertCheck: show an alert box with a checkbutton,
+ * (typically for things like "dont show this warning again")
+ */
+NS_IMETHODIMP CPromptService::AlertCheck (nsIDOMWindow *parent,
+ const PRUnichar *dialogTitle,
+ const PRUnichar *text,
+ const PRUnichar *checkMsg,
+ PRBool *checkValue)
+{
+ GtkWidget *dialog;
+ GtkWidget *gparent;
+ GtkWidget *check_button;
+
+ gparent = MozillaFindGtkParent (parent);
+ const nsACString &msg = NS_ConvertUCS2toUTF8 (text);
+ dialog = gtk_message_dialog_new (GTK_WINDOW(gparent),
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_WARNING,
+ GTK_BUTTONS_OK,
+ "%s",
+ PromiseFlatCString(msg).get ());
+
+ check_button = gtk_check_button_new_with_label ("");
+ gtk_widget_show (check_button);
+ gtk_box_pack_start (GTK_BOX (GTK_DIALOG(dialog)->vbox),
+ check_button, FALSE, FALSE, 5);
+ set_check_button_text (check_button, checkMsg);
+ set_check_button (check_button, checkValue);
+
+ set_title (dialog, dialogTitle);
+
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ get_check_button (check_button, checkValue);
+ gtk_widget_destroy (dialog);
+
+ return NS_OK;
+}
+
+/**
+ * CPromptService::Confirm: for simple yes/no dialogs
+ */
+NS_IMETHODIMP CPromptService::Confirm (nsIDOMWindow *parent,
+ const PRUnichar *dialogTitle,
+ const PRUnichar *text,
+ PRBool *_retval)
+{
+ GtkWidget *dialog;
+ GtkWidget *gparent;
+ int res;
+
+ gparent = MozillaFindGtkParent (parent);
+ const nsACString &msg = NS_ConvertUCS2toUTF8 (text);
+ dialog = gtk_message_dialog_new (GTK_WINDOW(gparent),
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_QUESTION,
+ GTK_BUTTONS_YES_NO,
+ "%s", PromiseFlatCString(msg).get ());
+ set_title (dialog, dialogTitle);
+
+ res = gtk_dialog_run (GTK_DIALOG (dialog));
+ *_retval = (res == GTK_RESPONSE_YES);
+ gtk_widget_destroy (dialog);
+
+ return NS_OK;
+}
+
+/**
+ * CPromptService::Confirm: for simple yes/no dialogs, with an additional
+ * check button
+ */
+NS_IMETHODIMP CPromptService::ConfirmCheck (nsIDOMWindow *parent,
+ const PRUnichar *dialogTitle,
+ const PRUnichar *text,
+ const PRUnichar *checkMsg,
+ PRBool *checkValue,
+ PRBool *_retval)
+{
+ GtkWidget *dialog;
+ GtkWidget *gparent;
+ GtkWidget *check_button;
+ int res;
+
+ gparent = MozillaFindGtkParent (parent);
+ const nsACString &msg = NS_ConvertUCS2toUTF8 (text);
+ dialog = gtk_message_dialog_new (GTK_WINDOW(gparent),
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_QUESTION,
+ GTK_BUTTONS_YES_NO,
+ "%s", PromiseFlatCString(msg).get ());
+
+ check_button = gtk_check_button_new_with_label ("");
+ gtk_widget_show (check_button);
+ gtk_box_pack_start (GTK_BOX (GTK_DIALOG(dialog)->vbox),
+ check_button, FALSE, FALSE, 5);
+ set_check_button_text (check_button, checkMsg);
+ set_check_button (check_button, checkValue);
+
+ set_title (dialog, dialogTitle);
+
+ res = gtk_dialog_run (GTK_DIALOG (dialog));
+ *_retval = (res == GTK_RESPONSE_YES);
+ get_check_button (check_button, checkValue);
+ gtk_widget_destroy (dialog);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP CPromptService::AddButton (GtkWidget *dialog,
+ char type,
+ const PRUnichar *title,
+ int id)
+{
+ const char *btitle;
+ const nsACString &utf8string = NS_ConvertUCS2toUTF8 (title);
+
+ g_print ("%d", type);
+
+ switch (type)
+ {
+ case BUTTON_TITLE_OK:
+ btitle = GTK_STOCK_OK;
+ break;
+ case BUTTON_TITLE_CANCEL:
+ btitle = GTK_STOCK_CANCEL;
+ break;
+ case BUTTON_TITLE_YES:
+ btitle = GTK_STOCK_YES;
+ break;
+ case BUTTON_TITLE_NO:
+ btitle = GTK_STOCK_NO;
+ break;
+ case BUTTON_TITLE_SAVE:
+ btitle = _("Save");
+ break;
+ case BUTTON_TITLE_REVERT:
+ btitle = _("Revert");
+ break;
+ case BUTTON_TITLE_DONT_SAVE:
+ btitle = _("Don't save");
+ break;
+ case BUTTON_TITLE_IS_STRING:
+ btitle = NULL;
+ break;
+
+ default:
+ return NS_ERROR_FAILURE;
+ }
+
+ gtk_dialog_add_button (GTK_DIALOG(dialog),
+ btitle ? btitle :
+ PromiseFlatCString(utf8string).get(),
+ id);
+
+ return NS_OK;
+}
+
+/**
+ * CPromptService::ConfirmEx: For fancy confirmation dialogs
+ */
+NS_IMETHODIMP CPromptService::ConfirmEx (nsIDOMWindow *parent,
+ const PRUnichar *dialogTitle,
+ const PRUnichar *text,
+ PRUint32 buttonFlags,
+ const PRUnichar *button0Title,
+ const PRUnichar *button1Title,
+ const PRUnichar *button2Title,
+ const PRUnichar *checkMsg,
+ PRBool *checkValue,
+ PRInt32 *buttonPressed)
+{
+ GtkWidget *dialog;
+ GtkWidget *gparent;
+ GtkWidget *check_button = NULL;
+ int ret;
+
+ gparent = MozillaFindGtkParent (parent);
+ const nsACString &msg = NS_ConvertUCS2toUTF8 (text);
+ dialog = gtk_message_dialog_new (GTK_WINDOW(gparent),
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_QUESTION,
+ GTK_BUTTONS_NONE,
+ "%s", PromiseFlatCString(msg).get ());
+
+ set_title (dialog, dialogTitle);
+
+ if (checkMsg)
+ {
+ check_button = gtk_check_button_new_with_label ("");
+ gtk_widget_show (check_button);
+ gtk_box_pack_start (GTK_BOX (GTK_DIALOG(dialog)->vbox),
+ check_button, FALSE, FALSE, 5);
+
+ set_check_button_text (check_button, checkMsg);
+ set_check_button (check_button, checkValue);
+ }
+
+ AddButton (dialog, (buttonFlags >> 16) & 0xFF,
+ button2Title, 2);
+ AddButton (dialog, (buttonFlags >> 8) & 0xFF,
+ button1Title, 1);
+ AddButton (dialog, buttonFlags & 0xFF,
+ button0Title, 0);
+
+ gtk_dialog_set_default_response (GTK_DIALOG(dialog), 0);
+
+ /* make a suitable sound */
+ gnome_triggers_vdo ("", "generic", NULL);
+
+ /* run dialog and capture return values */
+ ret = gtk_dialog_run (GTK_DIALOG (dialog));
+
+ /* handle return values */
+ if (checkMsg)
+ {
+ get_check_button (check_button, checkValue);
+ }
+
+ *buttonPressed = ret;
+
+ /* done */
+ gtk_widget_destroy (dialog);
+ return NS_OK;
+}
+
+/**
+ * CPromptService::Prompt: show a prompt for text, with a checkbutton
+ */
+NS_IMETHODIMP CPromptService::Prompt (nsIDOMWindow *parent,
+ const PRUnichar *dialogTitle,
+ const PRUnichar *text,
+ PRUnichar **value,
+ const PRUnichar *checkMsg,
+ PRBool *checkValue,
+ PRBool *_retval)
+{
+ GtkWidget *dialog;
+ GtkWidget *entry;
+ GtkWidget *label;
+ GtkWidget *check_button;
+ GtkWidget *gparent;
+ GladeXML *gxml;
+ gint ret;
+
+ /* build and show the dialog */
+ gxml = ephy_glade_widget_new ("prompts.glade", "prompt_dialog",
+ &dialog, NULL);
+ entry = glade_xml_get_widget (gxml, "entry");
+ label = glade_xml_get_widget (gxml, "label");
+ check_button = glade_xml_get_widget (gxml, "check_button");
+ g_object_unref (G_OBJECT (gxml));
+
+ /* parent the dialog */
+ gparent = MozillaFindGtkParent (parent);
+ gtk_window_set_transient_for (GTK_WINDOW (dialog),
+ GTK_WINDOW (gparent));
+
+ /* set dynamic attributes */
+ set_title (dialog, dialogTitle);
+ set_label_text (label, text);
+ set_check_button_text (check_button, checkMsg);
+ set_editable (entry, value);
+ set_check_button (check_button, checkValue);
+ set_check_button_size_to_label (check_button, label);
+
+ /* make a suitable sound */
+ /* NB: should be question, but this is missing in many
+ * of the current gnome sound packages that I've tried... */
+ gnome_triggers_vdo ("", "generic", NULL);
+
+ /* run dialog and capture return values */
+ ret = gtk_dialog_run (GTK_DIALOG (dialog));
+
+ /* handle return values */
+ get_check_button (check_button, checkValue);
+ get_editable (entry, value);
+ *_retval = (ret == GTK_RESPONSE_OK);
+
+ /* done */
+ gtk_widget_destroy (dialog);
+ return NS_OK;
+}
+
+/**
+ * CPromptService::PromptUsernameAndPassword: show a prompt for username
+ * and password with an additional check button.
+ */
+NS_IMETHODIMP CPromptService::PromptUsernameAndPassword
+ (nsIDOMWindow *parent,
+ const PRUnichar *dialogTitle,
+ const PRUnichar *text,
+ PRUnichar **username,
+ PRUnichar **password,
+ const PRUnichar *checkMsg,
+ PRBool *checkValue,
+ PRBool *_retval)
+{
+ GtkWidget *dialog;
+ GtkWidget *check_button;
+ GtkWidget *label;
+ GtkWidget *username_entry;
+ GtkWidget *password_entry;
+ GtkWidget *gparent;
+ GladeXML *gxml;
+ gint ret;
+
+ /* build and show the dialog */
+ gxml = ephy_glade_widget_new ("prompts.glade", "prompt_user_pass_dialog",
+ &dialog, NULL);
+ check_button = glade_xml_get_widget (gxml, "check_button");
+ label = glade_xml_get_widget (gxml, "label");
+ username_entry = glade_xml_get_widget (gxml, "username_entry");
+ password_entry = glade_xml_get_widget (gxml, "password_entry");
+ g_object_unref (G_OBJECT (gxml));
+
+ /* parent the dialog */
+ gparent = MozillaFindGtkParent (parent);
+ gtk_window_set_transient_for (GTK_WINDOW (dialog),
+ GTK_WINDOW (gparent));
+
+ /* set dynamic attributes */
+ set_title (dialog, dialogTitle);
+ set_check_button_text (check_button, checkMsg);
+ set_editable (username_entry, username);
+ set_editable (password_entry, password);
+ set_check_button (check_button, checkValue);
+ set_label_text (label, text);
+ set_check_button_size_to_label (check_button, label);
+
+ /* make a suitable sound */
+ gnome_triggers_vdo ("", "question", NULL);
+
+ /* run dialog and capture return values */
+ ret = gtk_dialog_run (GTK_DIALOG (dialog));
+
+ /* handle return values */
+ get_check_button (check_button, checkValue);
+ get_editable (username_entry, username);
+ get_editable (password_entry, password);
+ *_retval = (ret == GTK_RESPONSE_OK);
+
+ /* done */
+ gtk_widget_destroy (dialog);
+ return NS_OK;
+}
+
+/**
+ * CPromptService::PromptPassword: show a prompt for just
+ * a password with an additional check button.
+ */
+NS_IMETHODIMP CPromptService::PromptPassword (nsIDOMWindow *parent,
+ const PRUnichar *dialogTitle,
+ const PRUnichar *text,
+ PRUnichar **password,
+ const PRUnichar *checkMsg,
+ PRBool *checkValue,
+ PRBool *_retval)
+{
+ GtkWidget *dialog;
+ GtkWidget *label;
+ GtkWidget *check_button;
+ GtkWidget *password_entry;
+ GtkWidget *gparent;
+ GladeXML *gxml;
+ gint ret;
+
+ /* build and show the dialog */
+ gxml = ephy_glade_widget_new ("prompts.glade", "prompt_pass_dialog",
+ &dialog, NULL);
+ check_button = glade_xml_get_widget (gxml, "check_button");
+ label = glade_xml_get_widget (gxml, "label");
+ password_entry = glade_xml_get_widget (gxml, "password_entry");
+ g_object_unref (G_OBJECT (gxml));
+
+ /* parent the dialog */
+ gparent = MozillaFindGtkParent (parent);
+ gtk_window_set_transient_for (GTK_WINDOW (dialog),
+ GTK_WINDOW (gparent));
+
+ /* set dynamic attributes */
+ set_title (dialog, dialogTitle);
+ set_check_button_text (check_button, checkMsg);
+ set_editable (password_entry, password);
+ set_check_button (check_button, checkValue);
+ set_label_text (label, text);
+ set_check_button_size_to_label (check_button, label);
+
+ /* make a suitable sound */
+ gnome_triggers_vdo ("", "question", NULL);
+
+ /* run dialog and capture return values */
+ ret = gtk_dialog_run (GTK_DIALOG (dialog));
+
+ /* handle return values */
+ get_check_button (check_button, checkValue);
+ get_editable (password_entry, password);
+ *_retval = (ret == GTK_RESPONSE_OK);
+
+ /* done */
+ gtk_widget_destroy (dialog);
+ return NS_OK;
+}
+
+
+/**
+ * CPromptService::Select:
+ */
+NS_IMETHODIMP CPromptService::Select (nsIDOMWindow *parent,
+ const PRUnichar *dialogTitle,
+ const PRUnichar *text, PRUint32 count,
+ const PRUnichar **selectList,
+ PRInt32 *outSelection,
+ PRBool *_retval)
+{
+ GtkWidget *dialog;
+ GtkWidget *gparent;
+ GtkWidget *label;
+ GladeXML *gxml;
+ GtkWidget *treeview;
+ gint ret;
+
+ /* build and show the dialog */
+ gxml = ephy_glade_widget_new ("prompts.glade", "select_dialog",
+ &dialog, NULL);
+ treeview = glade_xml_get_widget (gxml, "treeview");
+ label = glade_xml_get_widget (gxml, "label");
+ g_object_unref (G_OBJECT (gxml));
+
+ /* parent the dialog */
+ gparent = MozillaFindGtkParent (parent);
+ gtk_window_set_transient_for (GTK_WINDOW (dialog),
+ GTK_WINDOW (gparent));
+
+ /* set dynamic attributes */
+ set_title (dialog, dialogTitle);
+ set_label_text (label, text);
+
+ /* setup treeview */
+ GtkCellRenderer *renderer;
+ GtkListStore *liststore;
+ GtkTreeSelection *selection;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+
+ gtk_tree_view_set_reorderable (GTK_TREE_VIEW(treeview), TRUE);
+
+ liststore = gtk_list_store_new (2,
+ G_TYPE_STRING,
+ G_TYPE_INT);
+
+ model = GTK_TREE_MODEL (liststore);
+
+ gtk_tree_view_set_model (GTK_TREE_VIEW(treeview),
+ model);
+ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(treeview),
+ FALSE);
+
+ renderer = gtk_cell_renderer_text_new ();
+
+ gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
+ 0, "Items",
+ renderer,
+ "text", 0,
+ NULL);
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(treeview));
+
+ for (PRUint32 i = 0 ; i < count ; i++)
+ {
+ char *itemText =
+ ToNewCString(NS_ConvertUCS2toUTF8 (selectList[i]));
+ gtk_list_store_append (GTK_LIST_STORE (model),
+ &iter);
+ gtk_list_store_set (GTK_LIST_STORE (model),
+ &iter,
+ 0, itemText,
+ 1, i,
+ -1);
+ nsMemory::Free(itemText);
+ }
+
+ gtk_tree_model_get_iter_first (model, &iter);
+ gtk_tree_selection_select_iter (selection, &iter);
+
+ /* make a suitable sound */
+ gnome_triggers_vdo ("", "question", NULL);
+
+ /* run dialog and capture return values */
+ ret = gtk_dialog_run (GTK_DIALOG (dialog));
+
+ /* handle return values */
+ if (gtk_tree_selection_get_selected (selection,
+ &model,
+ &iter))
+ {
+ GValue val = {0, };
+ gtk_tree_model_get_value (model, &iter, 1, &val);
+ *outSelection = g_value_get_int (&val);
+
+ *_retval = (ret == GTK_RESPONSE_OK) ? PR_TRUE : PR_FALSE;
+ }
+ else
+ {
+ *_retval = PR_FALSE;
+ }
+
+ gtk_widget_destroy (dialog);
+
+ return NS_OK;
+}
+
+NS_DEF_FACTORY (CPromptService, CPromptService);
+
+/**
+ * NS_NewPromptServiceFactory:
+ */
+nsresult NS_NewPromptServiceFactory(nsIFactory** aFactory)
+{
+ NS_ENSURE_ARG_POINTER(aFactory);
+ *aFactory = nsnull;
+
+ nsCPromptServiceFactory *result = new nsCPromptServiceFactory;
+ if (result == NULL)
+ {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+
+ NS_ADDREF(result);
+ *aFactory = result;
+
+ return NS_OK;
+}
+
+/**
+ * set_title: set a dialog title to a unicode string
+ */
+static void
+set_title (GtkWidget *dialog, const PRUnichar *title)
+{
+ const nsACString &utf8string = NS_ConvertUCS2toUTF8 (title);
+
+ /* set it */
+ gtk_window_set_title (GTK_WINDOW (dialog),
+ (title == NULL ? N_("Galeon") :
+ PromiseFlatCString(utf8string).get()));
+}
+
+/**
+ * set_label_text: set a labels text to a unicode string
+ */
+static void
+set_label_text (GtkWidget *label, const PRUnichar *text)
+{
+ const nsACString &utf8string = NS_ConvertUCS2toUTF8 (text);
+
+ /* set it */
+ gtk_label_set_text (GTK_LABEL (label),
+ PromiseFlatCString(utf8string).get());
+}
+
+/**
+ * set_check_button_text: set a check buttons text to a unicode string
+ */
+static void
+set_check_button_text (GtkWidget *check_button, const PRUnichar *text)
+{
+ const nsACString &utf8string = NS_ConvertUCS2toUTF8 (text);
+
+ /* set it */
+ gtk_label_set_text (GTK_LABEL (GTK_BIN (check_button)->child),
+ PromiseFlatCString(utf8string).get());
+}
+
+/**
+ * set_check_button: set a togglebutton to an initial state
+ */
+static void
+set_check_button (GtkWidget *button, PRBool *value)
+{
+ /* check pointer is valid */
+ if (value == NULL)
+ {
+ gtk_widget_hide (GTK_WIDGET (button));
+ return;
+ }
+
+ /* set the value of the check button */
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), *value);
+}
+
+/**
+ * se_check_button_size_to_label: sync text widgets sizes
+ */
+static void
+set_check_button_size_to_label (GtkWidget *check_button,
+ GtkWidget *label)
+{
+ GtkRequisition r, label_r;
+
+ gtk_widget_size_request (check_button, &r);
+ gtk_widget_size_request (label, &label_r);
+
+ if (r.width <= label_r.width) return;
+
+ gtk_widget_set_size_request (label, r.width, 0);
+}
+
+/**
+ * set_editable: set an editable to a unicode string
+ */
+static void
+set_editable (GtkWidget *entry, PRUnichar **text)
+{
+ const nsACString &utf8string = NS_ConvertUCS2toUTF8 (*text);
+
+ /* set this string value in the widget */
+ gtk_entry_set_text (GTK_ENTRY (entry),
+ PromiseFlatCString(utf8string).get());
+}
+
+/**
+ * get_check_button: get value of a toggle button and store it in a PRBool
+ */
+static void
+get_check_button (GtkWidget *button, PRBool *value)
+{
+ /* check we can write */
+ if (value == NULL)
+ {
+ return;
+ }
+
+ /* set the value from the check button */
+ *value = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
+}
+
+/**
+ * get_editable: get a string from an editable and store it as unicode
+ */
+static void
+get_editable (GtkWidget *editable, PRUnichar **text)
+{
+ char *edited;
+
+ /* check we can write */
+ if (text == NULL)
+ {
+ return;
+ }
+
+ /* get the text */
+ edited = gtk_editable_get_chars (GTK_EDITABLE (editable), 0, -1);
+
+ /* decode and set it as the return value */
+ *text = ToNewUnicode(NS_ConvertUTF8toUCS2(edited));
+}
diff --git a/embed/mozilla/PromptService.h b/embed/mozilla/PromptService.h
new file mode 100644
index 000000000..98d8d0c46
--- /dev/null
+++ b/embed/mozilla/PromptService.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2000 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __PromptService_h
+#define __PromptService_h
+
+#include "nsError.h"
+
+#define G_PROMPTSERVICE_CID \
+{ /* c5a77759-a07a-4025-8f74-ae89153ee6c2 */ \
+ 0xc5a77759, \
+ 0xa07a, \
+ 0x4025, \
+ {0x8f, 0x74, 0xae, 0x89, 0x15, 0x3e, 0xe6, 0xc2} \
+}
+
+#define G_PROMPTSERVICE_CLASSNAME "Galeon's Prompt Service"
+#define G_PROMPTSERVICE_CONTRACTID "@mozilla.org/embedcomp/prompt-service;1"
+
+class nsIFactory;
+
+extern nsresult NS_NewPromptServiceFactory(nsIFactory** aFactory);
+
+#endif
diff --git a/embed/mozilla/StartHereProtocolHandler.cpp b/embed/mozilla/StartHereProtocolHandler.cpp
new file mode 100644
index 000000000..47a1af310
--- /dev/null
+++ b/embed/mozilla/StartHereProtocolHandler.cpp
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2001 Matt Aubury, Philip Langdale
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "ephy-file-helpers.h"
+
+#include "nsCOMPtr.h"
+#include "nsIFactory.h"
+#include "nsIIOService.h"
+#include "nsIServiceManager.h"
+#include "nsIURI.h"
+#include "nsNetCID.h"
+#include "nsNetUtil.h"
+#include "nsXPComFactory.h"
+
+static NS_DEFINE_CID(kSimpleURICID, NS_SIMPLEURI_CID);
+
+class GStartHereProtocolHandler : public nsIProtocolHandler
+{
+ public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIPROTOCOLHANDLER
+
+ GStartHereProtocolHandler (void);
+ virtual ~GStartHereProtocolHandler();
+
+ nsCOMPtr<nsIChannel> mChannel;
+ nsCOMPtr<nsIURI> mURI;
+};
+
+/* Implementation file */
+NS_IMPL_ISUPPORTS1 (GStartHereProtocolHandler, nsIProtocolHandler)
+
+GStartHereProtocolHandler::GStartHereProtocolHandler (void)
+{
+ NS_INIT_ISUPPORTS();
+
+}
+
+GStartHereProtocolHandler::~GStartHereProtocolHandler()
+{
+ /* destructor code */
+}
+
+/* readonly attribute string scheme; */
+NS_IMETHODIMP GStartHereProtocolHandler::GetScheme(nsACString &aScheme)
+{
+ aScheme = NS_LITERAL_CSTRING("start-here");
+ return NS_OK;
+}
+
+/* readonly attribute long defaultPort; */
+NS_IMETHODIMP GStartHereProtocolHandler::GetDefaultPort(PRInt32 *aDefaultPort)
+{
+ nsresult rv = NS_OK;
+ if (aDefaultPort)
+ *aDefaultPort = -1;
+ else
+ rv = NS_ERROR_NULL_POINTER;
+ return rv;
+}
+
+/* readonly attribute short protocolFlags; */
+NS_IMETHODIMP GStartHereProtocolHandler::GetProtocolFlags(PRUint32 *aProtocolFlags)
+{
+ if (aProtocolFlags)
+ *aProtocolFlags = nsIProtocolHandler::URI_STD;
+ else
+ return NS_ERROR_NULL_POINTER;
+ return NS_OK;
+}
+
+/* nsIURI newURI (in string aSpec, in nsIURI aBaseURI); */
+NS_IMETHODIMP GStartHereProtocolHandler::NewURI(const nsACString &aSpec,
+ const char *aOriginCharset,
+ nsIURI *aBaseURI,
+ nsIURI **_retval)
+{
+ nsresult rv = NS_OK;
+ nsCOMPtr <nsIURI> newUri;
+
+ rv = nsComponentManager::CreateInstance(kSimpleURICID, NULL,
+ NS_GET_IID(nsIURI),
+ getter_AddRefs(newUri));
+
+ if (NS_SUCCEEDED(rv))
+ {
+ newUri->SetSpec(aSpec);
+ rv = newUri->QueryInterface(NS_GET_IID(nsIURI),
+ (void **) _retval);
+ }
+ return rv;
+}
+
+/* nsIChannel newChannel (in nsIURI aURI); */
+NS_IMETHODIMP GStartHereProtocolHandler::NewChannel(nsIURI *aURI,
+ nsIChannel **_retval)
+{
+ nsresult rv;
+
+ nsCAutoString path;
+ rv = aURI->GetPath(path);
+ if (NS_FAILED(rv)) return rv;
+
+ char *httpSpec = g_strconcat ("file:///",
+ ephy_file ("start_here.html"),
+ NULL);
+
+ if (!httpSpec) return NS_ERROR_OUT_OF_MEMORY;
+
+ nsCOMPtr<nsIIOService> serv(do_GetIOService(&rv));
+ if (NS_FAILED(rv)) return rv;
+
+ // now we have an HTTP url, give the user an HTTP channel
+ rv = serv->NewChannel(nsDependentCString(httpSpec), nsnull, nsnull, _retval);
+
+ return rv;
+}
+
+/* boolean allowPort (in long port, in string scheme); */
+NS_IMETHODIMP GStartHereProtocolHandler::AllowPort(PRInt32 port, const char *scheme,
+ PRBool *_retval)
+{
+ *_retval = PR_FALSE;
+ return NS_OK;
+}
+
+NS_DEF_FACTORY (GStartHereProtocolHandler, GStartHereProtocolHandler);
+
+/**
+ * NS_NewStartHereProtocolHandlerFactory:
+ */
+nsresult NS_NewStartHereHandlerFactory(nsIFactory** aFactory)
+{
+ NS_ENSURE_ARG_POINTER(aFactory);
+ *aFactory = nsnull;
+
+ nsGStartHereProtocolHandlerFactory *result = new nsGStartHereProtocolHandlerFactory;
+ if (result == NULL)
+ {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+
+ NS_ADDREF(result);
+ *aFactory = result;
+
+ return NS_OK;
+}
diff --git a/embed/mozilla/StartHereProtocolHandler.h b/embed/mozilla/StartHereProtocolHandler.h
new file mode 100644
index 000000000..82c74774b
--- /dev/null
+++ b/embed/mozilla/StartHereProtocolHandler.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2001 Philip Langdale
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef StartHereProtocolHandler_h__
+#define StartHereProtocolHandler_h__
+
+#include "nsError.h"
+
+#define G_START_HERE_PROTOCOLHANDLER_CID \
+{ /* a3a7b6e5-7a92-431d-87e6-3bef8e7ada51*/ \
+ 0xa3a7b6e5, \
+ 0x7a92, \
+ 0x431d, \
+ {0x87, 0xe6, 0x3b, 0xef, 0x8e, 0x7a, 0xda, 0x51} \
+}
+#define G_START_HERE_PROTOCOLHANDLER_CONTRACTID NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "start-here"
+#define G_START_HERE_PROTOCOLHANDLER_CLASSNAME "Galeon's start here protocol handler"
+
+class nsIFactory;
+
+extern nsresult NS_NewStartHereHandlerFactory(nsIFactory** aFactory);
+
+#endif // MyportalProtocolHandler_h__
diff --git a/embed/mozilla/mozilla-embed-persist.cpp b/embed/mozilla/mozilla-embed-persist.cpp
new file mode 100644
index 000000000..abfcacd57
--- /dev/null
+++ b/embed/mozilla/mozilla-embed-persist.cpp
@@ -0,0 +1,244 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "ProgressListener.h"
+#include "EphyWrapper.h"
+#include "mozilla-embed.h"
+#include "mozilla-embed-persist.h"
+
+#include <stddef.h>
+#include <nsIWebBrowserPersist.h>
+#include <nsString.h>
+#include <nsCWebBrowserPersist.h>
+#include <nsNetUtil.h>
+
+static void
+mozilla_embed_persist_class_init (MozillaEmbedPersistClass *klass);
+static void
+mozilla_embed_persist_init (MozillaEmbedPersist *ges);
+static void
+mozilla_embed_persist_finalize (GObject *object);
+
+static gresult
+impl_save (EphyEmbedPersist *persist);
+
+struct MozillaEmbedPersistPrivate
+{
+ gpointer dummy;
+};
+
+static GObjectClass *parent_class = NULL;
+
+GType
+mozilla_embed_persist_get_type (void)
+{
+ static GType mozilla_embed_persist_type = 0;
+
+ if (mozilla_embed_persist_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (MozillaEmbedPersistClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) mozilla_embed_persist_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (MozillaEmbedPersist),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) mozilla_embed_persist_init
+ };
+
+ mozilla_embed_persist_type =
+ g_type_register_static (EPHY_EMBED_PERSIST_TYPE,
+ "MozillaEmbedPersist",
+ &our_info, (GTypeFlags)0);
+ }
+
+ return mozilla_embed_persist_type;
+}
+
+static void
+mozilla_embed_persist_class_init (MozillaEmbedPersistClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ EphyEmbedPersistClass *persist_class;
+
+ parent_class = (GObjectClass *) g_type_class_peek_parent (klass);
+ persist_class = EPHY_EMBED_PERSIST_CLASS (klass);
+
+ object_class->finalize = mozilla_embed_persist_finalize;
+
+ persist_class->save = impl_save;
+}
+
+static void
+mozilla_embed_persist_init (MozillaEmbedPersist *persist)
+{
+ persist->priv = g_new0 (MozillaEmbedPersistPrivate, 1);
+}
+
+static void
+mozilla_embed_persist_finalize (GObject *object)
+{
+ MozillaEmbedPersist *persist;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (IS_MOZILLA_EMBED_PERSIST (object));
+
+ persist = MOZILLA_EMBED_PERSIST (object);
+
+ g_return_if_fail (persist->priv != NULL);
+
+ g_free (persist->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gresult
+impl_save (EphyEmbedPersist *persist)
+{
+ nsresult rv;
+ nsAutoString s;
+ char *filename;
+ char *uri;
+ int max_size;
+ EphyEmbed *embed;
+ EmbedPersistFlags flags;
+ EphyWrapper *wrapper = NULL;
+
+ g_object_get (persist,
+ "source", &uri,
+ "dest", &filename,
+ "flags", &flags,
+ "embed", &embed,
+ "max_size", &max_size,
+ NULL);
+
+ g_return_val_if_fail (filename != NULL, G_FAILED);
+
+ nsCOMPtr<nsIURI> linkURI;
+ linkURI = nsnull;
+ if (uri)
+ {
+ s.AssignWithConversion(uri);
+ rv = NS_NewURI(getter_AddRefs(linkURI), s);
+ if (NS_FAILED(rv) || !linkURI) return G_FAILED;
+ }
+
+ nsCOMPtr<nsIWebBrowserPersist> bpersist =
+ do_CreateInstance(NS_WEBBROWSERPERSIST_CONTRACTID, &rv);
+ if (NS_FAILED(rv) || !persist) return G_FAILED;
+
+ nsCOMPtr<nsILocalFile> file;
+ NS_NewLocalFile(NS_ConvertUTF8toUCS2(filename), PR_TRUE, getter_AddRefs(file));
+ if (NS_FAILED(rv) || !file) return G_FAILED;
+
+ nsCOMPtr<nsILocalFile> path;
+ if (flags & EMBED_PERSIST_SAVE_CONTENT)
+ {
+ char *datapath;
+ datapath = g_strconcat (filename, "content", NULL);
+ NS_NewLocalFile(NS_ConvertUTF8toUCS2(datapath), PR_TRUE, getter_AddRefs(path));
+ g_free (datapath);
+ }
+ else
+ {
+ path = nsnull;
+ }
+
+ nsCOMPtr<nsIDOMWindow> parent;
+ parent = nsnull;
+
+ if (embed)
+ {
+ wrapper = (EphyWrapper *) mozilla_embed_get_galeon_wrapper (MOZILLA_EMBED(embed));
+ wrapper->GetDOMWindow (getter_AddRefs (parent));
+ }
+
+ size_t len = strlen(filename);
+ if((filename[len-1] == 'z' && filename[len-2] == 'g') ||
+ (filename[len-1] == 'Z' && filename[len-2] == 'G'))
+ {
+ bpersist->SetPersistFlags (nsIWebBrowserPersist::PERSIST_FLAGS_NO_CONVERSION);
+ }
+ else
+ {
+ bpersist->SetPersistFlags (nsIWebBrowserPersist::PERSIST_FLAGS_NONE);
+ }
+
+ if (flags & EMBED_PERSIST_BYPASSCACHE)
+ {
+ bpersist->SetPersistFlags (nsIWebBrowserPersist::PERSIST_FLAGS_BYPASS_CACHE);
+ }
+
+ if (flags & EMBED_PERSIST_FROMCACHE)
+ {
+ bpersist->SetPersistFlags (nsIWebBrowserPersist::PERSIST_FLAGS_FROM_CACHE);
+ }
+
+ GProgressListener *aProgress = new GProgressListener ();
+
+ if (uri == NULL)
+ {
+ g_return_val_if_fail (wrapper != NULL, G_FAILED);
+
+ nsCOMPtr<nsIDOMDocument> DOMDocument;
+
+ if (flags & EMBED_PERSIST_MAINDOC)
+ {
+ rv = wrapper->GetMainDOMDocument (getter_AddRefs(DOMDocument));
+ }
+ else
+ {
+ rv = wrapper->GetDOMDocument (getter_AddRefs(DOMDocument));
+ }
+ if (NS_FAILED(rv) || !DOMDocument) return G_FAILED;
+
+ nsCOMPtr<nsIDocument> document =
+ do_QueryInterface (DOMDocument, &rv);
+ if (NS_FAILED(rv) || !document) return G_FAILED;
+
+ nsCOMPtr<nsIURI> uri;
+ rv = document->GetDocumentURL (getter_AddRefs(uri));
+ if (NS_FAILED(rv) || !uri) return G_FAILED;
+
+ aProgress->InitForPersist (bpersist, parent,
+ uri, file,
+ ACTION_OBJECT_NOTIFY,
+ persist,
+ !(flags & EMBED_PERSIST_SHOW_PROGRESS));
+
+ rv = bpersist->SaveDocument (DOMDocument, file, path, nsnull, 0, 0);
+ if (NS_FAILED(rv)) return G_FAILED;
+ }
+ else
+ {
+ aProgress->InitForPersist (bpersist, parent,
+ linkURI, file,
+ ACTION_OBJECT_NOTIFY,
+ persist,
+ !(flags & EMBED_PERSIST_SHOW_PROGRESS));
+
+ rv = bpersist->SaveURI (linkURI, nsnull, file);
+ if (NS_FAILED(rv)) return G_FAILED;
+ }
+
+ return G_OK;
+}
+
diff --git a/embed/mozilla/mozilla-embed-persist.h b/embed/mozilla/mozilla-embed-persist.h
new file mode 100644
index 000000000..bcd073ca3
--- /dev/null
+++ b/embed/mozilla/mozilla-embed-persist.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef MOZILLA_EMBED_PERSIST_H
+#define MOZILLA_EMBED_PERSIST_H
+
+#include "ephy-embed-persist.h"
+
+#include <glib-object.h>
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef struct MozillaEmbedPersistClass MozillaEmbedPersistClass;
+
+#define MOZILLA_EMBED_PERSIST_TYPE (mozilla_embed_persist_get_type ())
+#define MOZILLA_EMBED_PERSIST(obj) (GTK_CHECK_CAST ((obj), MOZILLA_EMBED_PERSIST_TYPE, MozillaEmbedPersist))
+#define MOZILLA_EMBED_PERSIST_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), MOZILLA_EMBED_PERSIST_TYPE, MozillaEmbedPersistClass))
+#define IS_MOZILLA_EMBED_PERSIST(obj) (GTK_CHECK_TYPE ((obj), MOZILLA_EMBED_PERSIST_TYPE))
+#define IS_MOZILLA_EMBED_PERSIST_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), MOZILLA_EMBED_PERSIST))
+#define MOZILLA_EMBED_PERSIST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MOZILLA_EMBED_PERSIST_TYPE, MozillaEmbedPersistClass))
+
+typedef struct MozillaEmbedPersist MozillaEmbedPersist;
+typedef struct MozillaEmbedPersistPrivate MozillaEmbedPersistPrivate;
+
+struct MozillaEmbedPersist
+{
+ EphyEmbedPersist parent;
+ MozillaEmbedPersistPrivate *priv;
+};
+
+struct MozillaEmbedPersistClass
+{
+ EphyEmbedPersistClass parent_class;
+};
+
+GType mozilla_embed_persist_get_type (void);
+
+G_END_DECLS
+
+#endif
diff --git a/embed/mozilla/mozilla-embed-shell.cpp b/embed/mozilla/mozilla-embed-shell.cpp
new file mode 100644
index 000000000..00b3c390d
--- /dev/null
+++ b/embed/mozilla/mozilla-embed-shell.cpp
@@ -0,0 +1,1106 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "glib.h"
+#include "ephy-string.h"
+#include "gtkmozembed.h"
+#include "mozilla-embed-shell.h"
+#include "mozilla-prefs.h"
+#include "ephy-prefs.h"
+#include "ephy-file-helpers.h"
+#include "mozilla-notifiers.h"
+#include "mozilla-i18n.h"
+#include "eel-gconf-extensions.h"
+#include "ephy-embed-prefs.h"
+#include "MozRegisterComponents.h"
+#include "FilePicker.h"
+
+#include <time.h>
+#include <libgnome/gnome-i18n.h>
+#include <string.h>
+#include <nsICacheService.h>
+#include <nsCOMPtr.h>
+#include <nsNetCID.h>
+#include <nsIServiceManager.h>
+#include <nsIIOService.h>
+#include <nsIProtocolProxyService.h>
+#include <nsIJVMManager.h>
+#include <nsIAtom.h>
+#include <nsICharsetConverterManager.h>
+#include <nsICharsetConverterManager2.h>
+#include <nsIFontList.h>
+#include <nsISupportsPrimitives.h>
+#include <nsReadableUtils.h>
+#include <nsIPermissionManager.h>
+#include <nsICookieManager.h>
+#include <nsIPermission.h>
+#include <nsIPasswordManager.h>
+#include <nsIPassword.h>
+#include <nsICookie.h>
+#include <nsCCookieManager.h>
+#include <nsCPasswordManager.h>
+
+#define MOZILLA_PROFILE_DIR "/mozilla"
+#define MOZILLA_PROFILE_NAME "epiphany"
+#define MOZILLA_PROFILE_FILE "prefs.js"
+
+static void
+mozilla_embed_shell_class_init (MozillaEmbedShellClass *klass);
+static void
+mozilla_embed_shell_init (MozillaEmbedShell *ges);
+static void
+mozilla_embed_shell_finalize (GObject *object);
+
+static void
+impl_get_capabilities (EphyEmbedShell *shell,
+ EmbedShellCapabilities *caps);
+static gresult
+impl_clear_cache (EphyEmbedShell *shell,
+ CacheType type);
+static gresult
+impl_set_offline_mode (EphyEmbedShell *shell,
+ gboolean offline);
+static gresult
+impl_load_proxy_autoconf (EphyEmbedShell *shell,
+ const char* url);
+static gresult
+impl_get_charset_titles (EphyEmbedShell *shell,
+ const char *group,
+ GList **charsets);
+static gresult
+impl_get_charset_groups (EphyEmbedShell *shell,
+ GList **groups);
+static gresult
+impl_get_font_list (EphyEmbedShell *shell,
+ const char *langGroup,
+ const char *fontType,
+ GList **fontList,
+ char **default_font);
+static gresult
+impl_set_permission (EphyEmbedShell *shell,
+ const char *url,
+ PermissionType type,
+ gboolean allow);
+static gresult
+impl_list_permissions (EphyEmbedShell *shell,
+ PermissionType type,
+ GList **permissions);
+static gresult
+impl_remove_permissions (EphyEmbedShell *shell,
+ PermissionType type,
+ GList *permissions);
+static gresult
+impl_list_cookies (EphyEmbedShell *shell,
+ GList **cookies);
+static gresult
+impl_remove_cookies (EphyEmbedShell *shell,
+ GList *cookies);
+static gresult
+impl_list_passwords (EphyEmbedShell *shell,
+ PasswordType type,
+ GList **passwords);
+static gresult
+impl_remove_passwords (EphyEmbedShell *shell,
+ GList *passwords,
+ PasswordType type);
+static gresult
+impl_show_file_picker (EphyEmbedShell *shell,
+ GtkWidget *parentWidget,
+ const char *title,
+ const char *directory,
+ const char *file,
+ FilePickerMode mode,
+ char **ret_fullpath,
+ gboolean *ret_save_content,
+ FileFormat *file_formats,
+ int *ret_file_format);
+
+static void mozilla_embed_shell_new_window_orphan_cb (GtkMozEmbedSingle *embed,
+ GtkMozEmbed **retval,
+ guint chrome_mask,
+ EphyEmbedShell *shell);
+
+struct MozillaEmbedShellPrivate
+{
+ GHashTable *charsets_hash;
+ GList *sorted_charsets_titles;
+};
+
+static NS_DEFINE_CID(kJVMManagerCID, NS_JVMMANAGER_CID);
+
+static GObjectClass *parent_class = NULL;
+
+GType
+mozilla_embed_shell_get_type (void)
+{
+ static GType mozilla_embed_shell_type = 0;
+
+ if (mozilla_embed_shell_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (MozillaEmbedShellClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) mozilla_embed_shell_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (MozillaEmbedShell),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) mozilla_embed_shell_init
+ };
+
+ mozilla_embed_shell_type = g_type_register_static (EPHY_EMBED_SHELL_TYPE,
+ "MozillaEmbedShell",
+ &our_info, (GTypeFlags)0);
+ }
+
+ return mozilla_embed_shell_type;
+}
+
+static void
+mozilla_embed_shell_class_init (MozillaEmbedShellClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ EphyEmbedShellClass *shell_class;
+
+ parent_class = (GObjectClass *) g_type_class_peek_parent (klass);
+ shell_class = EPHY_EMBED_SHELL_CLASS (klass);
+
+ object_class->finalize = mozilla_embed_shell_finalize;
+
+ shell_class->get_capabilities = impl_get_capabilities;
+ shell_class->clear_cache = impl_clear_cache;
+ shell_class->set_offline_mode = impl_set_offline_mode;
+ shell_class->load_proxy_autoconf = impl_load_proxy_autoconf;
+ shell_class->get_charset_titles = impl_get_charset_titles;
+ shell_class->get_charset_groups = impl_get_charset_groups;
+ shell_class->get_font_list = impl_get_font_list;
+ shell_class->set_permission = impl_set_permission;
+ shell_class->list_permissions = impl_list_permissions;
+ shell_class->remove_permissions = impl_remove_permissions;
+ shell_class->list_cookies = impl_list_cookies;
+ shell_class->remove_cookies = impl_remove_cookies;
+ shell_class->list_passwords = impl_list_passwords;
+ shell_class->remove_passwords = impl_remove_passwords;
+ shell_class->show_file_picker = impl_show_file_picker;
+}
+
+static void
+mozilla_load_proxy_prefs (MozillaEmbedShell *shell)
+{
+ char *tmp;
+ int i, mozilla_mode = 0;
+
+ /* Proxy mode */
+ tmp = eel_gconf_get_string (CONF_NETWORK_PROXY_MODE);
+ g_return_if_fail (tmp != NULL);
+
+ if (strcmp (tmp, "manual") == 0)
+ {
+ mozilla_mode = 1;
+ }
+ else if (strcmp (tmp, "auto") == 0)
+ {
+ mozilla_mode = 2;
+ }
+
+ mozilla_prefs_set_int ("network.proxy.type", mozilla_mode);
+ g_free (tmp);
+
+ /* Http proxy */
+ tmp = eel_gconf_get_string (CONF_NETWORK_HTTP_PROXY);
+ g_return_if_fail (tmp != NULL);
+ mozilla_prefs_set_string ("network.proxy.http", tmp);
+ g_free (tmp);
+
+ i = eel_gconf_get_integer (CONF_NETWORK_HTTP_PROXY_PORT);
+ mozilla_prefs_set_int ("network.proxy.http_port", i);
+
+ /* Ftp proxy */
+ tmp = eel_gconf_get_string (CONF_NETWORK_FTP_PROXY);
+ g_return_if_fail (tmp != NULL);
+ mozilla_prefs_set_string ("network.proxy.ftp", tmp);
+ g_free (tmp);
+
+ i = eel_gconf_get_integer (CONF_NETWORK_FTP_PROXY_PORT);
+ mozilla_prefs_set_int ("network.proxy.ftp_port", i);
+
+ /* Secure proxy */
+ tmp = eel_gconf_get_string (CONF_NETWORK_SSL_PROXY);
+ g_return_if_fail (tmp != NULL);
+ mozilla_prefs_set_string ("network.proxy.ssl", tmp);
+ g_free (tmp);
+
+ i = eel_gconf_get_integer (CONF_NETWORK_SSL_PROXY_PORT);
+ mozilla_prefs_set_int ("network.proxy.ssl_port", i);
+
+ /* Socks proxy */
+ tmp = eel_gconf_get_string (CONF_NETWORK_SOCKS_PROXY);
+ g_return_if_fail (tmp != NULL);
+ mozilla_prefs_set_string ("network.proxy.socks", tmp);
+ g_free (tmp);
+
+ i = eel_gconf_get_integer (CONF_NETWORK_SOCKS_PROXY_PORT);
+ mozilla_prefs_set_int ("network.proxy.socks_port", i);
+
+ /* Autoconfiguration */
+ tmp = eel_gconf_get_string (CONF_NETWORK_PROXY_AUTO_URL);
+ g_return_if_fail (tmp != NULL);
+ ephy_embed_shell_load_proxy_autoconf
+ (EPHY_EMBED_SHELL (shell), tmp);
+ g_free (tmp);
+}
+
+static void
+mozilla_set_default_prefs (void)
+{
+ mozilla_prefs_set_boolean ("mozilla.widget.raise-on-setfocus",
+ FALSE);
+ mozilla_prefs_set_boolean ("browser.display.use_system_colors",
+ FALSE);
+
+ /* set default search engine */
+ mozilla_prefs_set_string ("keyword.URL",_("http://www.google.com/search?q="));
+ mozilla_prefs_set_boolean ("keyword.enabled", TRUE);
+ mozilla_prefs_set_boolean ("security.checkloaduri", FALSE);
+
+ /* while we have no UI */
+ mozilla_prefs_set_boolean ("wallet.captureForms", FALSE);
+
+ /* deactivate mailcap and mime.types support */
+ mozilla_prefs_set_string ("helpers.global_mime_types_file", "");
+ mozilla_prefs_set_string ("helpers.global_mailcap_file", "");
+ mozilla_prefs_set_string ("helpers.private_mime_types_file", "");
+ mozilla_prefs_set_string ("helpers.private_mailcap_file", "");
+
+ /* dont allow xpi installs from epiphany, there are crashes */
+ mozilla_prefs_set_boolean ("xpinstall.enabled", FALSE);
+
+ /* disable sucky XUL ftp view, have nice ns4-like html page instead */
+ mozilla_prefs_set_boolean ("network.dir.generate_html", TRUE);
+
+ /* set the right accept encoding flags */
+ mozilla_prefs_set_string ("network.http.accept-encoding" ,
+ "gzip, deflate, compress;q=0.9");
+
+ mozilla_prefs_save ();
+}
+
+static void
+mozilla_init_single (MozillaEmbedShell *mes)
+{
+ GtkMozEmbedSingle *single;
+
+ /* get single */
+ single = gtk_moz_embed_single_get ();
+ if (single == NULL)
+ {
+ g_warning ("Failed to get singleton embed object!\n");
+ }
+
+ /* allow creation of orphan windows */
+ g_signal_connect (G_OBJECT (single), "new_window_orphan",
+ GTK_SIGNAL_FUNC (mozilla_embed_shell_new_window_orphan_cb),
+ mes);
+}
+
+static void
+mozilla_init_home (void)
+{
+ char *mozilla_five_home;
+ mozilla_five_home = g_strdup (g_getenv ("MOZILLA_FIVE_HOME"));
+ gtk_moz_embed_set_comp_path (mozilla_five_home);
+ g_free (mozilla_five_home);
+}
+
+void
+mozilla_init_profile (void)
+{
+ char *profile_path;
+ profile_path = g_build_filename (ephy_dot_dir (),
+ MOZILLA_PROFILE_DIR,
+ NULL);
+ gtk_moz_embed_set_profile_path (profile_path, MOZILLA_PROFILE_NAME);
+ g_free (profile_path);
+}
+
+static gboolean
+is_new_build (void)
+{
+ gboolean new_build = FALSE;
+ char *mozprefs, *build_test;
+
+ mozprefs = g_build_filename (ephy_dot_dir (),
+ MOZILLA_PROFILE_DIR,
+ MOZILLA_PROFILE_NAME,
+ MOZILLA_PROFILE_FILE,
+ NULL);
+
+ /* no mozilla prefs ? or new epiphany build */
+ build_test = eel_gconf_get_string ("/apps/epiphany/gconf_test");
+ if (!g_file_test(mozprefs, G_FILE_TEST_EXISTS) ||
+ build_test == NULL ||
+ strncmp (build_test, __TIME__, 8) != 0)
+ {
+ new_build = TRUE;
+ eel_gconf_set_string ("/apps/epiphany/gconf_test", __TIME__);
+ }
+
+ g_free (mozprefs);
+ g_free (build_test);
+
+ return new_build;
+}
+
+static void
+mozilla_init_prefs (void)
+{
+ mozilla_set_default_prefs ();
+ mozilla_notifiers_set_defaults ();
+}
+
+static gboolean
+have_gnome_url_handler (const gchar *protocol)
+{
+ gchar *key, *cmd;
+ gboolean rv;
+
+ key = g_strdup_printf ("/desktop/gnome/url-handlers/%s/command",
+ protocol);
+ cmd = eel_gconf_get_string (key);
+ g_free (key);
+
+ rv = (cmd != NULL);
+ g_free (cmd);
+
+ if (!rv) return rv;
+
+ key = g_strdup_printf ("/desktop/gnome/url-handlers/%s/enabled",
+ protocol);
+ rv = eel_gconf_get_boolean (key);
+ g_free (key);
+
+ return rv;
+}
+
+static void
+mozilla_register_external_protocols (void)
+{
+ /* FIXME register only when needed */
+ if (have_gnome_url_handler ("ftp"))
+ {
+ mozilla_register_FtpProtocolHandler ();
+ }
+ else
+ {
+ mozilla_unregister_FtpProtocolHandler ();
+ }
+
+ mozilla_register_MailtoProtocolHandler ();
+}
+
+static void
+mozilla_embed_shell_init (MozillaEmbedShell *mes)
+{
+ gboolean new_build;
+
+ mes->priv = g_new0 (MozillaEmbedShellPrivate, 1);
+
+ mes->priv->charsets_hash = NULL;
+ mes->priv->sorted_charsets_titles = NULL;
+
+ new_build = is_new_build ();
+
+ /* Pre initialization */
+ mozilla_notifiers_init (mes);
+ mozilla_init_home ();
+ mozilla_init_profile ();
+
+ /* Fire up the best */
+ gtk_moz_embed_push_startup ();
+
+ /* Post initialization */
+ if (new_build)
+ {
+ mozilla_init_prefs ();
+ }
+
+ mozilla_load_proxy_prefs (mes);
+
+ mozilla_init_single (mes);
+
+ mozilla_register_components ();
+
+ mozilla_register_external_protocols ();
+
+ /* FIXME alert if fails */
+}
+
+static void
+mozilla_embed_shell_new_window_orphan_cb (GtkMozEmbedSingle *embed,
+ GtkMozEmbed **retval,
+ guint chrome_mask,
+ EphyEmbedShell *shell)
+{
+ /* FIXME conversion duped in mozilla_embed */
+ EphyEmbed *new_embed;
+ int i;
+ EmbedChromeMask mask = EMBED_CHROME_OPENASPOPUP;
+
+ struct
+ {
+ guint chromemask;
+ EmbedChromeMask embed_mask;
+ }
+ conversion_map [] =
+ {
+ { GTK_MOZ_EMBED_FLAG_DEFAULTCHROME, EMBED_CHROME_DEFAULT },
+ { GTK_MOZ_EMBED_FLAG_MENUBARON, EMBED_CHROME_MENUBARON },
+ { GTK_MOZ_EMBED_FLAG_TOOLBARON, EMBED_CHROME_TOOLBARON },
+ { GTK_MOZ_EMBED_FLAG_STATUSBARON, EMBED_CHROME_STATUSBARON },
+ { GTK_MOZ_EMBED_FLAG_WINDOWRAISED, EMBED_CHROME_WINDOWRAISED },
+ { GTK_MOZ_EMBED_FLAG_WINDOWLOWERED, EMBED_CHROME_WINDOWLOWERED },
+ { GTK_MOZ_EMBED_FLAG_CENTERSCREEN, EMBED_CHROME_CENTERSCREEN },
+ { GTK_MOZ_EMBED_FLAG_OPENASDIALOG, EMBED_CHROME_OPENASDIALOG },
+ { GTK_MOZ_EMBED_FLAG_OPENASCHROME, EMBED_CHROME_OPENASCHROME },
+ { 0, EMBED_CHROME_NONE }
+ };
+
+ for (i = 0; conversion_map[i].chromemask != 0; i++)
+ {
+ if (chrome_mask & conversion_map[i].chromemask)
+ {
+ mask = (EmbedChromeMask) (mask | conversion_map[i].embed_mask);
+ }
+ }
+
+ g_signal_emit_by_name (shell, "new_window_orphan", &new_embed, mask);
+
+ g_assert (new_embed != NULL);
+
+ *retval = GTK_MOZ_EMBED(EPHY_EMBED(new_embed));
+}
+
+static void
+mozilla_embed_shell_finalize (GObject *object)
+{
+ MozillaEmbedShell *mes;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (IS_MOZILLA_EMBED_SHELL (object));
+
+ mes = MOZILLA_EMBED_SHELL (object);
+
+ g_return_if_fail (mes->priv != NULL);
+
+ mozilla_notifiers_free ();
+
+ mozilla_prefs_save ();
+
+ gtk_moz_embed_pop_startup ();
+
+ g_free (mes->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+impl_get_capabilities (EphyEmbedShell *shell,
+ EmbedShellCapabilities *caps)
+{
+ EmbedShellCapabilities mycaps;
+
+ mycaps = (EmbedShellCapabilities)
+ (CACHE_CLEAR_CAP |
+ OFFLINE_CAP |
+ PROXY_AUTOCONF_CAP |
+ JAVA_CONSOLE_CAP |
+ JS_CONSOLE_CAP |
+ CHARSETS_CAP |
+ PERMISSIONS_CAP |
+ COOKIES_CAP |
+ PASSWORDS_CAP);
+
+ *caps = mycaps;
+}
+
+static gresult
+impl_clear_cache (EphyEmbedShell *shell,
+ CacheType type)
+{
+ nsresult rv;
+
+ nsCOMPtr<nsICacheService> CacheService =
+ do_GetService (NS_CACHESERVICE_CONTRACTID, &rv);
+ if (NS_FAILED(rv)) return G_FAILED;
+
+ CacheService->EvictEntries((guint)type);
+
+ return G_OK;
+}
+
+static gresult
+impl_set_offline_mode (EphyEmbedShell *shell,
+ gboolean offline)
+{
+ nsresult rv;
+
+ nsCOMPtr<nsIIOService> io = do_GetService(NS_IOSERVICE_CONTRACTID, &rv);
+ if (NS_FAILED(rv))
+ return G_FAILED;
+
+ rv = io->SetOffline(offline);
+ if (NS_SUCCEEDED(rv)) return G_FAILED;
+
+ return G_OK;
+}
+
+static gresult
+impl_load_proxy_autoconf (EphyEmbedShell *shell,
+ const char* url)
+{
+ nsresult rv;
+
+ nsCOMPtr<nsIProtocolProxyService> pps =
+ do_GetService ("@mozilla.org/network/protocol-proxy-service;1",
+ &rv);
+ if (NS_FAILED(rv) || !pps) return G_FAILED;
+
+ rv = pps->ConfigureFromPAC (url);
+ if (NS_FAILED(rv)) return G_FAILED;
+
+ return G_OK;
+}
+
+static gresult
+fill_charsets_lists (MozillaEmbedShellPrivate *priv)
+{
+ nsresult rv;
+ char *tmp;
+ PRUint32 cscount;
+ PRUint32 translated_cscount = get_translated_cscount ();
+ char *charset_str, *charset_title_str;
+
+ nsCOMPtr<nsIAtom> docCharsetAtom;
+ nsCOMPtr<nsICharsetConverterManager2> ccm2 =
+ do_GetService (NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv);
+ if (!NS_SUCCEEDED(rv)) return G_FAILED;
+
+ nsCOMPtr <nsISupportsArray> cs_list;
+ rv = ccm2->GetDecoderList (getter_AddRefs(cs_list));
+ if (!NS_SUCCEEDED(rv)) return G_FAILED;
+
+ rv = cs_list->Count(&cscount);
+ priv->charsets_hash = g_hash_table_new (g_str_hash, g_str_equal);
+ for (PRUint32 i = 0; i < cscount; i++)
+ {
+ nsCOMPtr<nsISupports> cssupports =
+ (dont_AddRef)(cs_list->ElementAt(i));
+ nsCOMPtr<nsIAtom> csatom ( do_QueryInterface(cssupports) );
+ nsAutoString charset_ns, charset_title_ns;
+
+ /* charset name */
+ rv = csatom->ToString(charset_ns);
+ tmp = ToNewCString (charset_ns);
+ if (tmp == NULL || strlen (tmp) == 0)
+ {
+ continue;
+ }
+ charset_str = g_strdup (tmp);
+ nsMemory::Free (tmp);
+ tmp = nsnull;
+
+ /* charset readable title */
+ rv = ccm2->GetCharsetTitle2(csatom, &charset_title_ns);
+ tmp = ToNewCString (charset_title_ns);
+ if (tmp == NULL ||
+ strlen (tmp) == 0)
+ {
+ if (tmp) nsMemory::Free (tmp);
+ charset_title_str = g_strdup (charset_str);
+ }
+ else
+ {
+ charset_title_str = g_strdup (tmp);
+ nsMemory::Free (tmp);
+ tmp = nsnull;
+ }
+
+ for (PRUint32 j = 0; j < translated_cscount; j++)
+ {
+ if (g_ascii_strcasecmp (
+ charset_str,
+ charset_trans_array[j].charset_name) == 0)
+ {
+ g_free (charset_title_str);
+ charset_title_str = (char *)
+ _(charset_trans_array[j].charset_title);
+ break;
+ }
+ }
+
+ /* fill the hash and the sorted list */
+ g_hash_table_insert (priv->charsets_hash, charset_title_str, charset_str);
+ priv->sorted_charsets_titles =
+ g_list_insert_sorted (priv->sorted_charsets_titles,
+ (gpointer)charset_title_str,
+ (GCompareFunc)g_ascii_strcasecmp);
+ }
+
+ return G_OK;
+}
+
+static void
+ensure_charsets_tables (MozillaEmbedShell *shell)
+{
+ if (!shell->priv->charsets_hash)
+ {
+ fill_charsets_lists (shell->priv);
+ }
+}
+
+static gresult
+impl_get_charset_titles (EphyEmbedShell *shell,
+ const char *group,
+ GList **charsets)
+{
+ MozillaEmbedShell *mshell = MOZILLA_EMBED_SHELL(shell);
+ int count = get_translated_cscount ();
+ GList *l = NULL;
+ int j;
+
+ ensure_charsets_tables (mshell);
+ g_return_val_if_fail (mshell->priv->charsets_hash != NULL, G_FAILED);
+
+ for (j = 0; j < count; j++)
+ {
+ if (group == NULL ||
+ strcmp (group, lgroups[charset_trans_array[j].lgroup]) == 0)
+ {
+ CharsetInfo *info;
+ info = g_new0 (CharsetInfo, 1);
+ info->name = charset_trans_array[j].charset_name;
+ info->title = charset_trans_array[j].charset_title;
+ l = g_list_append (l, info);
+
+ /* FIXME check that the encoding exists in mozilla before
+ * adding it */
+ }
+ }
+
+ *charsets = l;
+
+ return G_OK;
+}
+
+static gresult
+impl_get_charset_groups (EphyEmbedShell *shell,
+ GList **groups)
+{
+ GList *l = NULL;
+ int i;
+
+ for (i = 0; lgroups[i] != NULL; i++)
+ {
+ l = g_list_append (l, (gpointer)lgroups[i]);
+ }
+
+ *groups = l;
+
+ return G_OK;
+}
+
+static gresult
+impl_get_font_list (EphyEmbedShell *shell,
+ const char *langGroup,
+ const char *fontType,
+ GList **fontList,
+ char **default_font)
+{
+ nsresult rv;
+
+ nsCOMPtr<nsIFontList> mozFontList;
+ mozFontList = do_CreateInstance("@mozilla.org/gfx/fontlist;1", &rv);
+ if(NS_FAILED(rv)) return G_FAILED;
+
+ nsCOMPtr<nsISimpleEnumerator> fontEnum;
+ mozFontList->AvailableFonts(NS_ConvertUTF8toUCS2(langGroup).get(),
+ NS_ConvertUTF8toUCS2(fontType).get(),
+ getter_AddRefs(fontEnum));
+ if(NS_FAILED(rv)) return G_FAILED;
+
+ GList *l = NULL;
+ PRBool enumResult;
+ for(fontEnum->HasMoreElements(&enumResult) ;
+ enumResult == PR_TRUE;
+ fontEnum->HasMoreElements(&enumResult))
+ {
+ nsCOMPtr<nsISupportsString> fontName;
+ fontEnum->GetNext(getter_AddRefs(fontName));
+ if(NS_FAILED(rv)) return G_FAILED;
+
+ nsString fontString;
+ fontName->GetData(fontString);
+
+ char *gFontString;
+ gFontString = g_strdup(NS_ConvertUCS2toUTF8(fontString).get());
+ l = g_list_append(l, gFontString);
+ }
+ *fontList = l;
+
+ if (default_font != NULL)
+ {
+ char key [255];
+
+ sprintf (key, "font.name.%s.%s", fontType, langGroup);
+
+ *default_font = mozilla_prefs_get_string (key);
+ }
+
+ return G_OK;
+}
+
+static gresult
+impl_set_permission (EphyEmbedShell *shell,
+ const char *url,
+ PermissionType type,
+ gboolean allow)
+{
+ nsresult rv;
+ nsCOMPtr<nsIPermissionManager> permissionManager =
+ do_CreateInstance (NS_PERMISSIONMANAGER_CONTRACTID);
+
+ rv = permissionManager->Add (nsDependentCString(url),
+ allow ? PR_TRUE : PR_FALSE, type);
+ if (NS_FAILED(rv)) return G_FAILED;
+
+ return G_OK;
+}
+
+static gresult
+impl_list_permissions (EphyEmbedShell *shell,
+ PermissionType type,
+ GList **permissions)
+{
+ nsresult result;
+
+ *permissions = NULL;
+
+ nsCOMPtr<nsIPermissionManager> permissionManager =
+ do_CreateInstance (NS_PERMISSIONMANAGER_CONTRACTID);
+ nsCOMPtr<nsISimpleEnumerator> permissionEnumerator;
+ result = permissionManager->GetEnumerator (getter_AddRefs(permissionEnumerator));
+ if (NS_FAILED(result)) return G_FAILED;
+
+ PRBool enumResult;
+ for (permissionEnumerator->HasMoreElements(&enumResult) ;
+ enumResult == PR_TRUE ;
+ permissionEnumerator->HasMoreElements(&enumResult))
+ {
+ nsCOMPtr<nsIPermission> nsPermission;
+ result = permissionEnumerator->GetNext (getter_AddRefs(nsPermission));
+ if (NS_FAILED(result)) return G_FAILED;
+
+ PRInt32 cType;
+ nsPermission->GetType (&cType);
+ if (cType == type)
+ {
+ PermissionInfo *b = g_new0 (PermissionInfo, 1);
+ gchar *tmp = NULL;
+
+ nsPermission->GetHost (&tmp);
+ b->domain = g_strdup (tmp);
+ nsMemory::Free (tmp);
+
+ PRBool cap;
+ nsPermission->GetCapability (&cap);
+ if (cap == PR_TRUE)
+ b->type = g_strdup (_("Allowed"));
+ else
+ b->type = g_strdup (_("Blocked"));
+
+ *permissions = g_list_prepend (*permissions, b);
+ }
+ }
+
+ *permissions = g_list_reverse (*permissions);
+
+ return G_OK;
+}
+
+static gresult
+impl_remove_permissions (EphyEmbedShell *shell,
+ PermissionType type,
+ GList *permissions)
+{
+ nsresult result;
+ nsCOMPtr<nsIPermissionManager> permissionManager =
+ do_CreateInstance (NS_PERMISSIONMANAGER_CONTRACTID);
+
+ for (GList *permissions = g_list_first(permissions); permissions != NULL;
+ permissions = g_list_next(permissions))
+ {
+ PermissionInfo *b = (PermissionInfo *)permissions->data;
+ result = permissionManager->Remove (nsDependentCString(b->domain),
+ type);
+ if (NS_FAILED(result)) return G_FAILED;
+ };
+
+ return G_OK;
+}
+
+static gresult
+impl_list_cookies (EphyEmbedShell *shell,
+ GList **cookies)
+{
+ nsresult result;
+
+ nsCOMPtr<nsICookieManager> cookieManager =
+ do_CreateInstance (NS_COOKIEMANAGER_CONTRACTID);
+ nsCOMPtr<nsISimpleEnumerator> cookieEnumerator;
+ result =
+ cookieManager->GetEnumerator (getter_AddRefs(cookieEnumerator));
+ if (NS_FAILED(result)) return G_FAILED;
+
+ PRBool enumResult;
+ for (cookieEnumerator->HasMoreElements(&enumResult) ;
+ enumResult == PR_TRUE ;
+ cookieEnumerator->HasMoreElements(&enumResult))
+ {
+ CookieInfo *c;
+
+ nsCOMPtr<nsICookie> nsCookie;
+ result = cookieEnumerator->GetNext (getter_AddRefs(nsCookie));
+ if (NS_FAILED(result)) return G_FAILED;
+
+ c = g_new0 (CookieInfo, 1);
+
+ nsCAutoString transfer;
+
+ nsCookie->GetHost (transfer);
+ c->base.domain = g_strdup (transfer.get());
+ nsCookie->GetName (transfer);
+ c->name = g_strdup (transfer.get());
+ nsCookie->GetValue (transfer);
+ c->value = g_strdup (transfer.get());
+ nsCookie->GetPath (transfer);
+ c->path = g_strdup (transfer.get());
+
+ PRBool isSecure;
+ nsCookie->GetIsSecure (&isSecure);
+ if (isSecure == PR_TRUE)
+ c->secure = g_strdup (_("Yes"));
+ else
+ c->secure = g_strdup (_("No"));
+
+ PRUint64 dateTime;
+ nsCookie->GetExpires (&dateTime);
+ if(dateTime == 0)
+ c->expire = g_strdup (_("End of current session"));
+ else
+ c->expire = g_strdup_printf ("%s",ctime((time_t*)&dateTime));
+
+ *cookies = g_list_prepend (*cookies, c);
+ }
+
+ *cookies = g_list_reverse (*cookies);
+
+ return G_OK;
+}
+
+static gresult
+impl_remove_cookies (EphyEmbedShell *shell,
+ GList *cookies)
+{
+ nsresult result;
+ GList *cl;
+ nsCOMPtr<nsICookieManager> cookieManager =
+ do_CreateInstance (NS_COOKIEMANAGER_CONTRACTID);
+
+ for (cl = g_list_first(cookies) ; cl != NULL ;
+ cl = g_list_next (cl))
+ {
+ CookieInfo *c = (CookieInfo *)cl->data;
+
+ result = cookieManager->Remove (NS_LITERAL_CSTRING(c->base.domain),
+ NS_LITERAL_CSTRING(c->name),
+ NS_LITERAL_CSTRING(c->path),
+ PR_FALSE);
+ if (NS_FAILED(result)) return G_FAILED;
+ };
+
+ return G_OK;
+}
+
+static gresult
+impl_list_passwords (EphyEmbedShell *shell,
+ PasswordType type,
+ GList **passwords)
+{
+ nsresult result = NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIPasswordManager> passwordManager =
+ do_CreateInstance (NS_PASSWORDMANAGER_CONTRACTID);
+ nsCOMPtr<nsISimpleEnumerator> passwordEnumerator;
+ if (type == PASSWORD_PASSWORD)
+ result = passwordManager->GetEnumerator
+ (getter_AddRefs(passwordEnumerator));
+ else if (type == PASSWORD_REJECT)
+ result = passwordManager->GetRejectEnumerator
+ (getter_AddRefs(passwordEnumerator));
+ if (NS_FAILED(result)) return G_FAILED;
+
+ PRBool enumResult;
+ for (passwordEnumerator->HasMoreElements(&enumResult) ;
+ enumResult == PR_TRUE ;
+ passwordEnumerator->HasMoreElements(&enumResult))
+ {
+ nsCOMPtr<nsIPassword> nsPassword;
+ result = passwordEnumerator->GetNext
+ (getter_AddRefs(nsPassword));
+ if (NS_FAILED(result)) return G_FAILED;
+
+ PasswordInfo *p = g_new0 (PasswordInfo, 1);
+
+ nsCAutoString transfer;
+ nsPassword->GetHost (transfer);
+ p->host = g_strdup (transfer.get());
+
+ if (type == PASSWORD_PASSWORD)
+ {
+ nsAutoString unicodeName;
+ nsPassword->GetUser (unicodeName);
+ p->username = g_strdup(NS_ConvertUCS2toUTF8(unicodeName).get());
+ }
+
+ *passwords = g_list_prepend (*passwords, p);
+ }
+
+ *passwords = g_list_reverse (*passwords);
+
+ return G_OK;
+}
+
+static gresult
+impl_remove_passwords (EphyEmbedShell *shell,
+ GList *passwords,
+ PasswordType type)
+{
+ nsresult result = NS_ERROR_FAILURE;
+ nsCOMPtr<nsIPasswordManager> passwordManager =
+ do_CreateInstance (NS_PASSWORDMANAGER_CONTRACTID);
+
+ for (GList *l = g_list_first(passwords) ; l !=NULL ;
+ l = g_list_next(l))
+ {
+ PasswordInfo *p = (PasswordInfo *)l->data;
+ if (type == PASSWORD_PASSWORD)
+ {
+ result = passwordManager->RemoveUser (NS_LITERAL_CSTRING(p->host),
+ NS_ConvertUTF8toUCS2(nsDependentCString(p->username)));
+ }
+ else if (type == PASSWORD_REJECT)
+ {
+ result = passwordManager->RemoveReject
+ (nsDependentCString(p->host));
+ };
+
+ if (NS_FAILED(result)) return G_FAILED;
+ };
+
+ return G_OK;
+}
+
+static gresult
+impl_show_file_picker (EphyEmbedShell *shell,
+ GtkWidget *parentWidget,
+ const char *title,
+ const char *directory,
+ const char *file,
+ FilePickerMode mode,
+ char **ret_fullpath,
+ gboolean *ret_save_content,
+ FileFormat *file_formats,
+ int *ret_file_format)
+{
+ PRBool showContentCheck;
+ gchar *expanded_directory;
+
+ if (ret_save_content == NULL)
+ showContentCheck = PR_FALSE;
+ else
+ showContentCheck = PR_TRUE;
+
+ GFilePicker *filePicker = new GFilePicker (showContentCheck,
+ file_formats);
+
+ /* FIXME sane path: expand tilde ... */
+ expanded_directory = g_strdup (directory);
+
+ /* make sure the directory exists, and use the home directory
+ * otherwise */
+ if (!expanded_directory ||
+ !g_file_test (expanded_directory, G_FILE_TEST_IS_DIR))
+ {
+ if (expanded_directory) g_free (expanded_directory);
+ expanded_directory = g_strdup (g_get_home_dir());
+ }
+
+ nsCOMPtr<nsILocalFile> dir =
+ do_CreateInstance (NS_LOCAL_FILE_CONTRACTID);
+ dir->InitWithPath (NS_ConvertUTF8toUCS2(expanded_directory));
+ g_free (expanded_directory);
+
+ filePicker->InitWithGtkWidget (parentWidget, title, mode);
+ filePicker->SetDefaultString (NS_ConvertUTF8toUCS2(file).get());
+ filePicker->SetDisplayDirectory (dir);
+
+ PRInt16 retval;
+ filePicker->Show (&retval);
+
+ if (ret_save_content != NULL)
+ {
+ if (retval == GFilePicker::returnOKSaveContent)
+ *ret_save_content = TRUE;
+ else
+ *ret_save_content = FALSE;
+ }
+ if (ret_file_format != NULL)
+ {
+ *ret_file_format = filePicker->mSelectedFileFormat;
+ }
+
+ if (retval == nsIFilePicker::returnCancel)
+ {
+ delete filePicker;
+ return G_FAILED;
+ }
+ else
+ {
+ if (*ret_fullpath)
+ g_free (*ret_fullpath);
+ nsCOMPtr<nsILocalFile> file;
+ filePicker->GetFile (getter_AddRefs(file));
+ nsAutoString tempFullPathStr;
+ file->GetPath (tempFullPathStr);
+ *ret_fullpath = g_strdup (NS_ConvertUCS2toUTF8(tempFullPathStr).get());
+ delete filePicker;
+ return G_OK;
+ }
+}
diff --git a/embed/mozilla/mozilla-embed-shell.h b/embed/mozilla/mozilla-embed-shell.h
new file mode 100644
index 000000000..daedb2948
--- /dev/null
+++ b/embed/mozilla/mozilla-embed-shell.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef MOZILLA_EMBED_SHELL_H
+#define MOZILLA_EMBED_SHELL_H
+
+#include "glib.h"
+#include "ephy-embed-shell.h"
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define MOZILLA_EMBED_SHELL_TYPE (mozilla_embed_shell_get_type ())
+#define MOZILLA_EMBED_SHELL(obj) (GTK_CHECK_CAST ((obj), MOZILLA_EMBED_SHELL_TYPE, MozillaEmbedShell))
+#define MOZILLA_EMBED_SHELL_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), MOZILLA_EMBED_SHELL_TYPE, MozillaEmbedShellClass))
+#define IS_MOZILLA_EMBED_SHELL(obj) (GTK_CHECK_TYPE ((obj), MOZILLA_EMBED_SHELL_TYPE))
+#define IS_MOZILLA_EMBED_SHELL_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), MOZILLA_EMBED_SHELL))
+#define MOZILLA_EMBED_SHELL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MOZILLA_EMBED_SHELL_TYPE, MozillaEmbedShellClass))
+
+typedef struct MozillaEmbedShell MozillaEmbedShell;
+typedef struct MozillaEmbedShellPrivate MozillaEmbedShellPrivate;
+
+extern GObject *mozilla_js_console;
+
+struct MozillaEmbedShell
+{
+ EphyEmbedShell parent;
+ MozillaEmbedShellPrivate *priv;
+};
+
+struct MozillaEmbedShellClass
+{
+ EphyEmbedShellClass parent_class;
+};
+
+GType mozilla_embed_shell_get_type (void);
+
+G_END_DECLS
+
+#endif
diff --git a/embed/mozilla/mozilla-embed.cpp b/embed/mozilla/mozilla-embed.cpp
new file mode 100644
index 000000000..d3d2277b0
--- /dev/null
+++ b/embed/mozilla/mozilla-embed.cpp
@@ -0,0 +1,1585 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "gtkmozembed.h"
+#include "gtkmozembed_internal.h"
+#include "ephy-string.h"
+#include "ephy-embed.h"
+#include "mozilla-embed.h"
+#include "MozillaPrivate.h"
+#include "EphyWrapper.h"
+#include "EventContext.h"
+#include "nsIWindowWatcher.h"
+
+#include <nsIURI.h>
+#include <nsIURL.h>
+#include <nsNetUtil.h>
+#include <nsString.h>
+#include <nsIRequest.h>
+#include <nsIWebProgressListener.h>
+#include <nsITransportSecurityInfo.h>
+#include <nsIPrintOptions.h>
+#include <nsGfxCIID.h>
+
+#include <math.h>
+
+static void
+mozilla_embed_class_init (MozillaEmbedClass *klass);
+static void
+mozilla_embed_init (MozillaEmbed *gs);
+static void
+mozilla_embed_finalize (GObject *object);
+static void
+mozilla_embed_destroy (GtkObject *object);
+static void
+ephy_embed_init (EphyEmbedClass *embed_class);
+
+static void
+impl_get_capabilities (EphyEmbed *embed,
+ EmbedCapabilities *caps);
+static gresult
+impl_load_url (EphyEmbed *embed,
+ const char *url);
+static gresult
+impl_stop_load (EphyEmbed *embed);
+static gresult
+impl_can_go_back (EphyEmbed *embed);
+static gresult
+impl_can_go_forward (EphyEmbed *embed);
+static gresult
+impl_can_go_up (EphyEmbed *embed);
+static gresult
+impl_get_go_up_list (EphyEmbed *embed, GSList **l);
+static gresult
+impl_go_back (EphyEmbed *embed);
+static gresult
+impl_go_forward (EphyEmbed *embed);
+static gresult
+impl_go_up (EphyEmbed *embed);
+static gresult
+impl_render_data (EphyEmbed *embed,
+ const char *data,
+ guint32 len,
+ const char *base_uri,
+ const char *mime_type);
+static gresult
+impl_open_stream (EphyEmbed *embed,
+ const char *base_uri,
+ const char *mime_type);
+static gresult
+impl_append_data (EphyEmbed *embed,
+ const char *data,
+ guint32 len);
+static gresult
+impl_close_stream (EphyEmbed *embed);
+static gresult
+impl_get_title (EphyEmbed *embed,
+ char **title);
+static gresult
+impl_get_location (EphyEmbed *embed,
+ gboolean toplevel,
+ gboolean requested,
+ char **location);
+static gresult
+impl_reload (EphyEmbed *embed,
+ EmbedReloadFlags flags);
+static gresult
+impl_copy_page (EphyEmbed *dest,
+ EphyEmbed *source,
+ EmbedDisplayType display_type);
+static gresult
+impl_grab_focus (EphyEmbed *embed);
+static gresult
+impl_get_link_tags (EphyEmbed *embed,
+ const char *link_type,
+ GList **tags);
+static gresult
+impl_zoom_set (EphyEmbed *embed,
+ int zoom,
+ gboolean reflow);
+static gresult
+impl_zoom_get (EphyEmbed *embed,
+ int *zoom);
+static gresult
+impl_selection_can_cut (EphyEmbed *embed);
+static gresult
+impl_selection_can_copy (EphyEmbed *embed);
+static gresult
+impl_can_paste (EphyEmbed *embed);
+static gresult
+impl_select_all (EphyEmbed *embed);
+static gresult
+impl_selection_cut (EphyEmbed *embed);
+static gresult
+impl_selection_copy (EphyEmbed *embed);
+static gresult
+impl_paste (EphyEmbed *embed);
+static gresult
+impl_shistory_count (EphyEmbed *embed,
+ int *count);
+static gresult
+impl_shistory_get_nth (EphyEmbed *embed,
+ int nth,
+ gboolean is_relative,
+ char **url,
+ char **title);
+static gresult
+impl_shistory_get_pos (EphyEmbed *embed,
+ int *pos);
+static gresult
+impl_shistory_go_nth (EphyEmbed *embed,
+ int nth);
+static gboolean
+impl_shistory_copy (EphyEmbed *source,
+ EphyEmbed *dest);
+static gresult
+impl_scroll (EphyEmbed *embed,
+ EmbedScrollDirection direction);
+static gresult
+impl_fine_scroll (EphyEmbed *embed,
+ int horiz, int vert);
+static gresult
+impl_get_security_level (EphyEmbed *embed,
+ EmbedSecurityLevel *level,
+ char **description);
+static gresult
+impl_find (EphyEmbed *embed,
+ EmbedFindInfo *info);
+
+static gresult
+impl_set_charset (EphyEmbed *embed,
+ const char *charset);
+
+static gresult
+impl_print (EphyEmbed *embed,
+ EmbedPrintInfo *info);
+
+static gresult
+impl_print_preview_close (EphyEmbed *embed);
+
+static gresult
+impl_print_preview_num_pages (EphyEmbed *embed,
+ gint *retNum);
+static gresult
+impl_print_preview_navigate (EphyEmbed *embed,
+ EmbedPrintPreviewNavType navType,
+ gint pageNum);
+
+static void
+mozilla_embed_connect_signals (MozillaEmbed *membed);
+static char *
+mozilla_embed_get_uri_parent (const char *uri);
+static void
+mozilla_embed_location_changed_cb (GtkMozEmbed *embed, MozillaEmbed *membed);
+static void
+mozilla_embed_title_changed_cb (GtkMozEmbed *embed, MozillaEmbed *membed);
+static void
+mozilla_embed_net_state_all_cb (GtkMozEmbed *embed, const char *aURI,
+ gint state, guint status, MozillaEmbed *membed);
+static void
+mozilla_embed_progress_cb (GtkMozEmbed *embed, const char *aURI,
+ gint curprogress, gint maxprogress, MozillaEmbed *membed);
+static void
+mozilla_embed_link_message_cb (GtkMozEmbed *embed, MozillaEmbed *membed);
+static void
+mozilla_embed_js_status_cb (GtkMozEmbed *embed, MozillaEmbed *membed);
+static void
+mozilla_embed_visibility_cb (GtkMozEmbed *embed, gboolean visibility, MozillaEmbed *membed);
+static void
+mozilla_embed_destroy_brsr_cb (GtkMozEmbed *embed, MozillaEmbed *embed);
+static gint
+mozilla_embed_dom_mouse_click_cb (GtkMozEmbed *embed, gpointer dom_event, MozillaEmbed *membed);
+static gint
+mozilla_embed_dom_mouse_down_cb (GtkMozEmbed *embed, gpointer dom_event,
+ MozillaEmbed *membed);
+static void
+mozilla_embed_size_to_cb (GtkMozEmbed *embed, gint width, gint height, MozillaEmbed *membed);
+static void
+mozilla_embed_new_window_cb (GtkMozEmbed *embed,
+ GtkMozEmbed **newEmbed,
+ guint chromemask, MozillaEmbed *membed);
+static void
+mozilla_embed_security_change_cb (GtkMozEmbed *embed,
+ gpointer request,
+ guint state, MozillaEmbed *membed);
+static EmbedSecurityLevel
+mozilla_embed_security_level (MozillaEmbed *membed);
+
+/* signals to connect on each embed widget */
+static const struct
+{
+ char *event;
+ void *func; /* should be a GtkSignalFunc or similar */
+}
+signal_connections[] =
+{
+ { "location", (void *) mozilla_embed_location_changed_cb },
+ { "title", (void *) mozilla_embed_title_changed_cb },
+ { "net_state_all", (void *) mozilla_embed_net_state_all_cb },
+ { "progress_all", (void *) mozilla_embed_progress_cb },
+ { "link_message", (void *) mozilla_embed_link_message_cb },
+ { "js_status", (void *) mozilla_embed_js_status_cb },
+ { "visibility", (void *) mozilla_embed_visibility_cb },
+ { "destroy_browser", (void *) mozilla_embed_destroy_brsr_cb },
+ { "dom_mouse_click", (void *) mozilla_embed_dom_mouse_click_cb },
+ { "dom_mouse_down", (void *) mozilla_embed_dom_mouse_down_cb },
+ { "size_to", (void *) mozilla_embed_size_to_cb },
+ { "new_window", (void *) mozilla_embed_new_window_cb },
+ { "security_change", (void *) mozilla_embed_security_change_cb },
+
+ /* terminator -- must be last in the list! */
+ { NULL, NULL }
+};
+
+struct MozillaEmbedPrivate
+{
+ MozillaEmbedPrivate() : wrapper(NULL), security_state(-1), no_page(1)
+ { /* nothing */ }
+
+ EphyWrapper *wrapper;
+ nsCOMPtr<nsIRequest> request;
+ gint security_state;
+
+ /* HACK 1: No page loaded, 0: Loading an empty page, -1: Page loaded */
+ gint no_page;
+};
+
+#define WINDOWWATCHER_CONTRACTID "@mozilla.org/embedcomp/window-watcher;1"
+
+static NS_DEFINE_CID(kPrintOptionsCID, NS_PRINTOPTIONS_CID);
+
+static GObjectClass *parent_class = NULL;
+
+GType
+mozilla_embed_get_type (void)
+{
+ static GType mozilla_embed_type = 0;
+
+ if (mozilla_embed_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (MozillaEmbedClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) mozilla_embed_class_init,
+ NULL,
+ NULL, /* class_data */
+ sizeof (MozillaEmbed),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) mozilla_embed_init
+ };
+
+ static const GInterfaceInfo embed_info =
+ {
+ (GInterfaceInitFunc) ephy_embed_init, /* interface_init */
+ NULL, /* interface_finalize */
+ NULL /* interface_data */
+ };
+
+ mozilla_embed_type = g_type_register_static (GTK_TYPE_MOZ_EMBED,
+ "MozillaEmbed",
+ &our_info,
+ (GTypeFlags)0);
+ g_type_add_interface_static (mozilla_embed_type,
+ EPHY_EMBED_TYPE,
+ &embed_info);
+ }
+
+ return mozilla_embed_type;
+}
+
+static void
+ephy_embed_init (EphyEmbedClass *embed_class)
+{
+ embed_class->get_capabilities = impl_get_capabilities;
+ embed_class->load_url = impl_load_url;
+ embed_class->stop_load = impl_stop_load;
+ embed_class->can_go_back = impl_can_go_back;
+ embed_class->can_go_forward =impl_can_go_forward;
+ embed_class->can_go_up = impl_can_go_up;
+ embed_class->get_go_up_list = impl_get_go_up_list;
+ embed_class->go_back = impl_go_back;
+ embed_class->go_forward = impl_go_forward;
+ embed_class->go_up = impl_go_up;
+ embed_class->render_data = impl_render_data;
+ embed_class->open_stream = impl_open_stream;
+ embed_class->append_data = impl_append_data;
+ embed_class->close_stream = impl_close_stream;
+ embed_class->get_title = impl_get_title;
+ embed_class->get_location = impl_get_location;
+ embed_class->reload = impl_reload;
+ embed_class->copy_page = impl_copy_page;
+ embed_class->grab_focus = impl_grab_focus;
+ embed_class->get_link_tags = impl_get_link_tags;
+ embed_class->zoom_set = impl_zoom_set;
+ embed_class->zoom_get = impl_zoom_get;
+ embed_class->selection_can_cut = impl_selection_can_cut;
+ embed_class->selection_can_copy = impl_selection_can_copy;
+ embed_class->can_paste = impl_can_paste;
+ embed_class->selection_cut = impl_selection_cut;
+ embed_class->selection_copy = impl_selection_copy;
+ embed_class->paste = impl_paste;
+ embed_class->shistory_count = impl_shistory_count;
+ embed_class->shistory_get_nth = impl_shistory_get_nth;
+ embed_class->shistory_get_pos = impl_shistory_get_pos;
+ embed_class->shistory_go_nth = impl_shistory_go_nth;
+ embed_class->shistory_copy = impl_shistory_copy;
+ embed_class->scroll = impl_scroll;
+ embed_class->fine_scroll = impl_fine_scroll;
+ embed_class->get_security_level = impl_get_security_level;
+ embed_class->find = impl_find;
+ embed_class->set_charset = impl_set_charset;
+ embed_class->select_all = impl_select_all;
+ embed_class->print = impl_print;
+ embed_class->print_preview_close = impl_print_preview_close;
+ embed_class->print_preview_num_pages = impl_print_preview_num_pages;
+ embed_class->print_preview_navigate = impl_print_preview_navigate;
+}
+
+static void
+mozilla_embed_class_init (MozillaEmbedClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkObjectClass *gtk_object_class = GTK_OBJECT_CLASS (klass);
+ parent_class = (GObjectClass *) g_type_class_peek_parent (klass);
+
+ gtk_object_class->destroy = mozilla_embed_destroy;
+ object_class->finalize = mozilla_embed_finalize;
+}
+
+static void
+mozilla_embed_init (MozillaEmbed *embed)
+{
+ embed->priv = new MozillaEmbedPrivate;
+
+ mozilla_embed_connect_signals (embed);
+}
+
+gpointer
+mozilla_embed_get_galeon_wrapper (MozillaEmbed *embed)
+{
+ g_return_val_if_fail (embed->priv->wrapper != NULL, NULL);
+
+ return embed->priv->wrapper;
+}
+
+static void
+mozilla_embed_connect_signals (MozillaEmbed *embed)
+{
+ gint i;
+ EphyEmbed *gembed;
+
+ gembed = EPHY_EMBED (embed);
+
+ /* connect signals */
+ for (i = 0; signal_connections[i].event != NULL; i++)
+ {
+ g_signal_connect (G_OBJECT(embed),
+ signal_connections[i].event,
+ G_CALLBACK(signal_connections[i].func),
+ embed);
+ }
+}
+
+static void
+mozilla_embed_destroy (GtkObject *object)
+{
+ int i;
+
+ for (i = 0; signal_connections[i].event != NULL; i++)
+ {
+ g_signal_handlers_disconnect_by_func
+ (G_OBJECT(object),
+ (gpointer)signal_connections[i].func,
+ (void *)object);
+ }
+
+ GTK_OBJECT_CLASS (parent_class)->destroy (object);
+}
+
+static void
+mozilla_embed_finalize (GObject *object)
+{
+ MozillaEmbed *embed;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (IS_MOZILLA_EMBED (object));
+
+ embed = MOZILLA_EMBED (object);
+
+ g_return_if_fail (embed->priv != NULL);
+
+ if (embed->priv->wrapper)
+ {
+ embed->priv->wrapper->Destroy();
+ delete embed->priv->wrapper;
+ embed->priv->wrapper = NULL;
+ }
+
+ delete embed->priv;
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+
+#ifdef DEBUG_MARCO
+ g_print ("MozillaEmbed finalized %p\n", embed);
+#endif
+}
+
+gpointer
+mozilla_embed_get_ephy_wrapper (MozillaEmbed *embed)
+{
+ g_return_val_if_fail (embed->priv->wrapper != NULL, NULL);
+
+ return embed->priv->wrapper;
+}
+
+static void
+impl_get_capabilities (EphyEmbed *embed,
+ EmbedCapabilities *caps)
+{
+ EmbedCapabilities mozilla_caps;
+
+ mozilla_caps = (EmbedCapabilities) (
+ EMBED_CLIPBOARD_CAP |
+ EMBED_COOKIES_CAP |
+ EMBED_LINKS_CAP |
+ EMBED_ZOOM_CAP |
+ EMBED_PRINT_CAP |
+ EMBED_FIND_CAP |
+ EMBED_SCROLL_CAP |
+ EMBED_FINE_SCROLL_CAP |
+ EMBED_SECURITY_CAP |
+ EMBED_CHARSET_CAP |
+ EMBED_SHISTORY_CAP );
+
+ *caps = mozilla_caps;
+}
+
+static gresult
+impl_load_url (EphyEmbed *embed,
+ const char *url)
+{
+ gtk_moz_embed_load_url (GTK_MOZ_EMBED(embed),
+ url);
+
+ return G_OK;
+}
+
+static gresult
+impl_stop_load (EphyEmbed *embed)
+{
+ gtk_moz_embed_stop_load (GTK_MOZ_EMBED(embed));
+
+ return G_OK;
+}
+
+static gresult
+impl_can_go_back (EphyEmbed *embed)
+{
+ if (gtk_moz_embed_can_go_back (GTK_MOZ_EMBED(embed)))
+ {
+ return G_OK;
+ }
+ else
+ {
+ return G_FAILED;
+ }
+}
+
+static gresult
+impl_can_go_forward (EphyEmbed *embed)
+{
+ if (gtk_moz_embed_can_go_forward (GTK_MOZ_EMBED(embed)))
+ {
+ return G_OK;
+ }
+ else
+ {
+ return G_FAILED;
+ }
+
+}
+
+static gresult
+impl_can_go_up (EphyEmbed *embed)
+{
+ char *location;
+ char *s;
+ gresult result;
+
+ if (ephy_embed_get_location (embed, TRUE, FALSE, &location) != G_OK)
+ return G_FAILED;
+ g_return_val_if_fail (location != NULL, G_FAILED);
+ if ((s = mozilla_embed_get_uri_parent (location)) != NULL)
+ {
+ g_free (s);
+ result = G_OK;
+ }
+ else
+ {
+ result = G_FAILED;
+ }
+
+ g_free (location);
+
+ return result;
+}
+
+static gresult
+impl_get_go_up_list (EphyEmbed *embed, GSList **l)
+{
+ char *location;
+ char *s;
+
+ if (ephy_embed_get_location (embed, TRUE, FALSE, &location) != G_OK)
+ return G_FAILED;
+ g_return_val_if_fail (location != NULL, G_FAILED);
+
+ *l = NULL;
+ s = location;
+ while ((s = mozilla_embed_get_uri_parent (s)) != NULL)
+ {
+ *l = g_slist_prepend (*l, s);
+ }
+
+ g_free (location);
+ *l = g_slist_reverse (*l);
+
+ return G_OK;
+}
+
+static gresult
+impl_go_back (EphyEmbed *embed)
+{
+ gtk_moz_embed_go_back (GTK_MOZ_EMBED(embed));
+
+ return G_OK;
+}
+
+static gresult
+impl_go_forward (EphyEmbed *embed)
+{
+ gtk_moz_embed_go_forward (GTK_MOZ_EMBED(embed));
+
+ return G_OK;
+}
+
+static gresult
+impl_go_up (EphyEmbed *embed)
+{
+ char *uri;
+ char *parent_uri;
+
+ ephy_embed_get_location (embed, TRUE, FALSE, &uri);
+ g_return_val_if_fail (uri != NULL, G_FAILED);
+
+ parent_uri = mozilla_embed_get_uri_parent (uri);
+ g_return_val_if_fail (parent_uri != NULL, G_FAILED);
+
+ ephy_embed_load_url (embed, parent_uri);
+
+ g_free (parent_uri);
+
+ return G_OK;
+}
+
+static char *
+mozilla_embed_get_uri_parent (const char *aUri)
+{
+ nsresult rv;
+
+ nsCOMPtr<nsIURI> uri;
+ rv = NS_NewURI (getter_AddRefs(uri), aUri);
+ if (NS_FAILED(rv) || !uri) return NULL;
+
+ nsCOMPtr<nsIURL> url = do_QueryInterface(uri, &rv);
+ if (NS_FAILED(rv) || !url) return NULL;
+
+ nsCAutoString dirPath;
+ rv = url->GetDirectory (dirPath);
+ if (NS_FAILED(rv) || !dirPath.Length()) return NULL;
+
+ nsCAutoString filePath;
+ rv = url->GetFilePath (filePath);
+ if (NS_FAILED(rv) || !filePath.Length()) return NULL;
+
+ PRInt32 pathLength = filePath.Length();
+ PRInt32 trailingSlash = filePath.RFind("/");
+
+ if(pathLength < 2 || trailingSlash == -1)
+ {
+ return NULL;
+ }
+
+ if(trailingSlash != (pathLength-1))
+ {
+ uri->SetPath(dirPath);
+ }
+ else
+ {
+ PRInt32 nextSlash = filePath.RFind("/",PR_FALSE,trailingSlash-1);
+ nsCAutoString parentPath;
+ filePath.Left(parentPath, nextSlash);
+ uri->SetPath(parentPath);
+ }
+
+ nsCAutoString spec;
+ uri->GetSpec(spec);
+
+ return !spec.IsEmpty() ? g_strdup(spec.get()) : NULL;
+}
+
+static gresult
+impl_render_data (EphyEmbed *embed,
+ const char *data,
+ guint32 len,
+ const char *base_uri,
+ const char *mime_type)
+{
+ gtk_moz_embed_render_data (GTK_MOZ_EMBED(embed),
+ data,
+ len,
+ base_uri,
+ mime_type);
+
+ return G_OK;
+}
+
+static gresult
+impl_open_stream (EphyEmbed *embed,
+ const char *base_uri,
+ const char *mime_type)
+{
+ gtk_moz_embed_open_stream (GTK_MOZ_EMBED(embed),
+ base_uri, mime_type);
+
+ return G_OK;
+}
+
+static gresult
+impl_append_data (EphyEmbed *embed,
+ const char *data,
+ guint32 len)
+{
+ gtk_moz_embed_append_data (GTK_MOZ_EMBED(embed),
+ data, len);
+
+ return G_OK;
+}
+
+static gresult
+impl_close_stream (EphyEmbed *embed)
+{
+ gtk_moz_embed_close_stream (GTK_MOZ_EMBED(embed));
+
+ return G_OK;
+}
+
+static gresult
+impl_get_title (EphyEmbed *embed,
+ char **title)
+{
+ nsXPIDLString uTitle;
+
+ *getter_Copies(uTitle) =
+ gtk_moz_embed_get_title_unichar (GTK_MOZ_EMBED(embed));
+
+ *title = g_strdup (NS_ConvertUCS2toUTF8(uTitle).get());
+
+ return G_OK;
+}
+
+static gresult
+impl_get_location (EphyEmbed *embed,
+ gboolean toplevel,
+ gboolean requested,
+ char **location)
+{
+ char *l;
+ nsresult rv;
+ nsCAutoString url;
+ EphyWrapper *wrapper;
+
+ wrapper = MOZILLA_EMBED(embed)->priv->wrapper;
+
+ /* if the wrapper is NULL than we have no location,
+ * in fact the wrapper is initialized on net start */
+ if (!wrapper)
+ {
+ *location = NULL;
+ return G_FAILED;
+ }
+
+ /* FIXME !toplevel requested not implemented */
+
+ if (toplevel)
+ {
+ l = gtk_moz_embed_get_location
+ (GTK_MOZ_EMBED(embed));
+ }
+ else if (!toplevel)
+ {
+ rv = wrapper->GetDocumentUrl (url);
+ l = (NS_SUCCEEDED (rv) && !url.IsEmpty()) ?
+ g_strdup (url.get()) : NULL;
+ }
+ else if (requested)
+ {
+ rv = wrapper->GetRealURL (url);
+ l = (NS_SUCCEEDED (rv) && !url.IsEmpty()) ?
+ g_strdup (url.get()) : NULL;
+ }
+
+ *location = l;
+
+ return G_OK;
+}
+
+static gresult
+impl_reload (EphyEmbed *embed,
+ EmbedReloadFlags flags)
+{
+ guint32 mflags;
+
+ mflags = GTK_MOZ_EMBED_FLAG_RELOADNORMAL;
+
+ if ((flags & EMBED_RELOAD_BYPASSCACHE) &&
+ (flags & EMBED_RELOAD_BYPASSPROXY))
+ {
+ mflags = GTK_MOZ_EMBED_FLAG_RELOADBYPASSPROXYANDCACHE;
+ }
+ else if (flags & EMBED_RELOAD_BYPASSCACHE)
+ {
+ mflags = GTK_MOZ_EMBED_FLAG_RELOADBYPASSCACHE;
+ }
+ else if (flags & EMBED_RELOAD_BYPASSPROXY)
+ {
+ mflags = GTK_MOZ_EMBED_FLAG_RELOADBYPASSPROXY;
+ }
+
+ gtk_moz_embed_reload (GTK_MOZ_EMBED(embed),
+ mflags);
+
+ return G_OK;
+}
+
+static gresult
+impl_copy_page (EphyEmbed *dest,
+ EphyEmbed *source,
+ EmbedDisplayType display_type)
+{
+ EphyWrapper *dWrapper;
+ dWrapper = MOZILLA_EMBED(dest)->priv->wrapper;
+ g_return_val_if_fail (dWrapper != NULL, G_FAILED);
+
+ EphyWrapper *sWrapper;
+ sWrapper = MOZILLA_EMBED(source)->priv->wrapper;
+ g_return_val_if_fail (sWrapper != NULL, G_FAILED);
+
+ nsresult rv;
+
+ nsCOMPtr<nsISupports> pageDescriptor;
+ rv = sWrapper->GetPageDescriptor(getter_AddRefs(pageDescriptor));
+ if (!pageDescriptor || NS_FAILED(rv)) return G_FAILED;
+
+ rv = dWrapper->LoadDocument(pageDescriptor, static_cast<PRUint32>(display_type));
+ if (NS_FAILED(rv)) return G_FAILED;
+
+ return G_OK;
+}
+
+static gresult
+impl_grab_focus (EphyEmbed *embed)
+{
+ gtk_widget_grab_focus (GTK_BIN (embed)->child);
+
+ return G_OK;
+}
+
+static gresult
+impl_get_link_tags (EphyEmbed *embed,
+ const char *link_type,
+ GList **tags)
+{
+ return G_NOT_IMPLEMENTED;
+}
+
+static gresult
+impl_zoom_set (EphyEmbed *embed,
+ int zoom,
+ gboolean reflow)
+{
+ EphyWrapper *wrapper;
+ nsresult result;
+
+ wrapper = MOZILLA_EMBED(embed)->priv->wrapper;
+ g_return_val_if_fail (wrapper != NULL, G_FAILED);
+
+ result = wrapper->SetZoom ((float)(zoom) / 100, reflow);
+
+ if (NS_SUCCEEDED (result))
+ {
+ g_signal_emit_by_name (embed, "ge_zoom_change", zoom);
+ }
+
+ return NS_SUCCEEDED(result) ? G_OK : G_FAILED;
+}
+
+static gresult
+impl_zoom_get (EphyEmbed *embed,
+ int *zoom)
+{
+ float f;
+ EphyWrapper *wrapper;
+
+ wrapper = MOZILLA_EMBED(embed)->priv->wrapper;
+ if (!wrapper)
+ {
+ *zoom = 100;
+ return G_OK;
+ }
+
+ nsresult result = wrapper->GetZoom (&f);
+
+ if (NS_SUCCEEDED (result))
+ {
+ *zoom = (int) rint (f * 100);
+
+ return G_OK;
+ }
+ else
+ {
+ return G_FAILED;
+ }
+}
+
+static gresult
+impl_selection_can_cut (EphyEmbed *embed)
+{
+ gboolean result;
+ EphyWrapper *wrapper;
+
+ wrapper = MOZILLA_EMBED(embed)->priv->wrapper;
+ g_return_val_if_fail (wrapper != NULL, G_FAILED);
+
+ wrapper->CanCutSelection (&result);
+
+ return result ? G_OK : G_FAILED;
+}
+
+static gresult
+impl_selection_can_copy (EphyEmbed *embed)
+{
+ gboolean result;
+ EphyWrapper *wrapper;
+
+ wrapper = MOZILLA_EMBED(embed)->priv->wrapper;
+ g_return_val_if_fail (wrapper != NULL, G_FAILED);
+
+ wrapper->CanCopySelection (&result);
+
+ return result ? G_OK : G_FAILED;
+}
+
+static gresult
+impl_can_paste (EphyEmbed *embed)
+{
+ gboolean result;
+ EphyWrapper *wrapper;
+
+ wrapper = MOZILLA_EMBED(embed)->priv->wrapper;
+ g_return_val_if_fail (wrapper != NULL, G_FAILED);
+
+ wrapper->CanPaste (&result);
+
+ return result ? G_OK : G_FAILED;
+}
+
+static gresult
+impl_select_all (EphyEmbed *embed)
+{
+ nsresult result;
+ EphyWrapper *wrapper;
+
+ wrapper = MOZILLA_EMBED(embed)->priv->wrapper;
+ g_return_val_if_fail (wrapper != NULL, G_FAILED);
+
+ result = wrapper->SelectAll ();
+
+ return result ? G_OK : G_FAILED;
+}
+
+static gresult
+impl_selection_cut (EphyEmbed *embed)
+{
+ nsresult rv;
+ EphyWrapper *wrapper;
+
+ wrapper = MOZILLA_EMBED(embed)->priv->wrapper;
+ g_return_val_if_fail (wrapper != NULL, G_FAILED);
+
+ rv = wrapper->CutSelection ();
+
+ return NS_SUCCEEDED(rv) ? G_OK : G_FAILED;
+}
+
+static gresult
+impl_selection_copy (EphyEmbed *embed)
+{
+ nsresult rv;
+ EphyWrapper *wrapper;
+
+ wrapper = MOZILLA_EMBED(embed)->priv->wrapper;
+ g_return_val_if_fail (wrapper != NULL, G_FAILED);
+
+ rv = wrapper->CopySelection ();
+
+ return NS_SUCCEEDED(rv) ? G_OK : G_FAILED;
+}
+
+static gresult
+impl_paste (EphyEmbed *embed)
+{
+ nsresult rv;
+ EphyWrapper *wrapper;
+
+ wrapper = MOZILLA_EMBED(embed)->priv->wrapper;
+ g_return_val_if_fail (wrapper != NULL, G_FAILED);
+
+ rv = wrapper->Paste ();
+
+ return NS_SUCCEEDED(rv) ? G_OK : G_FAILED;
+}
+
+static gresult
+impl_shistory_count (EphyEmbed *embed,
+ int *count)
+{
+ nsresult rv;
+ EphyWrapper *wrapper;
+ int c, index;
+
+ wrapper = MOZILLA_EMBED(embed)->priv->wrapper;
+ g_return_val_if_fail (wrapper != NULL, G_FAILED);
+
+ rv = wrapper->GetSHInfo (&c, &index);
+
+ *count = c;
+
+ return NS_SUCCEEDED(rv) ? G_OK : G_FAILED;
+}
+
+static gresult
+impl_shistory_get_nth (EphyEmbed *embed,
+ int nth,
+ gboolean is_relative,
+ char **aUrl,
+ char **aTitle)
+{
+ nsresult rv;
+ nsCAutoString url;
+ PRUnichar *title;
+ EphyWrapper *wrapper;
+
+ wrapper = MOZILLA_EMBED(embed)->priv->wrapper;
+ g_return_val_if_fail (wrapper != NULL, G_FAILED);
+
+ if (is_relative)
+ {
+ int pos;
+
+ if (ephy_embed_shistory_get_pos
+ (EPHY_EMBED(embed), &pos) == G_OK)
+ {
+ pos += nth;
+ }
+ else
+ {
+ return G_FAILED;
+ }
+ }
+
+ rv = wrapper->GetSHUrlAtIndex(nth, url);
+
+ *aUrl = (NS_SUCCEEDED (rv) && !url.IsEmpty()) ? g_strdup(url.get()) : NULL;
+
+ rv = wrapper->GetSHTitleAtIndex(nth, &title);
+
+ *aTitle = g_strdup (NS_ConvertUCS2toUTF8(title).get());
+
+ return G_OK;
+}
+
+static gresult
+impl_shistory_get_pos (EphyEmbed *embed,
+ int *pos)
+{
+ nsresult rv;
+ EphyWrapper *wrapper;
+ int count, index;
+
+ wrapper = MOZILLA_EMBED(embed)->priv->wrapper;
+ g_return_val_if_fail (wrapper != NULL, G_FAILED);
+
+ rv = wrapper->GetSHInfo (&count, &index);
+
+ *pos = index;
+
+ return NS_SUCCEEDED(rv) ? G_OK : G_FAILED;
+}
+
+static gresult
+impl_shistory_go_nth (EphyEmbed *embed,
+ int nth)
+{
+ nsresult rv;
+ EphyWrapper *wrapper;
+
+ wrapper = MOZILLA_EMBED(embed)->priv->wrapper;
+ g_return_val_if_fail (wrapper != NULL, G_FAILED);
+
+ rv = wrapper->GoToHistoryIndex (nth);
+
+ return NS_SUCCEEDED(rv) ? G_OK : G_FAILED;
+}
+
+static gboolean
+impl_shistory_copy (EphyEmbed *source,
+ EphyEmbed *dest)
+{
+ nsresult rv;
+ EphyWrapper *s_wrapper;
+ EphyWrapper *d_wrapper;
+
+ s_wrapper = MOZILLA_EMBED(source)->priv->wrapper;
+ g_return_val_if_fail (s_wrapper != NULL, G_FAILED);
+
+ d_wrapper = MOZILLA_EMBED(dest)->priv->wrapper;
+ g_return_val_if_fail (d_wrapper != NULL, G_FAILED);
+
+ rv = s_wrapper->CopyHistoryTo (d_wrapper);
+
+ return NS_SUCCEEDED(rv) ? G_OK : G_FAILED;
+}
+
+static gresult
+impl_scroll (EphyEmbed *embed,
+ EmbedScrollDirection direction)
+{
+ EphyWrapper *wrapper;
+
+ wrapper = MOZILLA_EMBED(embed)->priv->wrapper;
+ g_return_val_if_fail (wrapper != NULL, G_FAILED);
+
+ switch (direction)
+ {
+ case EMBED_SCROLL_UP:
+ wrapper->ScrollUp ();
+ break;
+ case EMBED_SCROLL_DOWN:
+ wrapper->ScrollDown ();
+ break;
+ case EMBED_SCROLL_LEFT:
+ wrapper->ScrollLeft ();
+ break;
+ case EMBED_SCROLL_RIGHT:
+ wrapper->ScrollRight ();
+ break;
+ }
+
+ return G_OK;
+}
+
+static gresult
+impl_fine_scroll (EphyEmbed *embed, int horiz, int vert)
+{
+ EphyWrapper *wrapper;
+
+ wrapper = MOZILLA_EMBED(embed)->priv->wrapper;
+ g_return_val_if_fail (wrapper != NULL, G_FAILED);
+
+ wrapper->FineScroll (horiz, vert);
+
+ return G_OK;
+}
+
+static gresult
+impl_get_security_level (EphyEmbed *embed,
+ EmbedSecurityLevel *level,
+ char **description)
+{
+ nsresult result;
+
+ nsCOMPtr<nsIChannel> channel;
+ channel = do_QueryInterface (MOZILLA_EMBED(embed)->priv->request,
+ &result);
+ if (NS_FAILED (result)) return G_FAILED;
+
+ nsCOMPtr<nsISupports> info;
+ result = channel->GetSecurityInfo(getter_AddRefs(info));
+ if (NS_FAILED (result)) return G_FAILED;
+
+ *description = NULL;
+ if (info)
+ {
+ nsCOMPtr<nsITransportSecurityInfo> secInfo(do_QueryInterface(info));
+ if (!secInfo) return G_FAILED;
+
+ nsXPIDLString tooltip;
+ result = secInfo->GetShortSecurityDescription(getter_Copies(tooltip));
+ if (NS_FAILED (result)) return G_FAILED;
+
+ if (tooltip)
+ {
+ const nsString &string = nsString(tooltip);
+ char *tmp;
+ tmp = ToNewCString (string);
+
+ *description = g_strdup (tmp);
+
+ nsMemory::Free (tmp);
+ }
+ }
+
+ *level = mozilla_embed_security_level (MOZILLA_EMBED (embed));
+ return G_OK;
+}
+
+static gresult
+impl_print (EphyEmbed *embed,
+ EmbedPrintInfo *info)
+{
+ nsresult result = NS_OK;
+ EphyWrapper *wrapper;
+
+ wrapper = MOZILLA_EMBED(embed)->priv->wrapper;
+ g_return_val_if_fail (wrapper != NULL, G_FAILED);
+
+ nsCOMPtr<nsIPrintSettings> options;
+ result = wrapper->GetPrintSettings(getter_AddRefs(options));
+ g_assert (NS_SUCCEEDED (result));
+
+ MozillaCollatePrintSettings(info, options);
+
+ options->SetPrintSilent (PR_TRUE);
+
+ result = wrapper->Print(options, info->preview);
+
+ return NS_SUCCEEDED (result) ? G_OK : G_FAILED;
+}
+
+static gresult
+impl_print_preview_close (EphyEmbed *embed)
+{
+ nsresult result = NS_OK;
+ EphyWrapper *wrapper;
+
+ wrapper = MOZILLA_EMBED(embed)->priv->wrapper;
+ g_return_val_if_fail (wrapper != NULL, G_FAILED);
+
+ result = wrapper->PrintPreviewClose();
+ return NS_SUCCEEDED(result) ? G_OK : G_FAILED;
+}
+
+static gresult
+impl_print_preview_num_pages (EphyEmbed *embed,
+ gint *retNum)
+{
+ nsresult result = NS_OK;
+ EphyWrapper *wrapper;
+
+ wrapper = MOZILLA_EMBED(embed)->priv->wrapper;
+ g_return_val_if_fail (wrapper != NULL, G_FAILED);
+
+ result = wrapper->PrintPreviewNumPages(retNum);
+ return NS_SUCCEEDED(result) ? G_OK : G_FAILED;
+}
+
+static gresult
+impl_print_preview_navigate (EphyEmbed *embed,
+ EmbedPrintPreviewNavType navType,
+ gint pageNum)
+{
+ nsresult result = NS_OK;
+ EphyWrapper *wrapper;
+
+ wrapper = MOZILLA_EMBED(embed)->priv->wrapper;
+ g_return_val_if_fail (wrapper != NULL, G_FAILED);
+
+ result = wrapper->PrintPreviewNavigate(navType, pageNum);
+ return NS_SUCCEEDED(result) ? G_OK : G_FAILED;
+}
+
+static gresult
+impl_find (EphyEmbed *embed,
+ EmbedFindInfo *info)
+{
+ nsresult result = NS_OK;
+ EphyWrapper *wrapper;
+
+ wrapper = MOZILLA_EMBED(embed)->priv->wrapper;
+ g_return_val_if_fail (wrapper != NULL, G_FAILED);
+
+ PRBool didFind;
+
+ result = wrapper->Find ((NS_ConvertUTF8toUCS2(info->search_string)).get(),
+ info->interactive,
+ info->match_case,
+ info->backwards, info->wrap,
+ info->entire_word, info->search_frames,
+ &didFind);
+
+ return didFind ? G_OK : G_FAILED;
+}
+
+static gresult
+impl_set_charset (EphyEmbed *embed,
+ const char *charset)
+{
+ nsresult result = NS_OK;
+ EphyWrapper *wrapper;
+ char *cset;
+
+ cset = g_strdup (charset);
+
+ wrapper = MOZILLA_EMBED(embed)->priv->wrapper;
+ g_return_val_if_fail (wrapper != NULL, G_FAILED);
+
+ wrapper->ForceCharacterSet (cset);
+
+ g_free (cset);
+
+ return NS_SUCCEEDED(result) ? G_OK : G_FAILED;
+}
+
+static void
+mozilla_embed_location_changed_cb (GtkMozEmbed *embed,
+ MozillaEmbed *membed)
+{
+ /* Do not emit signal if we are loading the
+ * fallback about:blank. We dont want the user
+ * to know about it. */
+ if (membed->priv->no_page != 0)
+ {
+ g_signal_emit_by_name (membed, "ge_location");
+ }
+
+ membed->priv->no_page = -1;
+}
+
+static void
+mozilla_embed_title_changed_cb (GtkMozEmbed *embed,
+ MozillaEmbed *membed)
+{
+ g_return_if_fail (IS_MOZILLA_EMBED (membed));
+ g_return_if_fail (GTK_IS_WIDGET (embed));
+ g_signal_emit_by_name (membed, "ge_title");
+}
+
+static void
+mozilla_embed_net_state_all_cb (GtkMozEmbed *embed, const char *aURI,
+ gint state, guint status,
+ MozillaEmbed *membed)
+{
+ EmbedState estate = EMBED_STATE_UNKNOWN;
+ int i;
+
+ struct
+ {
+ guint state;
+ EmbedState embed_state;
+ }
+ conversion_map [] =
+ {
+ { GTK_MOZ_EMBED_FLAG_START, EMBED_STATE_START },
+ { GTK_MOZ_EMBED_FLAG_STOP, EMBED_STATE_STOP },
+ { GTK_MOZ_EMBED_FLAG_REDIRECTING, EMBED_STATE_REDIRECTING },
+ { GTK_MOZ_EMBED_FLAG_TRANSFERRING, EMBED_STATE_TRANSFERRING },
+ { GTK_MOZ_EMBED_FLAG_NEGOTIATING, EMBED_STATE_NEGOTIATING },
+ { GTK_MOZ_EMBED_FLAG_IS_REQUEST, EMBED_STATE_IS_REQUEST },
+ { GTK_MOZ_EMBED_FLAG_IS_DOCUMENT, EMBED_STATE_IS_DOCUMENT },
+ { GTK_MOZ_EMBED_FLAG_IS_NETWORK, EMBED_STATE_IS_NETWORK },
+ { 0, EMBED_STATE_UNKNOWN }
+ };
+
+ /* No page loaded, default to about:blank */
+ if (membed->priv->no_page > 0 &&
+ (state & GTK_MOZ_EMBED_FLAG_STOP) &&
+ (state & GTK_MOZ_EMBED_FLAG_IS_DOCUMENT))
+ {
+ ephy_embed_load_url (EPHY_EMBED(membed), "about:blank");
+ membed->priv->no_page = 0;
+ }
+
+ if (!membed->priv->wrapper)
+ {
+ membed->priv->wrapper = new EphyWrapper ();
+
+ nsresult result;
+ result = membed->priv->wrapper->Init (GTK_MOZ_EMBED(embed));
+ if (NS_FAILED(result))
+ {
+ g_warning ("Wrapper initialization failed");
+ }
+ }
+
+ for (i = 0; conversion_map[i].state != 0; i++)
+ {
+ if (state & conversion_map[i].state)
+ {
+ estate = (EmbedState) (estate | conversion_map[i].embed_state);
+ }
+ }
+
+ g_signal_emit_by_name (membed, "ge_net_state", aURI, estate);
+}
+
+static void
+mozilla_embed_progress_cb (GtkMozEmbed *embed, const char *aURI,
+ gint curprogress, gint maxprogress,
+ MozillaEmbed *membed)
+{
+ g_signal_emit_by_name (membed, "ge_progress", aURI,
+ curprogress, maxprogress);
+}
+
+static void
+mozilla_embed_link_message_cb (GtkMozEmbed *embed,
+ MozillaEmbed *membed)
+{
+ nsXPIDLString message;
+
+ *getter_Copies(message) = gtk_moz_embed_get_link_message_unichar (embed);
+
+ g_signal_emit_by_name (membed, "ge_link_message",
+ g_strdup(NS_ConvertUCS2toUTF8(message).get()));
+}
+
+static void
+mozilla_embed_js_status_cb (GtkMozEmbed *embed,
+ MozillaEmbed *membed)
+{
+ nsXPIDLString status;
+
+ *getter_Copies(status) = gtk_moz_embed_get_js_status_unichar (embed);
+
+ g_signal_emit_by_name (membed, "ge_js_status",
+ g_strdup(NS_ConvertUCS2toUTF8(status).get()));
+}
+
+static void
+mozilla_embed_visibility_cb (GtkMozEmbed *embed, gboolean visibility,
+ MozillaEmbed *membed)
+{
+ g_signal_emit_by_name (membed, "ge_visibility", visibility);
+
+ nsresult rv;
+ nsCOMPtr<nsIWindowWatcher> wwatch
+ (do_GetService(WINDOWWATCHER_CONTRACTID, &rv));
+ if (NS_FAILED(rv) || !wwatch) return;
+
+ EphyWrapper *wrapper = (EphyWrapper *)mozilla_embed_get_galeon_wrapper(membed);
+ if(!wrapper) return;
+
+ nsCOMPtr<nsIDOMWindow> domWindow;
+ rv = wrapper->GetDOMWindow(getter_AddRefs(domWindow));
+ if(NS_FAILED(rv) || !domWindow) return;
+
+ rv = wwatch->SetActiveWindow(domWindow);
+}
+
+static void
+mozilla_embed_destroy_brsr_cb (GtkMozEmbed *embed,
+ MozillaEmbed *membed)
+{
+ g_signal_emit_by_name (membed, "ge_destroy_brsr");
+}
+
+static gint
+mozilla_embed_dom_mouse_click_cb (GtkMozEmbed *embed, gpointer dom_event,
+ MozillaEmbed *membed)
+{
+ EphyEmbedEvent *info;
+ EventContext event_context;
+ gint return_value = 0;
+ EphyWrapper *wrapper;
+ nsresult result;
+
+ info = ephy_embed_event_new ();
+
+ wrapper = MOZILLA_EMBED(membed)->priv->wrapper;
+ g_return_val_if_fail (wrapper != NULL, G_FAILED);
+
+ event_context.Init ((nsIDOMEvent*)dom_event, wrapper);
+ result = event_context.GetMouseEventInfo (info);
+
+ nsCOMPtr<nsIDOMDocument> domDoc;
+ result = event_context.GetTargetDocument (getter_AddRefs(domDoc));
+ if (NS_SUCCEEDED(result))
+ {
+ result = wrapper->PushTargetDocument (domDoc);
+ }
+
+ g_signal_emit_by_name (membed, "ge_dom_mouse_click", info, &return_value);
+
+ wrapper->PopTargetDocument ();
+
+ g_object_unref (info);
+
+ return return_value;
+}
+
+static gint
+mozilla_embed_dom_mouse_down_cb (GtkMozEmbed *embed, gpointer dom_event,
+ MozillaEmbed *membed)
+{
+ EphyEmbedEvent *info;
+ EventContext event_context;
+ gint return_value = 0;
+ EphyWrapper *wrapper;
+ nsresult result;
+
+ info = ephy_embed_event_new ();
+
+ wrapper = MOZILLA_EMBED(membed)->priv->wrapper;
+ g_return_val_if_fail (wrapper != NULL, G_FAILED);
+
+ event_context.Init ((nsIDOMEvent*)dom_event, wrapper);
+ result = event_context.GetMouseEventInfo (info);
+ if (NS_SUCCEEDED(result))
+ {
+ nsCOMPtr<nsIDOMDocument> domDoc;
+ result = event_context.GetTargetDocument (getter_AddRefs(domDoc));
+ if (NS_SUCCEEDED(result))
+ {
+ result = wrapper->PushTargetDocument (domDoc);
+ if (NS_SUCCEEDED(result))
+ {
+ g_signal_emit_by_name (membed, "ge_dom_mouse_down",
+ info, &return_value);
+ wrapper->PopTargetDocument ();
+ }
+ }
+
+ }
+
+ g_object_unref (info);
+
+ return return_value;
+}
+
+static void
+mozilla_embed_size_to_cb (GtkMozEmbed *embed, gint width, gint height,
+ MozillaEmbed *membed)
+{
+ g_signal_emit_by_name (membed, "ge_size_to", width, height);
+}
+
+static void
+mozilla_embed_new_window_cb (GtkMozEmbed *embed,
+ GtkMozEmbed **newEmbed,
+ guint chromemask,
+ MozillaEmbed *membed)
+{
+ int i;
+ EmbedChromeMask mask = EMBED_CHROME_OPENASPOPUP;
+ EphyEmbed *new_embed = NULL;
+
+ struct
+ {
+ guint chromemask;
+ EmbedChromeMask embed_mask;
+ }
+ conversion_map [] =
+ {
+ { GTK_MOZ_EMBED_FLAG_DEFAULTCHROME, EMBED_CHROME_DEFAULT },
+ { GTK_MOZ_EMBED_FLAG_MENUBARON, EMBED_CHROME_MENUBARON },
+ { GTK_MOZ_EMBED_FLAG_TOOLBARON, EMBED_CHROME_TOOLBARON },
+ { GTK_MOZ_EMBED_FLAG_PERSONALTOOLBARON, EMBED_CHROME_PERSONALTOOLBARON },
+ { GTK_MOZ_EMBED_FLAG_STATUSBARON, EMBED_CHROME_STATUSBARON },
+ { GTK_MOZ_EMBED_FLAG_WINDOWRAISED, EMBED_CHROME_WINDOWRAISED },
+ { GTK_MOZ_EMBED_FLAG_WINDOWLOWERED, EMBED_CHROME_WINDOWLOWERED },
+ { GTK_MOZ_EMBED_FLAG_CENTERSCREEN, EMBED_CHROME_CENTERSCREEN },
+ { GTK_MOZ_EMBED_FLAG_OPENASDIALOG, EMBED_CHROME_OPENASDIALOG },
+ { GTK_MOZ_EMBED_FLAG_OPENASCHROME, EMBED_CHROME_OPENASCHROME },
+ { 0, EMBED_CHROME_NONE }
+ };
+
+ for (i = 0; conversion_map[i].chromemask != 0; i++)
+ {
+ if (chromemask & conversion_map[i].chromemask)
+ {
+ mask = (EmbedChromeMask) (mask | conversion_map[i].embed_mask);
+ }
+ }
+
+ g_signal_emit_by_name (membed, "ge_new_window", &new_embed, mask);
+
+ g_assert (new_embed != NULL);
+
+ *newEmbed = GTK_MOZ_EMBED(new_embed);
+}
+
+static void
+mozilla_embed_security_change_cb (GtkMozEmbed *embed,
+ gpointer request,
+ guint state,
+ MozillaEmbed *membed)
+{
+ EmbedSecurityLevel level;
+
+ membed->priv->request = (nsIRequest *) request;
+ membed->priv->security_state = state;
+ level = mozilla_embed_security_level (membed);
+
+ g_signal_emit_by_name (membed, "ge_security_change", level);
+}
+
+static EmbedSecurityLevel
+mozilla_embed_security_level (MozillaEmbed *membed)
+{
+ EmbedSecurityLevel level;
+
+ switch (membed->priv->security_state)
+ {
+ case nsIWebProgressListener::STATE_IS_INSECURE:
+ level = STATE_IS_INSECURE;
+ break;
+ case nsIWebProgressListener::STATE_IS_BROKEN:
+ level = STATE_IS_BROKEN;
+ break;
+ case nsIWebProgressListener::STATE_IS_SECURE|
+ nsIWebProgressListener::STATE_SECURE_HIGH:
+ level = STATE_IS_SECURE_HIGH;
+ break;
+ case nsIWebProgressListener::STATE_IS_SECURE|
+ nsIWebProgressListener::STATE_SECURE_MED:
+ level = STATE_IS_SECURE_MED;
+ break;
+ case nsIWebProgressListener::STATE_IS_SECURE|
+ nsIWebProgressListener::STATE_SECURE_LOW:
+ level = STATE_IS_SECURE_LOW;
+ break;
+ default:
+ level = STATE_IS_UNKNOWN;
+ break;
+ }
+ return level;
+}
+
diff --git a/embed/mozilla/mozilla-embed.h b/embed/mozilla/mozilla-embed.h
new file mode 100644
index 000000000..b8ebca4c8
--- /dev/null
+++ b/embed/mozilla/mozilla-embed.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef MOZILLA_EMBED_H
+#define MOZILLA_EMBED_H
+
+#include "ephy-embed-types.h"
+#include "ephy-embed.h"
+
+#include <gtkmozembed.h>
+
+#include <glib-object.h>
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef struct MozillaEmbedClass MozillaEmbedClass;
+
+#define MOZILLA_EMBED_TYPE (mozilla_embed_get_type ())
+#define MOZILLA_EMBED(obj) (GTK_CHECK_CAST ((obj), MOZILLA_EMBED_TYPE, MozillaEmbed))
+#define MOZILLA_EMBED_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), MOZILLA_EMBED_TYPE, MozillaEmbedClass))
+#define IS_MOZILLA_EMBED(obj) (GTK_CHECK_TYPE ((obj), MOZILLA_EMBED_TYPE))
+#define IS_MOZILLA_EMBED_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), MOZILLA_EMBED))
+#define MOZILLA_EMBED_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MOZILLA_EMBED_TYPE, MozillaEmbedClass))
+
+typedef struct MozillaEmbed MozillaEmbed;
+typedef struct MozillaEmbedPrivate MozillaEmbedPrivate;
+
+struct MozillaEmbed
+{
+ GtkMozEmbed parent;
+ MozillaEmbedPrivate *priv;
+};
+
+struct MozillaEmbedClass
+{
+ GtkMozEmbedClass parent_class;
+};
+
+GType mozilla_embed_get_type (void);
+
+gpointer mozilla_embed_get_galeon_wrapper (MozillaEmbed *embed);
+
+G_END_DECLS
+
+#endif
diff --git a/embed/mozilla/mozilla-i18n.c b/embed/mozilla/mozilla-i18n.c
new file mode 100644
index 000000000..c974d9765
--- /dev/null
+++ b/embed/mozilla/mozilla-i18n.c
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2000 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "mozilla-i18n.h"
+
+#include <libgnome/gnome-i18n.h>
+
+const char *lgroups[] = {
+ N_("Arabic"),
+ N_("Baltic"),
+ N_("Central European"),
+ N_("Chinese"),
+ N_("Cyrillic"),
+ N_("Greek"),
+ N_("Hebrew"),
+ N_("Indian"),
+ N_("Japanese"),
+ N_("Korean"),
+ N_("Turkish"),
+ N_("Unicode"),
+ N_("Vietnamese"),
+ N_("Western"),
+ N_("Other"),
+ NULL
+};
+
+const CharsetInfoPriv charset_trans_array[] = {
+ {N_("Arabic (IBM-864)"), "IBM864", LG_ARABIC},
+ {N_("Arabic (IBM-864-I)"), "IBM864i", LG_ARABIC},
+ {N_("Arabic (ISO-8859-6)"), "ISO-8859-6", LG_ARABIC},
+ {N_("Arabic (ISO-8859-6-E)"), "ISO-8859-6-E", LG_ARABIC},
+ {N_("Arabic (ISO-8859-6-I)"), "ISO-8859-6-I", LG_ARABIC},
+ {N_("Arabic (MacArabic)"), "x-mac-arabic", LG_ARABIC},
+ {N_("Arabic (Windows-1256)"), "windows-1256", LG_ARABIC},
+ {N_("Armenian (ARMSCII-8)"), "armscii-8", LG_OTHER},
+ {N_("Baltic (ISO-8859-13)"), "ISO-8859-13", LG_BALTIC},
+ {N_("Baltic (ISO-8859-4)"), "ISO-8859-4", LG_BALTIC},
+ {N_("Baltic (Windows-1257)"), "windows-1257", LG_BALTIC},
+ {N_("Celtic (ISO-8859-14)"), "ISO-8859-14", LG_OTHER},
+ {N_("Central European (IBM-852)"), "IBM852", LG_CENTRAL_EUROPEAN},
+ {N_("Central European (ISO-8859-2)"), "ISO-8859-2", LG_CENTRAL_EUROPEAN},
+ {N_("Central European (MacCE)"), "x-mac-ce", LG_CENTRAL_EUROPEAN},
+ {N_("Central European (Windows-1250)"), "windows-1250", LG_CENTRAL_EUROPEAN},
+ {N_("Chinese Simplified (GB18030)"), "gb18030", LG_CHINESE},
+ {N_("Chinese Simplified (GB2312)"), "GB2312", LG_CHINESE},
+ {N_("Chinese Simplified (GBK)"), "x-gbk", LG_CHINESE},
+ {N_("Chinese Simplified (HZ)"), "HZ-GB-2312", LG_CHINESE},
+ {N_("Chinese Simplified (Windows-936)"), "windows-936", LG_CHINESE},
+ {N_("Chinese Traditional (Big5)"), "Big5", LG_CHINESE},
+ {N_("Chinese Traditional (Big5-HKSCS)"), "Big5-HKSCS", LG_CHINESE},
+ {N_("Chinese Traditional (EUC-TW)"), "x-euc-tw", LG_CHINESE},
+ {N_("Croatian (MacCroatian)"), "x-mac-croatian", LG_CENTRAL_EUROPEAN},
+ {N_("Cyrillic (IBM-855)"), "IBM855", LG_CYRILLIC},
+ {N_("Cyrillic (ISO-8859-5)"), "ISO-8859-5", LG_CYRILLIC},
+ {N_("Cyrillic (ISO-IR-111)"), "ISO-IR-111", LG_CYRILLIC},
+ {N_("Cyrillic (KOI8-R)"), "KOI8-R", LG_CYRILLIC},
+ {N_("Cyrillic (MacCyrillic)"), "x-mac-cyrillic", LG_CYRILLIC},
+ {N_("Cyrillic (Windows-1251)"), "windows-1251", LG_CYRILLIC},
+ {N_("Cyrillic/Russian (CP-866)"), "IBM866", LG_CYRILLIC},
+ {N_("Cyrillic/Ukrainian (KOI8-U)"), "KOI8-U", LG_CYRILLIC},
+ {N_("Cyrillic/Ukrainian (MacUkrainian)"), "x-mac-ukrainian", LG_CYRILLIC},
+ {N_("English (US-ASCII)"), "us-ascii", LG_WESTERN},
+ {N_("Farsi (MacFarsi)"), "x-mac-farsi", LG_OTHER},
+ {N_("Georgian (GEOSTD8)"), "geostd8", LG_OTHER},
+ {N_("Greek (ISO-8859-7)"), "ISO-8859-7", LG_GREEK},
+ {N_("Greek (MacGreek)"), "x-mac-greek", LG_GREEK},
+ {N_("Greek (Windows-1253)"), "windows-1253", LG_GREEK},
+ {N_("Gujarati (MacGujarati)"), "x-mac-gujarati", LG_INDIAN},
+ {N_("Gurmukhi (MacGurmukhi)"), "x-mac-gurmukhi", LG_INDIAN},
+ {N_("Hebrew (IBM-862)"), "IBM862", LG_HEBREW},
+ {N_("Hebrew (ISO-8859-8-E)"), "ISO-8859-8-E", LG_HEBREW},
+ {N_("Hebrew (ISO-8859-8-I)"), "ISO-8859-8-I", LG_HEBREW},
+ {N_("Hebrew (MacHebrew)"), "x-mac-hebrew", LG_HEBREW},
+ {N_("Hebrew (Windows-1255)"), "windows-1255", LG_HEBREW},
+ {N_("Hindi (MacDevanagari)"), "x-mac-devanagari", LG_INDIAN},
+ {N_("Icelandic (MacIcelandic)"), "x-mac-icelandic", LG_OTHER},
+ {N_("Japanese (EUC-JP)"), "EUC-JP", LG_JAPANESE},
+ {N_("Japanese (ISO-2022-JP)"), "ISO-2022-JP", LG_JAPANESE},
+ {N_("Japanese (Shift_JIS)"), "Shift_JIS", LG_JAPANESE},
+ {N_("Korean (EUC-KR)"), "EUC-KR", LG_KOREAN},
+ {N_("Korean (ISO-2022-KR)"), "ISO-2022-KR", LG_KOREAN},
+ {N_("Korean (JOHAB)"), "x-johab", LG_KOREAN},
+ {N_("Korean (UHC)"), "x-windows-949", LG_KOREAN},
+ {N_("Nordic (ISO-8859-10)"), "ISO-8859-10", LG_OTHER},
+ {N_("Romanian (MacRomanian)"), "x-mac-romanian", LG_OTHER},
+ {N_("Romanian (ISO-8859-16)"), "ISO-8859-16", LG_OTHER},
+ {N_("South European (ISO-8859-3)"), "ISO-8859-3", LG_OTHER},
+ {N_("Thai (TIS-620)"), "TIS-620", LG_OTHER},
+ {N_("Turkish (IBM-857)"), "IBM857", LG_TURKISH},
+ {N_("Turkish (ISO-8859-9)"), "ISO-8859-9", LG_TURKISH},
+ {N_("Turkish (MacTurkish)"), "x-mac-turkish", LG_TURKISH},
+ {N_("Turkish (Windows-1254)"), "windows-1254", LG_TURKISH},
+ {N_("Unicode (UTF-7)"), "UTF-7", LG_UNICODE},
+ {N_("Unicode (UTF-8)"), "UTF-8", LG_UNICODE},
+ {N_("Unicode (UTF-16BE)"), "UTF-16BE", LG_UNICODE},
+ {N_("Unicode (UTF-16LE)"), "UTF-16LE", LG_UNICODE},
+ {N_("Unicode (UTF-32BE)"), "UTF-32BE", LG_UNICODE},
+ {N_("Unicode (UTF-32LE)"), "UTF-32LE", LG_UNICODE},
+ {N_("User Defined"), "x-user-defined", LG_OTHER},
+ {N_("Vietnamese (TCVN)"), "x-viet-tcvn5712", LG_VIETNAMESE},
+ {N_("Vietnamese (VISCII)"), "VISCII", LG_VIETNAMESE},
+ {N_("Vietnamese (VPS)"), "x-viet-vps", LG_VIETNAMESE},
+ {N_("Vietnamese (Windows-1258)"), "windows-1258", LG_VIETNAMESE},
+ {N_("Visual Hebrew (ISO-8859-8)"), "ISO-8859-8", LG_HEBREW},
+ {N_("Western (IBM-850)"), "IBM850", LG_WESTERN},
+ {N_("Western (ISO-8859-1)"), "ISO-8859-1", LG_WESTERN},
+ {N_("Western (ISO-8859-15)"), "ISO-8859-15", LG_WESTERN},
+ {N_("Western (MacRoman)"), "x-mac-roman", LG_WESTERN},
+ {N_("Western (Windows-1252)"), "windows-1252", LG_WESTERN},
+ /* charsets whithout posibly translatable names */
+ {"T61.8bit", "T61.8bit", LG_OTHER},
+ {"x-imap4-modified-utf7", "x-imap4-modified-utf7", LG_UNICODE},
+ {"x-u-escaped", "x-u-escaped", LG_OTHER}
+};
+
+const gchar *lang_encode_item[LANG_ENC_NUM] =
+{
+ "x-western",
+ "x-central-euro",
+ "ja",
+ "zh-TW",
+ "zh-CN",
+ "ko",
+ "x-cyrillic",
+ "x-baltic",
+ "el",
+ "tr",
+ "x-unicode",
+ "th",
+ "he",
+ "ar"
+};
+
+const gchar *font_types[] =
+{
+ "serif",
+ "sans-serif",
+ "cursive",
+ "fantasy",
+ "monospace"
+};
+
+extern gint
+get_translated_cscount(void)
+{
+ return sizeof (charset_trans_array) / sizeof ((charset_trans_array)[0]);
+}
diff --git a/embed/mozilla/mozilla-i18n.h b/embed/mozilla/mozilla-i18n.h
new file mode 100644
index 000000000..5b5dbc321
--- /dev/null
+++ b/embed/mozilla/mozilla-i18n.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2000 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+#define LANG_ENC_NUM 14
+
+typedef enum {
+ LG_ARABIC,
+ LG_BALTIC,
+ LG_CENTRAL_EUROPEAN,
+ LG_CHINESE,
+ LG_CYRILLIC,
+ LG_GREEK,
+ LG_HEBREW,
+ LG_INDIAN,
+ LG_JAPANESE,
+ LG_KOREAN,
+ LG_TURKISH,
+ LG_UNICODE,
+ LG_VIETNAMESE,
+ LG_WESTERN,
+ LG_OTHER
+} LanguageGroup;
+
+typedef struct {
+ char *charset_title;
+ char *charset_name;
+ LanguageGroup lgroup;
+} CharsetInfoPriv;
+
+/* language groups names */
+extern const char *lgroups[];
+/* translated charset titles */
+extern const CharsetInfoPriv charset_trans_array[];
+
+/* FIXME */
+extern const char *lang_encode_name[LANG_ENC_NUM];
+extern const char *lang_encode_item[LANG_ENC_NUM];
+
+gint get_translated_cscount (void);
+
+G_END_DECLS
diff --git a/embed/mozilla/mozilla-notifiers.cpp b/embed/mozilla/mozilla-notifiers.cpp
new file mode 100644
index 000000000..24dfbb7a5
--- /dev/null
+++ b/embed/mozilla/mozilla-notifiers.cpp
@@ -0,0 +1,710 @@
+/*
+ * Copyright (C) 2000 Nate Case
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, OR (AT YOUR OPTION)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "ephy-embed-shell.h"
+#include "mozilla-notifiers.h"
+#include "eel-gconf-extensions.h"
+#include "mozilla-prefs.h"
+#include "MozRegisterComponents.h"
+#include "ephy-prefs.h"
+#include "ephy-embed-prefs.h"
+#include "mozilla-i18n.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <locale.h>
+#include <libgnome/gnome-i18n.h>
+#include <stdlib.h>
+#include <sys/utsname.h>
+#include "nsBuildID.h"
+
+static void
+mozilla_own_colors_notifier(GConfClient *client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ gpointer user_data);
+static void
+mozilla_own_fonts_notifier(GConfClient *client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ gpointer user_data);
+
+static void
+mozilla_animate_notifier(GConfClient *client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ gpointer user_data);
+static void
+generic_mozilla_string_notifier(GConfClient *client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ const char *pref_name);
+static void
+generic_mozilla_int_notifier(GConfClient *client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ const char *pref_name);
+static void
+generic_mozilla_bool_notifier(GConfClient *client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ const char *pref_name);
+static void
+mozilla_allow_popups_notifier(GConfClient *client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ gpointer user_data);
+
+static void
+mozilla_language_notifier(GConfClient *client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ gpointer user_data);
+
+static void
+mozilla_autodetect_charset_notifier(GConfClient *client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ EphyEmbedShell *shell);
+
+static void
+mozilla_default_font_notifier(GConfClient *client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ gpointer user_data);
+
+static void
+mozilla_proxy_mode_notifier (GConfClient *client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ char *pref);
+static void
+mozilla_proxy_autoconfig_notifier (GConfClient *client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ char *pref);
+
+static void
+mozilla_user_agent_notifier(GConfClient *client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ gpointer user_data);
+
+static void
+mozilla_default_charset_notifier (GConfClient *client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ EphyEmbedShell *shell);
+static void
+mozilla_socks_version_notifier (GConfClient *client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ gpointer user_data);
+
+/* Keeps the list of the notifiers we installed for mozilla prefs */
+/* to be able to remove them when exiting */
+GList *mozilla_notifiers = NULL;
+GList *font_infos = NULL;
+
+enum
+{
+ BOOL_PREF,
+ INT_PREF,
+ STRING_PREF
+};
+
+static const struct
+{
+ char *gconf_key;
+ guint pref_type;
+ const char *mozilla_key;
+}
+conversion_table [] =
+{
+ { CONF_FILTERING_JAVA_ENABLED, BOOL_PREF, "security.enable_java"},
+ { CONF_FILTERING_JAVASCRIPT_ENABLED, BOOL_PREF, "javascript.enabled"},
+ { CONF_FILTERING_IMAGE_LOADING_TYPE, INT_PREF, "network.image.imageBehavior"},
+ { CONF_RENDERING_BG_COLOR, STRING_PREF, "browser.display.background_color"},
+ { CONF_RENDERING_TEXT_COLOR, STRING_PREF, "browser.display.foreground_color"},
+ { CONF_RENDERING_UNVISITED_LINKS, STRING_PREF, "browser.anchor_color"},
+ { CONF_RENDERING_VISITED_LINKS, STRING_PREF, "browser.visited_color"},
+ { CONF_RENDERING_UNDERLINE_LINKS, BOOL_PREF, "browser.underline_anchors"},
+ { CONF_NETWORK_PROXY_AUTO_URL, STRING_PREF, "network.proxy.autoconfig_url"},
+ { CONF_NETWORK_HTTP_PROXY, STRING_PREF, "network.proxy.http"},
+ { CONF_NETWORK_FTP_PROXY, STRING_PREF, "network.proxy.ftp"},
+ { CONF_NETWORK_SSL_PROXY, STRING_PREF, "network.proxy.ssl"},
+ { CONF_NETWORK_SOCKS_PROXY, STRING_PREF, "network.proxy.socks"},
+ { CONF_NETWORK_HTTP_PROXY_PORT, INT_PREF, "network.proxy.http_port"},
+ { CONF_NETWORK_FTP_PROXY_PORT, INT_PREF, "network.proxy.ftp_port"},
+ { CONF_NETWORK_SSL_PROXY_PORT, INT_PREF, "network.proxy.ssl_port"},
+ { CONF_NETWORK_SOCKS_PROXY_PORT, INT_PREF, "network.proxy.socks_port"},
+ { CONF_NETWORK_NO_PROXIES_FOR, STRING_PREF, "network.proxy.no_proxies_on"},
+ { CONF_NETWORK_MEMORY_CACHE, INT_PREF, "browser.cache.memory.capacity"},
+ { CONF_NETWORK_DISK_CACHE, INT_PREF, "browser.cache.disk.capacity"},
+ { CONF_NETWORK_CACHE_COMPARE, INT_PREF, "browser.cache.check_doc_frequency"},
+ { CONF_PERSISTENT_COOKIE_WARN, BOOL_PREF, "network.cookie.warnAboutCookies"},
+ { CONF_PERSISTENT_COOKIES_BEHAVIOR, INT_PREF, "network.cookie.cookieBehavior"},
+ { CONF_PERSISTENT_COOKIE_LIFETIME, BOOL_PREF, "network.cookie.lifetime.enabled"},
+ { CONF_PERSISTENT_PASSWORDS_SAVE, BOOL_PREF, "signon.rememberSignons"},
+ { CONF_RENDERING_USE_SYSTEM_COLORS, BOOL_PREF, "browser.display.use_system_colors"},
+ { NULL, 0, NULL }
+};
+
+static const struct
+{
+ const char *gconf_key;
+ GConfClientNotifyFunc func;
+}
+custom_notifiers [] =
+{
+ { CONF_NETWORK_USER_AGENT,
+ (GConfClientNotifyFunc) mozilla_user_agent_notifier },
+ { CONF_FILTERING_ANIMATE_TYPE,
+ (GConfClientNotifyFunc) mozilla_animate_notifier },
+ { CONF_RENDERING_USE_OWN_COLORS,
+ (GConfClientNotifyFunc) mozilla_own_colors_notifier },
+ { CONF_RENDERING_USE_OWN_FONTS,
+ (GConfClientNotifyFunc) mozilla_own_fonts_notifier },
+ { CONF_FILTERING_ALLOW_POPUPS,
+ (GConfClientNotifyFunc) mozilla_allow_popups_notifier },
+ { CONF_LANGUAGE_DEFAULT_CHARSET,
+ (GConfClientNotifyFunc) mozilla_default_charset_notifier },
+ { CONF_RENDERING_LANGUAGE,
+ (GConfClientNotifyFunc) mozilla_language_notifier },
+ { CONF_LANGUAGE_AUTODETECT_CHARSET,
+ (GConfClientNotifyFunc) mozilla_autodetect_charset_notifier },
+ { CONF_RENDERING_DEFAULT_FONT,
+ (GConfClientNotifyFunc) mozilla_default_font_notifier },
+ { CONF_NETWORK_SOCKS_PROXY_VERSION,
+ (GConfClientNotifyFunc) mozilla_socks_version_notifier },
+ { CONF_NETWORK_PROXY_MODE,
+ (GConfClientNotifyFunc) mozilla_proxy_mode_notifier },
+ { CONF_NETWORK_PROXY_AUTO_URL,
+ (GConfClientNotifyFunc) mozilla_proxy_autoconfig_notifier },
+ {NULL, NULL}
+};
+
+static void
+mozilla_font_size_notifier (GConfClient *client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ char *pref)
+{
+ char key[255];
+
+ sprintf (key, "font.%s", pref);
+
+ mozilla_prefs_set_int (key, gconf_value_get_int(entry->value));
+}
+
+static void
+mozilla_proxy_mode_notifier (GConfClient *client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ char *pref)
+{
+ const char *mode;
+ int mozilla_mode = 0;
+
+ mode = gconf_value_get_string(entry->value);
+
+ if (strcmp (mode, "manual") == 0)
+ {
+ mozilla_mode = 1;
+ }
+ else if (strcmp (mode, "auto") == 0)
+ {
+ mozilla_mode = 2;
+ }
+
+ mozilla_prefs_set_int ("network.proxy.type", mozilla_mode);
+}
+
+static void
+mozilla_font_notifier (GConfClient *client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ char *pref)
+{
+ char key[255];
+
+ sprintf (key, "font.name.%s", pref);
+
+ mozilla_prefs_set_string (key, gconf_value_get_string(entry->value));
+}
+
+static void
+mozilla_proxy_autoconfig_notifier (GConfClient *client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ char *pref)
+{
+ ephy_embed_shell_load_proxy_autoconf
+ (embed_shell, gconf_value_get_string(entry->value));
+}
+
+void
+mozilla_notifiers_init(MozillaEmbedShell *shell)
+{
+ int i;
+
+ for (i = 0; conversion_table[i].gconf_key != NULL; i++)
+ {
+ GConfClientNotifyFunc func = NULL;
+
+ switch (conversion_table[i].pref_type)
+ {
+ case INT_PREF:
+ func = (GConfClientNotifyFunc) generic_mozilla_int_notifier;
+ break;
+ case BOOL_PREF:
+ func = (GConfClientNotifyFunc) generic_mozilla_bool_notifier;
+ break;
+ case STRING_PREF:
+ func = (GConfClientNotifyFunc) generic_mozilla_string_notifier;
+ break;
+ }
+
+ g_assert (func != NULL);
+
+ ephy_notification_add(
+ conversion_table[i].gconf_key,
+ func,
+ (gpointer)conversion_table[i].mozilla_key,
+ &mozilla_notifiers);
+ }
+
+ for (i = 0; custom_notifiers[i].gconf_key != NULL; i++)
+ {
+ ephy_notification_add(
+ custom_notifiers[i].gconf_key,
+ custom_notifiers[i].func,
+ (gpointer)shell,
+ &mozilla_notifiers);
+ }
+
+ /* fonts notifiers */
+ for (i = 0; i < LANG_ENC_NUM; i++)
+ {
+ int k;
+ char *types [] = { "serif", "sans-serif", "cursive", "fantasy", "monospace" };
+ char key[255];
+ char *info;
+
+ for (k = 0; k < 5; k++)
+ {
+ info = g_strconcat (types[k], ".", lang_encode_item[i], NULL);
+
+ sprintf (key, "%s_%s_%s", CONF_RENDERING_FONT,
+ types[k],
+ lang_encode_item[i]);
+ ephy_notification_add (key,
+ (GConfClientNotifyFunc)mozilla_font_notifier,
+ info,
+ &mozilla_notifiers);
+ font_infos = g_list_append (font_infos, info);
+ }
+
+ sprintf (key, "%s_%s", CONF_RENDERING_FONT_MIN_SIZE, lang_encode_item[i]);
+ info = g_strconcat ("minimum-size", ".", lang_encode_item[i], NULL);
+ ephy_notification_add (key,
+ (GConfClientNotifyFunc)mozilla_font_size_notifier,
+ info,
+ &mozilla_notifiers);
+ font_infos = g_list_append (font_infos, info);
+
+ sprintf (key, "%s_%s", CONF_RENDERING_FONT_FIXED_SIZE, lang_encode_item[i]);
+ info = g_strconcat ("size.fixed", ".", lang_encode_item[i], NULL);
+ ephy_notification_add (key,
+ (GConfClientNotifyFunc)mozilla_font_size_notifier,
+ info,
+ &mozilla_notifiers);
+ font_infos = g_list_append (font_infos, info);
+
+ sprintf (key, "%s_%s", CONF_RENDERING_FONT_VAR_SIZE, lang_encode_item[i]);
+ info = g_strconcat ("size.variable", ".", lang_encode_item[i], NULL);
+ ephy_notification_add (key,
+ (GConfClientNotifyFunc)mozilla_font_size_notifier,
+ info,
+ &mozilla_notifiers);
+ font_infos = g_list_append (font_infos, info);
+ }
+}
+
+void
+mozilla_notifiers_free (void)
+{
+ GList *l;
+
+ ephy_notification_remove (&mozilla_notifiers);
+
+ for (l = font_infos; l != NULL; l = l->next)
+ {
+ g_free (l->data);
+ }
+
+ g_list_free (font_infos);
+}
+
+void
+mozilla_notifiers_set_defaults(void)
+{
+ GConfClient* client = eel_gconf_client_get_global();
+ GConfValue* value;
+ int i;
+
+ for (i = 0; conversion_table[i].gconf_key != NULL; i++)
+ {
+ value = gconf_client_get
+ (client, conversion_table[i].gconf_key, NULL);
+ if (value)
+ {
+ gconf_client_set (client,
+ conversion_table[i].gconf_key,
+ value, NULL);
+ gconf_value_free (value);
+ }
+ }
+
+ for (i = 0; custom_notifiers[i].gconf_key != NULL; i++)
+ {
+ value = gconf_client_get
+ (client, custom_notifiers[i].gconf_key, NULL);
+ if (value)
+ {
+ gconf_client_set (client,
+ custom_notifiers[i].gconf_key,
+ value, NULL);
+ gconf_value_free (value);
+ }
+ }
+}
+
+/**
+ * generic_mozilla_string_notify: update mozilla pref to match epiphany prefs.
+ * user_data should match the mozilla key
+ */
+static void
+generic_mozilla_string_notifier(GConfClient *client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ const char *pref_name)
+{
+ const gchar *value;
+
+ /* determine type of gconf key, in order of likelyhood */
+ switch (entry->value->type)
+ {
+ case GCONF_VALUE_STRING:
+ value = gconf_value_get_string(entry->value);
+ if (value)
+ {
+ mozilla_prefs_set_string
+ (pref_name,
+ gconf_value_get_string(entry->value));
+ }
+ break;
+
+ default:
+ g_warning("Unsupported variable type");
+ }
+}
+
+
+/**
+ * generic_mozilla_int_notify: update mozilla pref to match epiphany prefs.
+ * user_data should match the mozilla key
+ */
+static void
+generic_mozilla_int_notifier(GConfClient *client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ const char *pref_name)
+{
+ /* determine type of gconf key, in order of likelyhood */
+ switch (entry->value->type)
+ {
+ case GCONF_VALUE_INT: mozilla_prefs_set_int(pref_name,
+ gconf_value_get_int(entry->value));
+ break;
+ case GCONF_VALUE_BOOL: mozilla_prefs_set_boolean(pref_name,
+ gconf_value_get_bool(entry->value));
+ break;
+ case GCONF_VALUE_STRING: mozilla_prefs_set_string(pref_name,
+ gconf_value_get_string(entry->value));
+ break;
+ default: g_warning("Unsupported variable type");
+ }
+}
+
+
+/**
+ * generic_mozilla_bool_notify: update mozilla pref to match epiphany prefs.
+ * user_data should match the mozilla key
+ */
+static void
+generic_mozilla_bool_notifier(GConfClient *client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ const char *pref_name)
+{
+ /* determine type of gconf key, in order of likelyhood */
+ switch (entry->value->type)
+ {
+ case GCONF_VALUE_BOOL: mozilla_prefs_set_boolean(pref_name,
+ gconf_value_get_bool(entry->value));
+ break;
+ case GCONF_VALUE_INT: mozilla_prefs_set_int(pref_name,
+ gconf_value_get_int(entry->value));
+ break;
+ default: g_warning("Unsupported variable type");
+ }
+}
+
+static void
+mozilla_default_charset_notifier(GConfClient *client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ EphyEmbedShell *shell)
+{
+ /* FIXME */
+}
+
+
+static void
+mozilla_own_colors_notifier(GConfClient *client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ gpointer user_data)
+{
+ mozilla_prefs_set_boolean("browser.display.use_document_colors",
+ !gconf_value_get_bool(entry->value));
+}
+
+static void
+mozilla_own_fonts_notifier(GConfClient *client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ gpointer user_data)
+{
+ mozilla_prefs_set_int("browser.display.use_document_fonts",
+ !gconf_value_get_bool(entry->value));
+}
+
+static void
+mozilla_animate_notifier(GConfClient *client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ gpointer user_data)
+{
+ static const gchar *type[] =
+ {
+ "normal",
+ "once",
+ "none"
+ };
+
+ mozilla_prefs_set_string ("image.animation_mode",
+ type[gconf_value_get_int(entry->value)]);
+}
+
+static void
+mozilla_allow_popups_notifier(GConfClient *client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ gpointer user_data)
+{
+ gboolean new_val = eel_gconf_get_boolean(CONF_FILTERING_ALLOW_POPUPS);
+ mozilla_prefs_set_boolean ("dom.disable_open_during_load",
+ !new_val);
+}
+
+static void
+mozilla_language_notifier(GConfClient *client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ gpointer user_data)
+{
+ gchar *languages;
+ GSList *language_list ,*cur_lang_list;
+
+ language_list = eel_gconf_get_string_list (CONF_RENDERING_LANGUAGE);
+
+ languages = NULL;
+ cur_lang_list = language_list;
+ while (cur_lang_list != NULL) {
+ char *lang, *tmp;
+
+ lang = g_strdup((char *)cur_lang_list->data);
+
+ if (languages == NULL)
+ languages = lang;
+ else {
+ tmp = languages;
+ languages = g_strconcat(languages, ",", lang, NULL);
+ g_free(lang);
+ g_free(tmp);
+ }
+ g_free(cur_lang_list->data);
+ cur_lang_list = cur_lang_list->next;
+ }
+
+ if (languages == NULL)
+ {
+ languages = g_strdup ("");
+ }
+
+ mozilla_prefs_set_string ("intl.accept_languages", languages);
+ g_free (languages);
+
+ g_slist_free(language_list);
+}
+
+static char *autodetect_charset_prefs[] =
+{
+ "",
+ "zh_parallel_state_machine",
+ "cjk_parallel_state_machine",
+ "ja_parallel_state_machine",
+ "ko_parallel_state_machine",
+ "ruprob",
+ "zhcn_parallel_state_machine",
+ "zhtw_parallel_state_machine",
+ "ukprob"
+};
+
+static void
+mozilla_autodetect_charset_notifier(GConfClient *client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ EphyEmbedShell *shell)
+{
+ int charset = eel_gconf_get_integer (CONF_LANGUAGE_AUTODETECT_CHARSET);
+ if (charset < 0 ||
+ charset >= (int)(sizeof(autodetect_charset_prefs)
+ / sizeof(autodetect_charset_prefs[0])))
+ {
+ g_warning ("mozilla_autodetect_charset_notifier: "
+ "unsupported value: %d", charset);
+ return;
+ }
+ mozilla_prefs_set_string ("intl.charset.detector",
+ autodetect_charset_prefs[charset]);
+}
+
+static void
+mozilla_default_font_notifier(GConfClient *client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ gpointer user_data)
+{
+ const gchar *font_types [] = {"serif","sans-serif"};
+ int default_font;
+
+ default_font = eel_gconf_get_integer (CONF_RENDERING_DEFAULT_FONT);
+ if (default_font < 0 ||
+ default_font >= (int)(sizeof(font_types) / sizeof(font_types[0])))
+ {
+ g_warning ("mozilla_default_font_notifier: "
+ "unsupported value: %d", default_font);
+ return;
+ }
+ mozilla_prefs_set_string ("font.default", font_types[default_font]);
+}
+
+static void
+mozilla_prefs_set_user_agent ()
+{
+ static gchar *default_user_agent = NULL;
+ gchar *value;
+ gchar *user_agent = NULL;
+ struct utsname name;
+ gchar *system;
+
+ if (!default_user_agent)
+ {
+ if (uname (&name) == 0)
+ {
+ system = g_strdup_printf ("%s %s",
+ name.sysname,
+ name.machine);
+ }
+ else
+ {
+ system = g_strdup ("Unknown");
+ }
+
+ default_user_agent = g_strdup_printf
+ ("Mozilla/5.0 Ephy/" VERSION " (X11; %s; U;) Gecko/%d",
+ system,
+ NS_BUILD_ID/100);
+
+ g_free (system);
+ }
+
+ value = eel_gconf_get_string (CONF_NETWORK_USER_AGENT);
+
+ /* now, build a valid user agent string */
+ if (!value || !strcmp ("", value)
+ || !strcmp ("default", value)
+ || !strcmp ("Ephy", value)
+ || !strcmp (_("Default (recommended)"), value)
+ || !strcmp ("Default (recommended)", value))
+ {
+ user_agent = g_strdup (default_user_agent);
+ }
+ else
+ {
+ user_agent = g_strdup (value);
+ }
+
+ mozilla_prefs_set_string ("general.useragent.override", user_agent);
+ g_free (user_agent);
+}
+
+static void
+mozilla_user_agent_notifier (GConfClient *client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ gpointer user_data)
+{
+ switch (entry->value->type)
+ {
+ case GCONF_VALUE_STRING:
+ mozilla_prefs_set_user_agent ();
+ break;
+
+ default:
+ g_warning ("Unsupported variable type");
+ break;
+ }
+}
+
+static void
+mozilla_socks_version_notifier (GConfClient *client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ gpointer user_data)
+{
+ int version;
+ version = gconf_value_get_int(entry->value) + 4;
+ mozilla_prefs_set_int ("network.proxy.socks_version",
+ version);
+}
diff --git a/embed/mozilla/mozilla-notifiers.h b/embed/mozilla/mozilla-notifiers.h
new file mode 100644
index 000000000..6718365f7
--- /dev/null
+++ b/embed/mozilla/mozilla-notifiers.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2000 Nate Case
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef MOZILLA_NOTIFIERS_H
+#define MOZILLA_NOTIFIERS_H
+
+#include "mozilla-embed-shell.h"
+
+void mozilla_notifiers_init (MozillaEmbedShell *shell);
+
+void mozilla_notifiers_set_defaults (void);
+
+void mozilla_notifiers_free (void);
+
+#endif
diff --git a/embed/mozilla/mozilla-prefs.cpp b/embed/mozilla/mozilla-prefs.cpp
new file mode 100644
index 000000000..e5b8c68e2
--- /dev/null
+++ b/embed/mozilla/mozilla-prefs.cpp
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2000-2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "mozilla-prefs.h"
+
+#include <nsCOMPtr.h>
+#include <nsIPrefService.h>
+#include <nsIServiceManager.h>
+#include <nsMemory.h>
+#include <glib/gmessages.h>
+#include <glib/gstrfuncs.h>
+
+gboolean
+mozilla_prefs_save (void)
+{
+ nsCOMPtr<nsIPrefService> prefService =
+ do_GetService (NS_PREFSERVICE_CONTRACTID);
+ g_return_val_if_fail (prefService != nsnull, FALSE);
+
+ nsresult rv = prefService->SavePrefFile (nsnull);
+ return NS_SUCCEEDED (rv) ? TRUE : FALSE;
+}
+
+gboolean
+mozilla_prefs_set_string(const char *preference_name, const char *new_value)
+{
+ g_return_val_if_fail (preference_name != NULL, FALSE);
+ g_return_val_if_fail (new_value != NULL, FALSE);
+ nsCOMPtr<nsIPrefService> prefService =
+ do_GetService (NS_PREFSERVICE_CONTRACTID);
+ nsCOMPtr<nsIPrefBranch> pref;
+ prefService->GetBranch ("", getter_AddRefs(pref));
+
+ if (pref)
+ {
+ nsresult rv = pref->SetCharPref (preference_name, new_value);
+ return NS_SUCCEEDED (rv) ? TRUE : FALSE;
+ }
+
+ return FALSE;
+}
+
+gboolean
+mozilla_prefs_set_boolean (const char *preference_name,
+ gboolean new_boolean_value)
+{
+ g_return_val_if_fail (preference_name != NULL, FALSE);
+
+ nsCOMPtr<nsIPrefService> prefService =
+ do_GetService (NS_PREFSERVICE_CONTRACTID);
+ nsCOMPtr<nsIPrefBranch> pref;
+ prefService->GetBranch ("", getter_AddRefs(pref));
+
+ if (pref)
+ {
+ nsresult rv = pref->SetBoolPref (preference_name,
+ new_boolean_value ? PR_TRUE : PR_FALSE);
+ return NS_SUCCEEDED (rv) ? TRUE : FALSE;
+ }
+ return FALSE;
+}
+
+gboolean
+mozilla_prefs_set_int (const char *preference_name, int new_int_value)
+{
+ g_return_val_if_fail (preference_name != NULL, FALSE);
+
+ nsCOMPtr<nsIPrefService> prefService =
+ do_GetService (NS_PREFSERVICE_CONTRACTID);
+ nsCOMPtr<nsIPrefBranch> pref;
+ prefService->GetBranch ("", getter_AddRefs(pref));
+
+ if (pref)
+ {
+ nsresult rv = pref->SetIntPref (preference_name, new_int_value);
+ return NS_SUCCEEDED (rv) ? TRUE : FALSE;
+ }
+
+ return FALSE;
+}
+
+gboolean
+mozilla_prefs_get_boolean (const char *preference_name,
+ gboolean default_value)
+{
+ PRBool value;
+
+ g_return_val_if_fail (preference_name != NULL, FALSE);
+
+ nsCOMPtr<nsIPrefService> prefService =
+ do_GetService (NS_PREFSERVICE_CONTRACTID);
+ nsCOMPtr<nsIPrefBranch> pref;
+ prefService->GetBranch ("", getter_AddRefs(pref));
+
+ if (pref)
+ {
+ nsresult result;
+
+ result = pref->GetBoolPref (preference_name, &value);
+ if (NS_FAILED (result)) return default_value;
+ }
+
+ return (value == PR_TRUE) ? TRUE : FALSE;
+}
+
+gint
+mozilla_prefs_get_int (const char *preference_name)
+{
+ int value = -1;
+
+ g_return_val_if_fail (preference_name != NULL, FALSE);
+
+ nsCOMPtr<nsIPrefService> prefService =
+ do_GetService (NS_PREFSERVICE_CONTRACTID);
+ nsCOMPtr<nsIPrefBranch> pref;
+ prefService->GetBranch ("", getter_AddRefs(pref));
+
+ if (pref)
+ {
+ pref->GetIntPref (preference_name, &value);
+ }
+
+ return value;
+}
+
+gchar *
+mozilla_prefs_get_string(const char *preference_name)
+{
+ gchar *value = NULL;
+ gchar *result = NULL;
+
+ g_return_val_if_fail (preference_name != NULL, FALSE);
+ nsCOMPtr<nsIPrefService> prefService =
+ do_GetService (NS_PREFSERVICE_CONTRACTID);
+ nsCOMPtr<nsIPrefBranch> pref;
+ prefService->GetBranch ("", getter_AddRefs(pref));
+
+ if (pref)
+ {
+ pref->GetCharPref (preference_name, &value);
+ }
+
+ /* it's allocated by mozilla, so I could not g_free it */
+ if (value)
+ {
+ result = g_strdup (value);
+ nsMemory::Free (value);
+ }
+
+ return result;
+}
+
+gboolean
+mozilla_prefs_remove (const char *preference_name)
+{
+ g_return_val_if_fail (preference_name != NULL, FALSE);
+
+ nsCOMPtr<nsIPrefService> prefService =
+ do_GetService (NS_PREFSERVICE_CONTRACTID);
+ nsCOMPtr<nsIPrefBranch> pref;
+ prefService->GetBranch ("", getter_AddRefs(pref));
+
+ if (pref)
+ {
+ nsresult rv = pref->ClearUserPref (preference_name);
+ return NS_SUCCEEDED (rv) ? TRUE : FALSE;
+ }
+
+ return FALSE;
+}
diff --git a/embed/mozilla/mozilla-prefs.h b/embed/mozilla/mozilla-prefs.h
new file mode 100644
index 000000000..82055c4a7
--- /dev/null
+++ b/embed/mozilla/mozilla-prefs.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2000-2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef MOZILLA_PREFS_H
+#define MOZILLA_PREFS_H
+
+#include "glib/gtypes.h"
+
+gboolean mozilla_prefs_save (void);
+
+gboolean mozilla_prefs_set_string (const char *preference_name,
+ const char *new_value);
+
+gboolean mozilla_prefs_set_boolean (const char *preference_name,
+ gboolean new_boolean_value);
+
+gboolean mozilla_prefs_set_int (const char *preference_name,
+ int new_int_value);
+
+gboolean mozilla_prefs_get_boolean (const char *preference_name,
+ gboolean default_value);
+
+int mozilla_prefs_get_int (const char *preference_name);
+
+gchar *mozilla_prefs_get_string (const char *preference_name);
+
+gboolean mozilla_prefs_remove (const char *preference_name);
+
+#endif
diff --git a/embed/mozilla/nsUnicharUtils.cpp b/embed/mozilla/nsUnicharUtils.cpp
new file mode 100644
index 000000000..d70619303
--- /dev/null
+++ b/embed/mozilla/nsUnicharUtils.cpp
@@ -0,0 +1,344 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Unicode case conversion helpers.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corp..
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Alec Flett <alecf@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsString.h"
+#include "nsUnicharUtils.h"
+#include "nsReadableUtils.h"
+#include "nsUnicharUtilCIID.h"
+#include "nsICaseConversion.h"
+#include "nsIServiceManager.h"
+#include "nsCRT.h"
+
+#include "nsIObserver.h"
+#include "nsIObserverService.h"
+
+// global cache of the case conversion service
+static nsICaseConversion *gCaseConv = nsnull;
+
+class nsShutdownObserver : public nsIObserver
+{
+public:
+ nsShutdownObserver() { NS_INIT_ISUPPORTS(); }
+ virtual ~nsShutdownObserver() {}
+ NS_DECL_ISUPPORTS
+
+ NS_IMETHOD Observe(nsISupports *aSubject, const char *aTopic,
+ const PRUnichar *aData)
+ {
+ if (nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)==0) {
+ NS_IF_RELEASE(gCaseConv);
+ }
+
+ return NS_OK;
+ }
+
+};
+
+NS_IMPL_ISUPPORTS1(nsShutdownObserver, nsIObserver)
+
+static nsresult NS_InitCaseConversion() {
+ if (gCaseConv) return NS_OK;
+
+ nsresult rv;
+
+ rv = CallGetService(NS_UNICHARUTIL_CONTRACTID, &gCaseConv);
+
+ if (NS_SUCCEEDED(rv)) {
+ nsCOMPtr<nsIObserverService> obs =
+ do_GetService("@mozilla.org/observer-service;1", &rv);
+ if (NS_SUCCEEDED(rv)) {
+ nsShutdownObserver *observer = new nsShutdownObserver();
+ if (observer)
+ obs->AddObserver(observer, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_FALSE);
+ }
+ }
+
+ return NS_OK;
+}
+
+class ConvertToLowerCase
+{
+public:
+ typedef PRUnichar value_type;
+
+ ConvertToLowerCase()
+ {
+ NS_InitCaseConversion();
+ }
+
+ PRUint32 write( const PRUnichar* aSource, PRUint32 aSourceLength)
+ {
+ if (gCaseConv)
+ gCaseConv->ToLower(aSource, NS_CONST_CAST(PRUnichar*,aSource), aSourceLength);
+ else
+ NS_WARNING("No case converter: no conversion done");
+
+ return aSourceLength;
+ }
+};
+
+void
+ToLowerCase( nsAString& aString )
+ {
+ nsAString::iterator fromBegin, fromEnd;
+ ConvertToLowerCase converter;
+ copy_string(aString.BeginWriting(fromBegin), aString.EndWriting(fromEnd), converter);
+ }
+
+void
+ToLowerCase( nsASingleFragmentString& aString )
+ {
+ ConvertToLowerCase converter;
+ PRUnichar* start;
+ converter.write(aString.BeginWriting(start), aString.Length());
+ }
+
+void
+ToLowerCase( nsString& aString )
+ {
+ ConvertToLowerCase converter;
+ converter.write(aString.mUStr, aString.mLength);
+ }
+
+class CopyToLowerCase
+ {
+ public:
+ typedef PRUnichar value_type;
+
+ CopyToLowerCase( nsAString::iterator& aDestIter )
+ : mIter(aDestIter)
+ {
+ NS_InitCaseConversion();
+ }
+
+ PRUint32 write( const PRUnichar* aSource, PRUint32 aSourceLength )
+ {
+ PRUint32 len = PR_MIN(PRUint32(mIter.size_forward()), aSourceLength);
+ PRUnichar* dest = NS_CONST_CAST(PRUnichar*, mIter.get());
+ if (gCaseConv)
+ gCaseConv->ToLower(aSource, dest, len);
+ else {
+ NS_WARNING("No case converter: only copying");
+ memcpy((void*)aSource, (void*)dest, len * sizeof(*aSource));
+ }
+ mIter.advance(len);
+ return len;
+ }
+
+ protected:
+ nsAString::iterator& mIter;
+ };
+
+void
+ToLowerCase( const nsAString& aSource, nsAString& aDest )
+ {
+ nsAString::const_iterator fromBegin, fromEnd;
+ nsAString::iterator toBegin;
+ aDest.SetLength(aSource.Length());
+ CopyToLowerCase converter(aDest.BeginWriting(toBegin));
+ copy_string(aSource.BeginReading(fromBegin), aSource.EndReading(fromEnd), converter);
+ }
+
+class ConvertToUpperCase
+{
+public:
+ typedef PRUnichar value_type;
+
+ ConvertToUpperCase()
+ {
+ NS_InitCaseConversion();
+ }
+
+ PRUint32 write( const PRUnichar* aSource, PRUint32 aSourceLength)
+ {
+ if (gCaseConv)
+ gCaseConv->ToUpper(aSource, NS_CONST_CAST(PRUnichar*,aSource), aSourceLength);
+ else
+ NS_WARNING("No case converter: no conversion done");
+
+ return aSourceLength;
+ }
+};
+
+void
+ToUpperCase( nsAString& aString )
+ {
+ nsAString::iterator fromBegin, fromEnd;
+ ConvertToUpperCase converter;
+ copy_string(aString.BeginWriting(fromBegin), aString.EndWriting(fromEnd), converter);
+ }
+
+void
+ToUpperCase( nsASingleFragmentString& aString )
+ {
+ ConvertToUpperCase converter;
+ PRUnichar* start;
+ converter.write(aString.BeginWriting(start), aString.Length());
+ }
+
+void
+ToUpperCase( nsString& aString )
+ {
+ ConvertToUpperCase converter;
+ converter.write(aString.mUStr, aString.mLength);
+ }
+
+class CopyToUpperCase
+ {
+ public:
+ typedef PRUnichar value_type;
+
+ CopyToUpperCase( nsAString::iterator& aDestIter )
+ : mIter(aDestIter)
+ {
+ NS_InitCaseConversion();
+ }
+
+ PRUint32 write( const PRUnichar* aSource, PRUint32 aSourceLength )
+ {
+ PRUint32 len = PR_MIN(PRUint32(mIter.size_forward()), aSourceLength);
+ PRUnichar* dest = NS_CONST_CAST(PRUnichar*, mIter.get());
+ if (gCaseConv)
+ gCaseConv->ToUpper(aSource, dest, len);
+ else {
+ NS_WARNING("No case converter: only copying");
+ memcpy((void*)aSource, (void*)dest, len * sizeof(*aSource));
+ }
+ mIter.advance(len);
+ return len;
+ }
+
+ protected:
+ nsAString::iterator& mIter;
+ };
+
+void
+ToUpperCase( const nsAString& aSource, nsAString& aDest )
+ {
+ nsAString::const_iterator fromBegin, fromEnd;
+ nsAString::iterator toBegin;
+ aDest.SetLength(aSource.Length());
+ CopyToUpperCase converter(aDest.BeginWriting(toBegin));
+ copy_string(aSource.BeginReading(fromBegin), aSource.EndReading(fromEnd), converter);
+ }
+
+PRBool
+CaseInsensitiveFindInReadable( const nsAString& aPattern, nsAString::const_iterator& aSearchStart, nsAString::const_iterator& aSearchEnd )
+{
+ return FindInReadable(aPattern, aSearchStart, aSearchEnd, nsCaseInsensitiveStringComparator());
+}
+
+
+int
+nsCaseInsensitiveStringComparator::operator()( const PRUnichar* lhs, const PRUnichar* rhs, PRUint32 aLength ) const
+ {
+ NS_InitCaseConversion();
+ PRInt32 result;
+ if (gCaseConv) {
+ gCaseConv->CaseInsensitiveCompare(lhs, rhs, aLength, &result);
+ }
+ else {
+ NS_WARNING("No case converter: using default");
+ nsDefaultStringComparator comparator;
+ result = comparator(lhs, rhs, aLength);
+ }
+ return result;
+ }
+
+int
+nsCaseInsensitiveStringComparator::operator()( PRUnichar lhs, PRUnichar rhs ) const
+ {
+ // see if they're an exact match first
+ if (lhs == rhs) return 0;
+
+ NS_InitCaseConversion();
+
+ if (gCaseConv) {
+ gCaseConv->ToLower(lhs, &lhs);
+ gCaseConv->ToLower(rhs, &rhs);
+ } else {
+ if (lhs < 256)
+ lhs = tolower(char(lhs));
+ if (rhs < 256)
+ rhs = tolower(char(rhs));
+ NS_WARNING("No case converter: no conversion done");
+ }
+
+ if (lhs == rhs) return 0;
+ if (lhs < rhs) return -1;
+ return 1;
+ }
+
+PRUnichar
+ToLowerCase(PRUnichar aChar)
+{
+ PRUnichar result;
+ if (NS_FAILED(NS_InitCaseConversion()))
+ return aChar;
+
+ if (gCaseConv)
+ gCaseConv->ToLower(aChar, &result);
+ else {
+ NS_WARNING("No case converter: no conversion done");
+ if (aChar < 256)
+ result = tolower(char(aChar));
+ else
+ result = aChar;
+ }
+ return result;
+}
+
+PRUnichar
+ToUpperCase(PRUnichar aChar)
+{
+ PRUnichar result;
+ if (NS_FAILED(NS_InitCaseConversion()))
+ return aChar;
+
+ if (gCaseConv)
+ gCaseConv->ToUpper(aChar, &result);
+ else {
+ NS_WARNING("No case converter: no conversion done");
+ if (aChar < 256)
+ result = toupper(char(aChar));
+ else
+ result = aChar;
+ }
+ return result;
+}
+
diff --git a/embed/mozilla/nsUnicharUtils.h b/embed/mozilla/nsUnicharUtils.h
new file mode 100644
index 000000000..6ae9a238d
--- /dev/null
+++ b/embed/mozilla/nsUnicharUtils.h
@@ -0,0 +1,96 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Unicode case conversion helpers.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corp..
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Alec Flett <alecf@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef nsUnicharUtils_h__
+#define nsUnicharUtils_h__
+#ifndef nsAString_h___
+#include "nsAString.h"
+#endif
+
+class nsASingleFragmentString;
+class nsString;
+
+void ToLowerCase( nsAString& );
+void ToUpperCase( nsAString& );
+
+void ToLowerCase( nsASingleFragmentString& );
+void ToUpperCase( nsASingleFragmentString& );
+
+void ToLowerCase( nsString& );
+void ToUpperCase( nsString& );
+
+void ToLowerCase( const nsAString& aSource, nsAString& aDest );
+void ToUpperCase( const nsAString& aSource, nsAString& aDest );
+
+PRBool CaseInsensitiveFindInReadable( const nsAString& aPattern, nsAString::const_iterator&, nsAString::const_iterator& );
+
+class nsCaseInsensitiveStringComparator
+ : public nsStringComparator
+ {
+ public:
+ virtual int operator()( const PRUnichar*, const PRUnichar*, PRUint32 aLength ) const;
+ virtual int operator()( PRUnichar, PRUnichar ) const;
+ };
+
+
+PRUnichar ToUpperCase(PRUnichar);
+PRUnichar ToLowerCase(PRUnichar);
+
+inline PRBool IsUpperCase(PRUnichar c) {
+ return ToLowerCase(c) != c;
+}
+
+inline PRBool IsLowerCase(PRUnichar c) {
+ return ToUpperCase(c) != c;
+}
+
+#define IS_HIGH_SURROGATE(u) ((PRUnichar)(u) >= (PRUnichar)0xd800 && (PRUnichar)(u) <= (PRUnichar)0xdbff)
+#define IS_LOW_SURROGATE(u) ((PRUnichar)(u) >= (PRUnichar)0xdc00 && (PRUnichar)(u) <= (PRUnichar)0xdfff)
+
+#define SURROGATE_TO_UCS4(h, l) ((((PRUint32)(h)-(PRUint32)0xd800) << 10) + \
+ (PRUint32)(l) - (PRUint32)(0xdc00) + 0x10000)
+
+/* (0x3131u <= (u) && (u) <= 0x318eu) => Hangul Compatibility Jamo */
+/* (0xac00u <= (u) && (u) <= 0xd7a3u) => Hangul Syllables */
+#define IS_CJ_CHAR(u) \
+ ((0x2e80u <= (u) && (u) <= 0x312fu) || \
+ (0x3190u <= (u) && (u) <= 0xabffu) || \
+ (0xf900u <= (u) && (u) <= 0xfaffu) || \
+ (0xff00u <= (u) && (u) <= 0xffffu) )
+
+#endif /* nsUnicharUtils_h__ */
diff --git a/embed/print-dialog.c b/embed/print-dialog.c
new file mode 100755
index 000000000..09929376c
--- /dev/null
+++ b/embed/print-dialog.c
@@ -0,0 +1,402 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "print-dialog.h"
+#include "ephy-prefs.h"
+#include <gtk/gtkdialog.h>
+
+#define CONF_PRINT_BOTTOM_MARGIN "/apps/epiphany/print/bottom_margin"
+#define CONF_PRINT_TOP_MARGIN "/apps/epiphany/print/top_margin"
+#define CONF_PRINT_LEFT_MARGIN "/apps/epiphany/print/left_margin"
+#define CONF_PRINT_RIGHT_MARGIN "/apps/epiphany/print/right_margin"
+#define CONF_PRINT_PAGE_TITLE "/apps/epiphany/print/page_title_toggle"
+#define CONF_PRINT_PAGE_URL "/apps/epiphany/print/page_url_toggle"
+#define CONF_PRINT_DATE "/apps/epiphany/print/date_toggle"
+#define CONF_PRINT_PAGE_NUMBERS "/apps/epiphany/print/page_numbers_toggle"
+#define CONF_PRINT_PRINTER "/apps/epiphany/print/printer"
+#define CONF_PRINT_FILE "/apps/epiphany/print/file"
+#define CONF_PRINT_PRINTON "/apps/epiphany/print/printon"
+#define CONF_PRINT_PAPER "/apps/epiphany/print/paper"
+#define CONF_PRINT_ALL_PAGES "/apps/epiphany/print/all_pages"
+#define CONF_PRINT_START_FROM_LAST "/apps/epiphany/print/start_from_last"
+#define CONF_PRINT_COLOR "/apps/epiphany/print/color"
+#define CONF_PRINT_ORIENTATION "/apps/epiphany/print/orientation"
+
+static void print_dialog_class_init (PrintDialogClass *klass);
+static void print_dialog_init (PrintDialog *dialog);
+static void print_dialog_finalize (GObject *object);
+
+/* Glade callbacks */
+void
+print_cancel_button_cb (GtkWidget *widget,
+ EphyDialog *dialog);
+void
+print_ok_button_cb (GtkWidget *widget,
+ EphyDialog *dialog);
+void
+print_preview_button_cb (GtkWidget *widget,
+ EphyDialog *dialog);
+
+static GObjectClass *parent_class = NULL;
+
+struct PrintDialogPrivate
+{
+ gpointer dummy;
+};
+
+enum
+{
+ PRINTON_PROP,
+ PRINTER_PROP,
+ FILE_PROP,
+ PAPER_PROP,
+ TOP_PROP,
+ BOTTOM_PROP,
+ LEFT_PROP,
+ RIGHT_PROP,
+ PAGE_TITLE_PROP,
+ PAGE_URL_PROP,
+ PAGE_NUMBERS_PROP,
+ DATE_PROP,
+ ALL_PAGES_PROP,
+ TO_PROP,
+ FROM_PROP,
+ COLOR_PROP,
+ ORIENTATION_PROP
+};
+
+enum
+{
+ PREVIEW,
+ LAST_SIGNAL
+};
+
+static const
+EphyDialogProperty properties [] =
+{
+ { PRINTON_PROP, "printer_radiobutton", CONF_PRINT_PRINTON, PT_NORMAL, NULL },
+ { PRINTER_PROP, "printer_entry", CONF_PRINT_PRINTER, PT_NORMAL, NULL },
+ { FILE_PROP, "file_entry", CONF_PRINT_FILE, PT_NORMAL, NULL },
+ { PAPER_PROP,"letter_radiobutton", CONF_PRINT_PAPER, PT_NORMAL, NULL },
+ { TOP_PROP, "top_spinbutton", CONF_PRINT_TOP_MARGIN, PT_NORMAL, NULL },
+ { BOTTOM_PROP, "bottom_spinbutton", CONF_PRINT_BOTTOM_MARGIN, PT_NORMAL, NULL },
+ { LEFT_PROP,"left_spinbutton", CONF_PRINT_LEFT_MARGIN, PT_NORMAL, NULL },
+ { RIGHT_PROP, "right_spinbutton", CONF_PRINT_RIGHT_MARGIN, PT_NORMAL, NULL },
+ { PAGE_TITLE_PROP, "print_page_title_checkbutton", CONF_PRINT_PAGE_TITLE, PT_NORMAL, NULL },
+ { PAGE_URL_PROP, "print_page_url_checkbutton", CONF_PRINT_PAGE_URL, PT_NORMAL, NULL },
+ { PAGE_NUMBERS_PROP, "print_page_numbers_checkbutton", CONF_PRINT_PAGE_NUMBERS, PT_NORMAL, NULL },
+ { DATE_PROP, "print_date_checkbutton", CONF_PRINT_DATE, PT_NORMAL, NULL },
+ { ALL_PAGES_PROP, "all_pages_radiobutton", CONF_PRINT_ALL_PAGES, PT_NORMAL, NULL },
+ { TO_PROP, "to_spinbutton", NULL, PT_NORMAL, NULL },
+ { FROM_PROP, "from_spinbutton", NULL, PT_NORMAL, NULL },
+ { COLOR_PROP, "print_color_radiobutton", CONF_PRINT_COLOR, PT_NORMAL, NULL },
+ { ORIENTATION_PROP, "orient_p_radiobutton", CONF_PRINT_ORIENTATION, PT_NORMAL, NULL },
+
+ { -1, NULL, NULL }
+};
+
+static guint print_dialog_signals[LAST_SIGNAL] = { 0 };
+
+GType
+print_dialog_get_type (void)
+{
+ static GType print_dialog_type = 0;
+
+ if (print_dialog_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (PrintDialogClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) print_dialog_class_init,
+ NULL,
+ NULL, /* class_data */
+ sizeof (PrintDialog),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) print_dialog_init
+ };
+
+ print_dialog_type = g_type_register_static (EPHY_EMBED_DIALOG_TYPE,
+ "PrintDialog",
+ &our_info, 0);
+ }
+
+ return print_dialog_type;
+
+}
+
+static void
+print_dialog_class_init (PrintDialogClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = print_dialog_finalize;
+
+ print_dialog_signals[PREVIEW] =
+ g_signal_new ("preview",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (PrintDialogClass, preview),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+}
+
+static void
+print_dialog_init (PrintDialog *dialog)
+{
+ dialog->priv = g_new0 (PrintDialogPrivate, 1);
+
+ dialog->only_collect_info = FALSE;
+
+ dialog->ret_info = NULL;
+
+ ephy_dialog_construct (EPHY_DIALOG(dialog),
+ properties,
+ "print.glade", "print_dialog");
+}
+
+static void
+print_dialog_finalize (GObject *object)
+{
+ PrintDialog *dialog;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (IS_PRINT_DIALOG (object));
+
+ dialog = PRINT_DIALOG (object);
+
+ g_return_if_fail (dialog->priv != NULL);
+
+ g_free (dialog->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+EphyDialog *
+print_dialog_new (EphyEmbed *embed,
+ EmbedPrintInfo **ret_info)
+{
+ PrintDialog *dialog;
+
+ dialog = PRINT_DIALOG (g_object_new (PRINT_DIALOG_TYPE,
+ "EphyEmbed", embed,
+ NULL));
+
+ if (!embed) dialog->only_collect_info = TRUE;
+ dialog->ret_info = ret_info;
+
+ return EPHY_DIALOG(dialog);
+}
+
+EphyDialog *
+print_dialog_new_with_parent (GtkWidget *window,
+ EphyEmbed *embed,
+ EmbedPrintInfo **ret_info)
+{
+ PrintDialog *dialog;
+
+ dialog = PRINT_DIALOG (g_object_new (PRINT_DIALOG_TYPE,
+ "EphyEmbed", embed,
+ "ParentWindow", window,
+ NULL));
+
+ if (!embed) dialog->only_collect_info = TRUE;
+ dialog->ret_info = ret_info;
+
+ return EPHY_DIALOG(dialog);
+}
+
+void
+print_free_info (EmbedPrintInfo *info)
+{
+ g_free (info->printer);
+ g_free (info->file);
+ g_free (info->header_left_string);
+ g_free (info->header_right_string);
+ g_free (info->footer_left_string);
+ g_free (info->footer_right_string);
+ g_free (info);
+}
+
+static EmbedPrintInfo *
+print_get_info (EphyDialog *dialog)
+{
+ EmbedPrintInfo *info;
+ GValue print_to_file = {0, };
+ GValue printer = {0, };
+ GValue file = {0, };
+ GValue top_margin = {0, };
+ GValue bottom_margin = {0, };
+ GValue left_margin = {0, };
+ GValue right_margin = {0, };
+ GValue from_page = {0, };
+ GValue to_page = {0, };
+ GValue paper = {0, };
+ GValue pages = {0, };
+ GValue print_color = {0, };
+ GValue orientation = {0, };
+ GValue page_title = {0, };
+ GValue page_url = {0, };
+ GValue date = {0, };
+ GValue page_numbers = {0, };
+
+ info = g_new0 (EmbedPrintInfo, 1);
+
+ ephy_dialog_get_value (dialog, PRINTON_PROP, &print_to_file);
+ info->print_to_file = g_value_get_int (&print_to_file);
+
+ ephy_dialog_get_value (dialog, PRINTER_PROP, &printer);
+ info->printer = g_strdup (g_value_get_string (&printer));
+
+ ephy_dialog_get_value (dialog, FILE_PROP, &file);
+ info->file = g_strdup (g_value_get_string (&file));
+
+ ephy_dialog_get_value (dialog, BOTTOM_PROP, &bottom_margin);
+ info->bottom_margin = g_value_get_float (&bottom_margin);
+
+ ephy_dialog_get_value (dialog, LEFT_PROP, &left_margin);
+ info->left_margin = g_value_get_float (&left_margin);
+
+ ephy_dialog_get_value (dialog, TOP_PROP, &top_margin);
+ info->top_margin = g_value_get_float (&top_margin);
+
+ ephy_dialog_get_value (dialog, RIGHT_PROP, &right_margin);
+ info->right_margin = g_value_get_float (&right_margin);
+
+ ephy_dialog_get_value (dialog, FROM_PROP, &from_page);
+ info->from_page = g_value_get_float (&from_page);
+
+ ephy_dialog_get_value (dialog, TO_PROP, &to_page);
+ info->to_page = g_value_get_float (&to_page);
+
+ ephy_dialog_get_value (dialog, PAPER_PROP, &paper);
+ info->paper = g_value_get_int (&paper);
+
+ ephy_dialog_get_value (dialog, ALL_PAGES_PROP, &pages);
+ info->pages = g_value_get_int (&pages);
+
+ ephy_dialog_get_value (dialog, COLOR_PROP, &print_color);
+ info->print_color = g_value_get_int (&print_color);
+
+ ephy_dialog_get_value (dialog, ORIENTATION_PROP, &orientation);
+ info->orientation = g_value_get_int (&orientation);
+
+ info->frame_type = 0;
+
+ ephy_dialog_get_value (dialog, PAGE_TITLE_PROP, &page_title);
+ info->header_left_string = g_value_get_boolean (&page_title) ?
+ g_strdup ("&T") : g_strdup ("");
+
+ ephy_dialog_get_value (dialog, PAGE_URL_PROP, &page_url);
+ info->header_right_string = g_value_get_boolean (&page_url) ?
+ g_strdup ("&U") : g_strdup ("");
+
+ ephy_dialog_get_value (dialog, PAGE_NUMBERS_PROP, &page_numbers);
+ info->footer_left_string = g_value_get_boolean (&page_numbers) ?
+ g_strdup ("&PT") : g_strdup ("");
+
+ ephy_dialog_get_value (dialog, DATE_PROP, &date);
+ info->footer_right_string = g_value_get_boolean (&date) ?
+ g_strdup ("&D") : g_strdup ("");
+
+ info->header_center_string = g_strdup("");
+ info->footer_center_string = g_strdup("");
+
+ return info;
+}
+
+static void
+print_dialog_print (EphyDialog *dialog)
+{
+ EmbedPrintInfo *info;
+ EphyEmbed *embed;
+
+ info = print_get_info (dialog);
+
+ if(PRINT_DIALOG(dialog)->only_collect_info && PRINT_DIALOG(dialog)->ret_info)
+ {
+ *(PRINT_DIALOG(dialog)->ret_info) = info;
+ }
+ else
+ {
+ embed = ephy_embed_dialog_get_embed
+ (EPHY_EMBED_DIALOG(dialog));
+
+ info->preview = FALSE;
+ ephy_embed_print (embed, info);
+ print_free_info (info);
+ }
+
+ g_object_unref (G_OBJECT(dialog));
+}
+
+static void
+print_dialog_preview (EphyDialog *dialog)
+{
+ EmbedPrintInfo *info;
+ EphyEmbed *embed;
+
+ info = print_get_info (dialog);
+
+ if(PRINT_DIALOG(dialog)->only_collect_info && PRINT_DIALOG(dialog)->ret_info)
+ {
+ *(PRINT_DIALOG(dialog)->ret_info) = info;
+ }
+ else
+ {
+ embed = ephy_embed_dialog_get_embed
+ (EPHY_EMBED_DIALOG(dialog));
+
+ info->preview = TRUE;
+ ephy_embed_print (embed, info);
+ print_free_info (info);
+ }
+ g_signal_emit (G_OBJECT (dialog), print_dialog_signals[PREVIEW], 0);
+
+ g_object_unref (G_OBJECT(dialog));
+}
+
+void
+print_cancel_button_cb (GtkWidget *widget,
+ EphyDialog *dialog)
+{
+ g_object_unref (G_OBJECT(dialog));
+}
+
+void
+print_ok_button_cb (GtkWidget *widget,
+ EphyDialog *dialog)
+{
+ print_dialog_print (dialog);
+}
+
+void
+print_preview_button_cb (GtkWidget *widget,
+ EphyDialog *dialog)
+{
+ //FIXME: Don't show preview button at all.
+ if(!(PRINT_DIALOG(dialog)->only_collect_info))
+ print_dialog_preview (dialog);
+}
+
+
diff --git a/embed/print-dialog.h b/embed/print-dialog.h
new file mode 100644
index 000000000..5342f0223
--- /dev/null
+++ b/embed/print-dialog.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef PRINT_DIALOG_H
+#define PRINT_DIALOG_H
+
+#include "ephy-embed-dialog.h"
+#include "ephy-embed.h"
+
+#include <glib-object.h>
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef struct PrintDialog PrintDialog;
+typedef struct PrintDialogClass PrintDialogClass;
+
+#define PRINT_DIALOG_TYPE (print_dialog_get_type ())
+#define PRINT_DIALOG(obj) (GTK_CHECK_CAST ((obj), PRINT_DIALOG_TYPE, PrintDialog))
+#define PRINT_DIALOG_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), PRINT_DIALOG, PrintDialogClass))
+#define IS_PRINT_DIALOG(obj) (GTK_CHECK_TYPE ((obj), PRINT_DIALOG_TYPE))
+#define IS_PRINT_DIALOG_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), PRINT_DIALOG))
+
+typedef struct PrintDialogPrivate PrintDialogPrivate;
+
+struct PrintDialog
+{
+ EphyEmbedDialog parent;
+ PrintDialogPrivate *priv;
+ //FIXME: These should be gobject properties
+ gboolean only_collect_info;
+ EmbedPrintInfo **ret_info;
+};
+
+struct PrintDialogClass
+{
+ EphyEmbedDialogClass parent_class;
+
+ void (* preview) (PrintDialog *dialog);
+};
+
+GType print_dialog_get_type (void);
+
+EphyDialog *print_dialog_new (EphyEmbed *embed,
+ EmbedPrintInfo **ret_info);
+
+EphyDialog *print_dialog_new_with_parent (GtkWidget *window,
+ EphyEmbed *embed,
+ EmbedPrintInfo **ret_info);
+
+gboolean print_dialog_is_preview (PrintDialog *dialog);
+
+void print_free_info (EmbedPrintInfo *info);
+
+G_END_DECLS
+
+#endif
+
diff --git a/idl/EphyAutomation.idl b/idl/EphyAutomation.idl
new file mode 100644
index 000000000..090fd51f3
--- /dev/null
+++ b/idl/EphyAutomation.idl
@@ -0,0 +1,27 @@
+#include <Bonobo.idl>
+
+module GNOME {
+
+ interface EphyAutomation : Bonobo::Unknown {
+ boolean loadurl (in string url,
+ in string geometry,
+ in boolean fullscreen,
+ in boolean open_in_existing_tab,
+ in boolean open_in_new_tab,
+ in boolean open_in_new_window,
+ in boolean raise);
+
+ boolean addBookmark (in string url);
+
+ /**
+ * Closes all opened windows.
+ * if disableServer is true,
+ * server mode is disbaled
+ * (and Galeon exits)
+ */
+ boolean quit (in boolean disableServer);
+
+ boolean loadSession (in string filename);
+ };
+};
+
diff --git a/lib/.cvsignore b/lib/.cvsignore
new file mode 100644
index 000000000..20e4cb0c8
--- /dev/null
+++ b/lib/.cvsignore
@@ -0,0 +1,6 @@
+Makefile
+Makefile.in
+*.lo
+.deps
+.libs
+*.la
diff --git a/lib/Makefile.am b/lib/Makefile.am
new file mode 100644
index 000000000..60092472f
--- /dev/null
+++ b/lib/Makefile.am
@@ -0,0 +1,73 @@
+SUBDIRS = widgets toolbar
+
+INCLUDES = \
+ $(WARN_CFLAGS) \
+ $(EPIPHANY_DEPENDENCY_CFLAGS) \
+ -DSHARE_DIR=\"$(pkgdatadir)\" \
+ -DG_DISABLE_DEPRECATED \
+ -DGDK_DISABLE_DEPRECATED \
+ -DGTK_DISABLE_DEPRECATED \
+ -DGDK_PIXBUF_DISABLE_DEPRECATED \
+ -DGNOME_DISABLE_DEPRECATED
+
+noinst_LTLIBRARIES = libephy.la
+
+libephy_la_SOURCES = \
+ ephy-types.h \
+ ephy-prefs.h \
+ ephy-gobject-misc.h \
+ eel-gconf-extensions.c \
+ eel-gconf-extensions.h \
+ ephy-dialog.c \
+ ephy-dialog.h \
+ ephy-dnd.c \
+ ephy-dnd.h \
+ ephy-marshal.c \
+ ephy-marshal.h \
+ ephy-types.h \
+ ephy-bonobo-extensions.h \
+ ephy-bonobo-extensions.c \
+ ephy-file-helpers.c \
+ ephy-file-helpers.h \
+ ephy-glade.c \
+ ephy-glade.h \
+ ephy-gui.c \
+ ephy-gui.h \
+ ephy-prefs-utils.c \
+ ephy-prefs-utils.h \
+ ephy-state.c \
+ ephy-state.h \
+ ephy-string.c \
+ ephy-string.h \
+ ephy-autocompletion.c \
+ ephy-autocompletion.h \
+ ephy-autocompletion-source.c \
+ ephy-autocompletion-source.h \
+ ephy-stock-icons.c \
+ ephy-stock-icons.h \
+ ephy-filesystem-autocompletion.c \
+ ephy-filesystem-autocompletion.h \
+ ephy-thread-helpers.c \
+ ephy-thread-helpers.h \
+ ephy-node.c \
+ ephy-node.h \
+ ephy-node-filter.c \
+ ephy-node-filter.h
+
+libephy_la_LIBADD = \
+ $(top_builddir)/lib/widgets/libephywidgets.la \
+ $(top_builddir)/lib/toolbar/libephytoolbar.la
+
+BUILT_SOURCES=ephy-marshal.c ephy-marshal.h
+
+CLEAN_FILES = $(BUILT_SOURCES)
+
+ephy-marshal.c: ephy-marshal.list
+ @GLIB_GENMARSHAL@ --prefix=ephy_marshal $(srcdir)/ephy-marshal.list --header --body > ephy-marshal.c
+
+ephy-marshal.h: ephy-marshal.list
+ @GLIB_GENMARSHAL@ --prefix=ephy_marshal $(srcdir)/ephy-marshal.list --header > ephy-marshal.h
+
+EXTRA_DIST = \
+ ephy-marshal.list
+
diff --git a/lib/eel-gconf-extensions.c b/lib/eel-gconf-extensions.c
new file mode 100644
index 000000000..e6593219a
--- /dev/null
+++ b/lib/eel-gconf-extensions.c
@@ -0,0 +1,556 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+
+/* eel-gconf-extensions.c - Stuff to make GConf easier to use.
+
+ Copyright (C) 2000, 2001 Eazel, Inc.
+
+ The Gnome Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The Gnome 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the Gnome Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Authors: Ramiro Estrugo <ramiro@eazel.com>
+*/
+
+#include <stdlib.h>
+#include <config.h>
+#include "eel-gconf-extensions.h"
+
+#include <gconf/gconf-client.h>
+#include <gconf/gconf.h>
+#include <gtk/gtkwidget.h>
+#include <libgnome/gnome-i18n.h>
+#include <gtk/gtkmessagedialog.h>
+
+static GConfClient *global_gconf_client = NULL;
+
+static void
+global_client_free (void)
+{
+ if (global_gconf_client == NULL) {
+ return;
+ }
+
+ g_object_unref (G_OBJECT (global_gconf_client));
+ global_gconf_client = NULL;
+}
+
+/* Public */
+GConfClient *
+eel_gconf_client_get_global (void)
+{
+ /* Initialize gconf if needed */
+ if (!gconf_is_initialized ()) {
+ char *argv[] = { "eel-preferences", NULL };
+ GError *error = NULL;
+
+ if (!gconf_init (1, argv, &error)) {
+ if (eel_gconf_handle_error (&error)) {
+ return NULL;
+ }
+ }
+
+ }
+
+ if (global_gconf_client == NULL) {
+ global_gconf_client = gconf_client_get_default ();
+ g_atexit (global_client_free);
+ }
+
+ return global_gconf_client;
+}
+
+gboolean
+eel_gconf_handle_error (GError **error)
+{
+ g_return_val_if_fail (error != NULL, FALSE);
+
+ if (*error != NULL) {
+ g_warning (_("GConf error:\n %s"), (*error)->message);
+ g_error_free (*error);
+ *error = NULL;
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+void
+eel_gconf_set_boolean (const char *key,
+ gboolean boolean_value)
+{
+ GConfClient *client;
+ GError *error = NULL;
+
+ g_return_if_fail (key != NULL);
+
+ client = eel_gconf_client_get_global ();
+ g_return_if_fail (client != NULL);
+
+ gconf_client_set_bool (client, key, boolean_value, &error);
+ eel_gconf_handle_error (&error);
+}
+
+gboolean
+eel_gconf_get_boolean (const char *key)
+{
+ gboolean result;
+ GConfClient *client;
+ GError *error = NULL;
+
+ g_return_val_if_fail (key != NULL, FALSE);
+
+ client = eel_gconf_client_get_global ();
+ g_return_val_if_fail (client != NULL, FALSE);
+
+ result = gconf_client_get_bool (client, key, &error);
+
+ if (eel_gconf_handle_error (&error)) {
+ result = FALSE;
+ }
+
+ return result;
+}
+
+void
+eel_gconf_set_integer (const char *key,
+ int int_value)
+{
+ GConfClient *client;
+ GError *error = NULL;
+
+ g_return_if_fail (key != NULL);
+
+ client = eel_gconf_client_get_global ();
+ g_return_if_fail (client != NULL);
+
+ gconf_client_set_int (client, key, int_value, &error);
+ eel_gconf_handle_error (&error);
+}
+
+int
+eel_gconf_get_integer (const char *key)
+{
+ int result;
+ GConfClient *client;
+ GError *error = NULL;
+
+ g_return_val_if_fail (key != NULL, 0);
+
+ client = eel_gconf_client_get_global ();
+ g_return_val_if_fail (client != NULL, 0);
+
+ result = gconf_client_get_int (client, key, &error);
+
+ if (eel_gconf_handle_error (&error)) {
+ result = 0;
+ }
+
+ return result;
+}
+
+void
+eel_gconf_set_float (const char *key,
+ gfloat float_value)
+{
+ GConfClient *client;
+ GError *error = NULL;
+
+ g_return_if_fail (key != NULL);
+
+ client = eel_gconf_client_get_global ();
+ g_return_if_fail (client != NULL);
+
+ gconf_client_set_float (client, key, float_value, &error);
+ eel_gconf_handle_error (&error);
+}
+
+gfloat
+eel_gconf_get_float (const char *key)
+{
+ gfloat result;
+ GConfClient *client;
+ GError *error = NULL;
+
+ g_return_val_if_fail (key != NULL, 0);
+
+ client = eel_gconf_client_get_global ();
+ g_return_val_if_fail (client != NULL, 0);
+
+ result = gconf_client_get_float (client, key, &error);
+
+ if (eel_gconf_handle_error (&error)) {
+ result = 0;
+ }
+
+ return result;
+}
+
+void
+eel_gconf_set_string (const char *key,
+ const char *string_value)
+{
+ GConfClient *client;
+ GError *error = NULL;
+
+ g_return_if_fail (key != NULL);
+ g_return_if_fail (string_value != NULL);
+
+ client = eel_gconf_client_get_global ();
+ g_return_if_fail (client != NULL);
+
+ gconf_client_set_string (client, key, string_value, &error);
+ eel_gconf_handle_error (&error);
+}
+
+void
+eel_gconf_unset (const char *key)
+{
+ GConfClient *client;
+ GError *error = NULL;
+
+ g_return_if_fail (key != NULL);
+
+ client = eel_gconf_client_get_global ();
+ g_return_if_fail (client != NULL);
+
+ gconf_client_unset (client, key, &error);
+ eel_gconf_handle_error (&error);
+}
+
+char *
+eel_gconf_get_string (const char *key)
+{
+ char *result;
+ GConfClient *client;
+ GError *error = NULL;
+
+ g_return_val_if_fail (key != NULL, NULL);
+
+ client = eel_gconf_client_get_global ();
+ g_return_val_if_fail (client != NULL, NULL);
+
+ result = gconf_client_get_string (client, key, &error);
+
+ if (eel_gconf_handle_error (&error)) {
+ result = g_strdup ("");
+ }
+
+ return result;
+}
+
+void
+eel_gconf_set_string_list (const char *key,
+ const GSList *slist)
+{
+ GConfClient *client;
+ GError *error;
+
+ g_return_if_fail (key != NULL);
+
+ client = eel_gconf_client_get_global ();
+ g_return_if_fail (client != NULL);
+
+ error = NULL;
+ gconf_client_set_list (client, key, GCONF_VALUE_STRING,
+ /* Need cast cause of GConf api bug */
+ (GSList *) slist,
+ &error);
+ eel_gconf_handle_error (&error);
+}
+
+GSList *
+eel_gconf_get_string_list (const char *key)
+{
+ GSList *slist;
+ GConfClient *client;
+ GError *error;
+
+ g_return_val_if_fail (key != NULL, NULL);
+
+ client = eel_gconf_client_get_global ();
+ g_return_val_if_fail (client != NULL, NULL);
+
+ error = NULL;
+ slist = gconf_client_get_list (client, key, GCONF_VALUE_STRING, &error);
+ if (eel_gconf_handle_error (&error)) {
+ slist = NULL;
+ }
+
+ return slist;
+}
+
+/* This code wasn't part of the original eel-gconf-extensions.c */
+void
+eel_gconf_set_integer_list (const char *key,
+ const GSList *slist)
+{
+ GConfClient *client;
+ GError *error;
+
+ g_return_if_fail (key != NULL);
+
+ client = eel_gconf_client_get_global ();
+ g_return_if_fail (client != NULL);
+
+ error = NULL;
+ gconf_client_set_list (client, key, GCONF_VALUE_INT,
+ /* Need cast cause of GConf api bug */
+ (GSList *) slist,
+ &error);
+ eel_gconf_handle_error (&error);
+}
+
+GSList *
+eel_gconf_get_integer_list (const char *key)
+{
+ GSList *slist;
+ GConfClient *client;
+ GError *error;
+
+ g_return_val_if_fail (key != NULL, NULL);
+
+ client = eel_gconf_client_get_global ();
+ g_return_val_if_fail (client != NULL, NULL);
+
+ error = NULL;
+ slist = gconf_client_get_list (client, key, GCONF_VALUE_INT, &error);
+ if (eel_gconf_handle_error (&error)) {
+ slist = NULL;
+ }
+
+ return slist;
+}
+/* End of added code */
+
+gboolean
+eel_gconf_is_default (const char *key)
+{
+ gboolean result;
+ GConfValue *value;
+ GError *error = NULL;
+
+ g_return_val_if_fail (key != NULL, FALSE);
+
+ value = gconf_client_get_without_default (eel_gconf_client_get_global (), key, &error);
+
+ if (eel_gconf_handle_error (&error)) {
+ if (value != NULL) {
+ gconf_value_free (value);
+ }
+ return FALSE;
+ }
+
+ result = (value == NULL);
+
+ if (value != NULL) {
+ gconf_value_free (value);
+ }
+
+
+ return result;
+}
+
+gboolean
+eel_gconf_monitor_add (const char *directory)
+{
+ GError *error = NULL;
+ GConfClient *client;
+
+ g_return_val_if_fail (directory != NULL, FALSE);
+
+ client = eel_gconf_client_get_global ();
+ g_return_val_if_fail (client != NULL, FALSE);
+
+ gconf_client_add_dir (client,
+ directory,
+ GCONF_CLIENT_PRELOAD_NONE,
+ &error);
+
+ if (eel_gconf_handle_error (&error)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+gboolean
+eel_gconf_monitor_remove (const char *directory)
+{
+ GError *error = NULL;
+ GConfClient *client;
+
+ if (directory == NULL) {
+ return FALSE;
+ }
+
+ client = eel_gconf_client_get_global ();
+ g_return_val_if_fail (client != NULL, FALSE);
+
+ gconf_client_remove_dir (client,
+ directory,
+ &error);
+
+ if (eel_gconf_handle_error (&error)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+void
+eel_gconf_suggest_sync (void)
+{
+ GConfClient *client;
+ GError *error = NULL;
+
+ client = eel_gconf_client_get_global ();
+ g_return_if_fail (client != NULL);
+
+ gconf_client_suggest_sync (client, &error);
+ eel_gconf_handle_error (&error);
+}
+
+GConfValue*
+eel_gconf_get_value (const char *key)
+{
+ GConfValue *value = NULL;
+ GConfClient *client;
+ GError *error = NULL;
+
+ g_return_val_if_fail (key != NULL, NULL);
+
+ client = eel_gconf_client_get_global ();
+ g_return_val_if_fail (client != NULL, NULL);
+
+ value = gconf_client_get (client, key, &error);
+
+ if (eel_gconf_handle_error (&error)) {
+ if (value != NULL) {
+ gconf_value_free (value);
+ value = NULL;
+ }
+ }
+
+ return value;
+}
+
+void
+eel_gconf_set_value (const char *key, GConfValue *value)
+{
+ GConfClient *client;
+ GError *error = NULL;
+
+ g_return_if_fail (key != NULL);
+
+ client = eel_gconf_client_get_global ();
+ g_return_if_fail (client != NULL);
+
+ gconf_client_set (client, key, value, &error);
+
+ if (eel_gconf_handle_error (&error)) {
+ return;
+ }
+}
+
+void
+eel_gconf_value_free (GConfValue *value)
+{
+ if (value == NULL) {
+ return;
+ }
+
+ gconf_value_free (value);
+}
+
+guint
+eel_gconf_notification_add (const char *key,
+ GConfClientNotifyFunc notification_callback,
+ gpointer callback_data)
+{
+ guint notification_id;
+ GConfClient *client;
+ GError *error = NULL;
+
+ g_return_val_if_fail (key != NULL, EEL_GCONF_UNDEFINED_CONNECTION);
+ g_return_val_if_fail (notification_callback != NULL, EEL_GCONF_UNDEFINED_CONNECTION);
+
+ client = eel_gconf_client_get_global ();
+ g_return_val_if_fail (client != NULL, EEL_GCONF_UNDEFINED_CONNECTION);
+
+ notification_id = gconf_client_notify_add (client,
+ key,
+ notification_callback,
+ callback_data,
+ NULL,
+ &error);
+
+ if (eel_gconf_handle_error (&error)) {
+ if (notification_id != EEL_GCONF_UNDEFINED_CONNECTION) {
+ gconf_client_notify_remove (client, notification_id);
+ notification_id = EEL_GCONF_UNDEFINED_CONNECTION;
+ }
+ }
+
+ return notification_id;
+}
+
+void
+eel_gconf_notification_remove (guint notification_id)
+{
+ GConfClient *client;
+
+ if (notification_id == EEL_GCONF_UNDEFINED_CONNECTION) {
+ return;
+ }
+
+ client = eel_gconf_client_get_global ();
+ g_return_if_fail (client != NULL);
+
+ gconf_client_notify_remove (client, notification_id);
+}
+
+/* Simple wrapper for eel_gconf_notifier_add which
+ * adds the notifier id to the GList given as argument
+ * so that a call to ephy_notification_free can remove the notifiers
+ */
+void
+ephy_notification_add (const char *key,
+ GConfClientNotifyFunc notification_callback,
+ gpointer callback_data,
+ GList **notifiers)
+{
+ guint id = 0;
+
+ id = eel_gconf_notification_add(key,
+ notification_callback,
+ callback_data);
+ if (notifiers != NULL) {
+ *notifiers = g_list_append(*notifiers,
+ (gpointer)id);
+ }
+}
+
+/* Removes all the notifiers listed in notifiers */
+/* Frees the notifiers list */
+void
+ephy_notification_remove (GList **notifiers)
+{
+ g_list_foreach(*notifiers,
+ (GFunc)eel_gconf_notification_remove,
+ NULL);
+ g_list_free(*notifiers);
+ *notifiers = NULL;
+}
+
diff --git a/lib/eel-gconf-extensions.h b/lib/eel-gconf-extensions.h
new file mode 100644
index 000000000..df51afaa1
--- /dev/null
+++ b/lib/eel-gconf-extensions.h
@@ -0,0 +1,87 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+
+/* eel-gconf-extensions.h - Stuff to make GConf easier to use.
+
+ Copyright (C) 2000, 2001 Eazel, Inc.
+
+ The Gnome Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The Gnome 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the Gnome Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Authors: Ramiro Estrugo <ramiro@eazel.com>
+*/
+
+#ifndef EEL_GCONF_EXTENSIONS_H
+#define EEL_GCONF_EXTENSIONS_H
+
+#include <glib/gerror.h>
+#include <gconf/gconf.h>
+#include <gconf/gconf-client.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define EEL_GCONF_UNDEFINED_CONNECTION 0
+
+GConfClient *eel_gconf_client_get_global (void);
+gboolean eel_gconf_handle_error (GError **error);
+void eel_gconf_set_boolean (const char *key,
+ gboolean boolean_value);
+gboolean eel_gconf_get_boolean (const char *key);
+int eel_gconf_get_integer (const char *key);
+void eel_gconf_set_integer (const char *key,
+ int int_value);
+gfloat eel_gconf_get_float (const char *key);
+void eel_gconf_set_float (const char *key,
+ gfloat float_value);
+char * eel_gconf_get_string (const char *key);
+void eel_gconf_set_string (const char *key,
+ const char *string_value);
+GSList * eel_gconf_get_string_list (const char *key);
+void eel_gconf_set_string_list (const char *key,
+ const GSList *string_list_value);
+gboolean eel_gconf_is_default (const char *key);
+gboolean eel_gconf_monitor_add (const char *directory);
+gboolean eel_gconf_monitor_remove (const char *directory);
+void eel_gconf_suggest_sync (void);
+GConfValue* eel_gconf_get_value (const char *key);
+gboolean eel_gconf_value_is_equal (const GConfValue *a,
+ const GConfValue *b);
+void eel_gconf_set_value (const char *key, GConfValue *value);
+void eel_gconf_value_free (GConfValue *value);
+void eel_gconf_unset (const char *key);
+
+/* Functions which weren't part of the eel-gconf-extensions.h file from eel */
+GSList *eel_gconf_get_integer_list (const char *key);
+void eel_gconf_set_integer_list (const char *key,
+ const GSList *slist);
+guint eel_gconf_notification_add (const char *key,
+ GConfClientNotifyFunc notification_callback,
+ gpointer callback_data);
+void eel_gconf_notification_remove (guint notification_id);
+
+void ephy_notification_add (const char *key,
+ GConfClientNotifyFunc notification_callback,
+ gpointer callback_data,
+ GList **notifiers);
+
+void ephy_notification_remove (GList **notifiers);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* EEL_GCONF_EXTENSIONS_H */
diff --git a/lib/ephy-autocompletion-source.c b/lib/ephy-autocompletion-source.c
new file mode 100644
index 000000000..717b9924e
--- /dev/null
+++ b/lib/ephy-autocompletion-source.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2002 Ricardo Fernándezs Pascual <ric@users.sourceforge.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "ephy-autocompletion-source.h"
+#include "ephy-marshal.h"
+
+static void ephy_autocompletion_source_base_init (gpointer g_class);
+
+GType
+ephy_autocompletion_source_get_type (void)
+{
+ static GType autocompletion_source_type = 0;
+
+ if (! autocompletion_source_type)
+ {
+ static const GTypeInfo autocompletion_source_info =
+ {
+ sizeof (EphyAutocompletionSourceIface), /* class_size */
+ ephy_autocompletion_source_base_init, /* base_init */
+ NULL, /* base_finalize */
+ NULL,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ 0,
+ 0, /* n_preallocs */
+ NULL
+ };
+
+ autocompletion_source_type = g_type_register_static
+ (G_TYPE_INTERFACE, "EphyAutocompletionSource", &autocompletion_source_info, 0);
+ g_type_interface_add_prerequisite (autocompletion_source_type, G_TYPE_OBJECT);
+ }
+
+ return autocompletion_source_type;
+}
+
+static void
+ephy_autocompletion_source_base_init (gpointer g_class)
+{
+ static gboolean initialized = FALSE;
+
+ if (!initialized)
+ {
+ g_signal_new ("data-changed",
+ EPHY_TYPE_AUTOCOMPLETION_SOURCE,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EphyAutocompletionSourceIface, data_changed),
+ NULL, NULL,
+ ephy_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+ initialized = TRUE;
+ }
+}
+
+
+void
+ephy_autocompletion_source_foreach (EphyAutocompletionSource *source,
+ const gchar *basic_key,
+ EphyAutocompletionSourceForeachFunc func,
+ gpointer data)
+{
+ (* EPHY_AUTOCOMPLETION_SOURCE_GET_IFACE (source)->foreach) (source, basic_key, func, data);
+}
+
+void
+ephy_autocompletion_source_set_basic_key (EphyAutocompletionSource *source,
+ const gchar *basic_key)
+{
+ (* EPHY_AUTOCOMPLETION_SOURCE_GET_IFACE (source)->set_basic_key) (source, basic_key);
+}
diff --git a/lib/ephy-autocompletion-source.h b/lib/ephy-autocompletion-source.h
new file mode 100644
index 000000000..595708b3a
--- /dev/null
+++ b/lib/ephy-autocompletion-source.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2002 Ricardo Fernándezs Pascual <ric@users.sourceforge.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EPHY_AUTOCOMPLETION_SOUCE_H
+#define EPHY_AUTOCOMPLETION_SOUCE_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define EPHY_TYPE_AUTOCOMPLETION_SOURCE (ephy_autocompletion_source_get_type ())
+#define EPHY_AUTOCOMPLETION_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ EPHY_TYPE_AUTOCOMPLETION_SOURCE, \
+ EphyAutocompletionSource))
+#define EPHY_IS_AUTOCOMPLETION_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ EPHY_TYPE_AUTOCOMPLETION_SOURCE))
+#define EPHY_AUTOCOMPLETION_SOURCE_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), \
+ EPHY_TYPE_AUTOCOMPLETION_SOURCE, \
+ EphyAutocompletionSourceIface))
+
+
+typedef struct _EphyAutocompletionSource EphyAutocompletionSource;
+typedef struct _EphyAutocompletionSourceIface EphyAutocompletionSourceIface;
+typedef void (* EphyAutocompletionSourceForeachFunc) (EphyAutocompletionSource *source,
+ const char *item,
+ const char *title,
+ const char *target,
+ gboolean is_action,
+ gboolean substring,
+ guint32 score,
+ gpointer data);
+
+struct _EphyAutocompletionSourceIface
+{
+ GTypeInterface g_iface;
+
+ /* Signals */
+
+ /**
+ * Sources MUST emit this signal when theirs data changes, expecially if the
+ * strings are freed / modified. Otherwise, things will crash.
+ */
+ void (* data_changed) (EphyAutocompletionSource *source);
+
+ /* Virtual Table */
+ void (* foreach) (EphyAutocompletionSource *source,
+ const gchar *basic_key,
+ EphyAutocompletionSourceForeachFunc func,
+ gpointer data);
+ void (* set_basic_key) (EphyAutocompletionSource *source,
+ const gchar *basic_key);
+};
+
+GType ephy_autocompletion_source_get_type (void);
+void ephy_autocompletion_source_foreach (EphyAutocompletionSource *source,
+ const gchar *basic_key,
+ EphyAutocompletionSourceForeachFunc func,
+ gpointer data);
+void ephy_autocompletion_source_set_basic_key (EphyAutocompletionSource *source,
+ const gchar *basic_key);
+
+G_END_DECLS
+
+#endif
+
diff --git a/lib/ephy-autocompletion.c b/lib/ephy-autocompletion.c
new file mode 100644
index 000000000..a3f3348c1
--- /dev/null
+++ b/lib/ephy-autocompletion.c
@@ -0,0 +1,664 @@
+/*
+ * Copyright (C) 2002 Ricardo Fernández Pascual
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "ephy-autocompletion.h"
+#include "ephy-gobject-misc.h"
+#include "ephy-marshal.h"
+
+#define NOT_IMPLEMENTED g_warning ("not implemented: " G_STRLOC);
+
+//#define DEBUG_MSG(x) g_print x
+#define DEBUG_MSG(x)
+
+//#define DEBUG_TIME
+
+#ifdef DEBUG_TIME
+#include <glib/gtimer.h>
+#endif
+
+/**
+ * Private data
+ */
+
+typedef enum {
+ GAS_NEEDS_REFINE,
+ GAS_NEEDS_FULL_UPDATE,
+ GAS_UPDATED
+} EphyAutocompletionStatus;
+
+typedef struct {
+ EphyAutocompletionMatch *array;
+ guint num_matches;
+ guint num_action_matches;
+ guint array_size;
+} ACMatchArray;
+
+#define ACMA_BASE_SIZE 10240
+
+struct _EphyAutocompletionPrivate {
+ GSList *sources;
+
+ guint nkeys;
+ gchar **keys;
+ guint *key_lengths;
+ gchar **prefixes;
+ guint *prefix_lengths;
+
+ gchar *common_prefix;
+ ACMatchArray matches;
+ EphyAutocompletionStatus status;
+ gboolean sorted;
+ gboolean changed;
+
+ gboolean sort_alpha;
+};
+
+/**
+ * Private functions, only availble from this file
+ */
+static void ephy_autocompletion_class_init (EphyAutocompletionClass *klass);
+static void ephy_autocompletion_init (EphyAutocompletion *e);
+static void ephy_autocompletion_finalize_impl (GObject *o);
+static void ephy_autocompletion_reset (EphyAutocompletion *ac);
+static void ephy_autocompletion_update_matches (EphyAutocompletion *ac);
+static void ephy_autocompletion_update_matches_full (EphyAutocompletion *ac);
+static gboolean ephy_autocompletion_sort_by_score (EphyAutocompletion *ac);
+static void ephy_autocompletion_data_changed_cb (EphyAutocompletionSource *s,
+ EphyAutocompletion *ac);
+
+static void acma_init (ACMatchArray *a);
+static void acma_destroy (ACMatchArray *a);
+static inline void acma_append (ACMatchArray *a,
+ EphyAutocompletionMatch *m,
+ gboolean action);
+static void acma_grow (ACMatchArray *a);
+
+
+static gpointer g_object_class;
+
+/**
+ * Signals enums and ids
+ */
+enum EphyAutocompletionSignalsEnum {
+ EPHY_AUTOCOMPLETION_SOURCES_CHANGED,
+ EPHY_AUTOCOMPLETION_LAST_SIGNAL
+};
+static gint EphyAutocompletionSignals[EPHY_AUTOCOMPLETION_LAST_SIGNAL];
+
+/**
+ * Autocompletion object
+ */
+
+MAKE_GET_TYPE (ephy_autocompletion, "EphyAutocompletion", EphyAutocompletion,
+ ephy_autocompletion_class_init, ephy_autocompletion_init, G_TYPE_OBJECT);
+
+static void
+ephy_autocompletion_class_init (EphyAutocompletionClass *klass)
+{
+ G_OBJECT_CLASS (klass)->finalize = ephy_autocompletion_finalize_impl;
+ g_object_class = g_type_class_peek_parent (klass);
+
+ EphyAutocompletionSignals[EPHY_AUTOCOMPLETION_SOURCES_CHANGED] = g_signal_new (
+ "sources-changed", G_OBJECT_CLASS_TYPE (klass),
+ G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST | G_SIGNAL_RUN_CLEANUP,
+ G_STRUCT_OFFSET (EphyAutocompletionClass, sources_changed),
+ NULL, NULL,
+ ephy_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+}
+
+static void
+ephy_autocompletion_init (EphyAutocompletion *ac)
+{
+ EphyAutocompletionPrivate *p = g_new0 (EphyAutocompletionPrivate, 1);
+ ac->priv = p;
+ p->sources = NULL;
+ p->common_prefix = NULL;
+ acma_init (&p->matches);
+ p->status = GAS_NEEDS_FULL_UPDATE;
+
+ p->nkeys = 1;
+
+ p->keys = g_new0 (gchar *, 2);
+ p->keys[0] = g_strdup ("");
+ p->key_lengths = g_new0 (guint, 2);
+ p->key_lengths[0] = 0;
+
+ p->prefixes = g_new0 (gchar *, 2);
+ p->prefixes[0] = g_strdup ("");
+ p->prefix_lengths = g_new0 (guint, 2);
+ p->prefix_lengths[0] = 0;
+
+ p->sort_alpha = TRUE;
+}
+
+static void
+ephy_autocompletion_finalize_impl (GObject *o)
+{
+ EphyAutocompletion *ac = EPHY_AUTOCOMPLETION (o);
+ EphyAutocompletionPrivate *p = ac->priv;
+ GSList *li;
+
+ ephy_autocompletion_reset (ac);
+
+ for (li = p->sources; li; li = li->next)
+ {
+ g_signal_handlers_disconnect_by_func (li->data,
+ ephy_autocompletion_data_changed_cb, ac);
+ g_object_unref (li->data);
+ }
+
+ g_slist_free (p->sources);
+
+ g_strfreev (p->keys);
+ g_free (p->key_lengths);
+ g_strfreev (p->prefixes);
+ g_free (p->prefix_lengths);
+
+ G_OBJECT_CLASS (g_object_class)->finalize (o);
+
+}
+
+static void
+ephy_autocompletion_reset (EphyAutocompletion *ac)
+{
+ EphyAutocompletionPrivate *p = ac->priv;
+#ifdef DEBUG_TIME
+ GTimer *timer = g_timer_new ();
+ g_timer_start (timer);
+#endif
+ acma_destroy (&p->matches);
+ g_free (p->common_prefix);
+ p->common_prefix = NULL;
+ p->status = GAS_NEEDS_FULL_UPDATE;
+#ifdef DEBUG_TIME
+ DEBUG_MSG (("AC: %f elapsed resetting\n", g_timer_elapsed (timer, NULL)));
+ g_timer_destroy (timer);
+#endif
+}
+
+EphyAutocompletion *
+ephy_autocompletion_new (void)
+{
+ EphyAutocompletion *ret = g_object_new (EPHY_TYPE_AUTOCOMPLETION, NULL);
+ return ret;
+}
+void
+ephy_autocompletion_add_source (EphyAutocompletion *ac,
+ EphyAutocompletionSource *s)
+{
+ EphyAutocompletionPrivate *p = ac->priv;
+ g_object_ref (G_OBJECT (s));
+ p->sources = g_slist_prepend (p->sources, s);
+ ephy_autocompletion_reset (ac);
+ g_signal_connect (s, "data-changed", G_CALLBACK (ephy_autocompletion_data_changed_cb), ac);
+
+ g_signal_emit (ac, EphyAutocompletionSignals[EPHY_AUTOCOMPLETION_SOURCES_CHANGED], 0);
+}
+
+void
+ephy_autocompletion_set_key (EphyAutocompletion *ac,
+ const gchar *key)
+{
+ EphyAutocompletionPrivate *p = ac->priv;
+ guint i;
+ guint keylen = strlen (key);
+
+ if (strcmp (key, p->keys[0]))
+ {
+ GSList *li;
+ for (li = p->sources; li; li = li->next)
+ {
+ ephy_autocompletion_source_set_basic_key
+ (EPHY_AUTOCOMPLETION_SOURCE (li->data), key);
+ }
+ }
+
+ if (keylen >= p->key_lengths[0]
+ && !strncmp (p->keys[0], key, p->key_lengths[0]))
+ {
+ if (!strcmp (key, p->keys[0]))
+ {
+ return;
+ }
+ if (p->status != GAS_NEEDS_FULL_UPDATE)
+ {
+ p->status = GAS_NEEDS_REFINE;
+ }
+ if (p->common_prefix)
+ {
+ if (strncmp (p->common_prefix, key, keylen))
+ {
+ g_free (p->common_prefix);
+ p->common_prefix = NULL;
+ }
+ }
+ }
+ else
+ {
+ p->status = GAS_NEEDS_FULL_UPDATE;
+ g_free (p->common_prefix);
+ p->common_prefix = NULL;
+ }
+
+ for (i = 0; p->prefixes[i]; ++i)
+ {
+ g_free (p->keys[i]);
+ p->keys[i] = g_strconcat (p->prefixes[i], key, NULL);
+ p->key_lengths[i] = keylen + p->prefix_lengths[i];
+ }
+
+}
+
+gchar *
+ephy_autocompletion_get_common_prefix (EphyAutocompletion *ac)
+{
+ EphyAutocompletionPrivate *p = ac->priv;
+ ephy_autocompletion_update_matches (ac);
+ if (!p->common_prefix)
+ {
+ guint common_length = 0;
+ guint i;
+#ifdef DEBUG_TIME
+ GTimer *timer = g_timer_new ();
+ g_timer_start (timer);
+#endif
+ for (i = 0; i < p->matches.num_matches; i++)
+ {
+ EphyAutocompletionMatch *mi = &p->matches.array[i];
+ const gchar *realmatch = mi->title + mi->offset;
+ if (!p->common_prefix)
+ {
+ p->common_prefix = g_strdup (realmatch);
+ common_length = strlen (p->common_prefix);
+ continue;
+ }
+ else if (!strncmp (realmatch, p->common_prefix, common_length))
+ {
+ continue;
+ }
+ else
+ {
+ common_length = 0;
+ while (realmatch[common_length]
+ && realmatch[common_length] == p->common_prefix[common_length])
+ {
+ ++common_length;
+ }
+ g_free (p->common_prefix);
+ p->common_prefix = g_strndup (realmatch, common_length);
+ }
+ }
+#ifdef DEBUG_TIME
+ DEBUG_MSG (("AC: %f elapsed calculating common prefix\n", g_timer_elapsed (timer, NULL)));
+ g_timer_destroy (timer);
+#endif
+ }
+ return g_strdup (p->common_prefix);
+}
+
+const EphyAutocompletionMatch *
+ephy_autocompletion_get_matches (EphyAutocompletion *ac)
+{
+ ephy_autocompletion_update_matches (ac);
+ return ac->priv->matches.array;
+}
+
+const EphyAutocompletionMatch *
+ephy_autocompletion_get_matches_sorted_by_score (EphyAutocompletion *ac,
+ gboolean *changed)
+{
+ *changed = ephy_autocompletion_sort_by_score (ac);
+ return ac->priv->matches.array;
+}
+
+guint
+ephy_autocompletion_get_num_matches (EphyAutocompletion *ac)
+{
+ ephy_autocompletion_update_matches (ac);
+
+ return ac->priv->matches.num_matches;
+}
+
+guint
+ephy_autocompletion_get_num_action_matches (EphyAutocompletion *ac)
+{
+ return ac->priv->matches.num_matches -
+ ac->priv->matches.num_action_matches;
+}
+
+static void
+ephy_autocompletion_refine_matches (EphyAutocompletion *ac)
+{
+ EphyAutocompletionPrivate *p = ac->priv;
+ ACMatchArray oldmatches = p->matches;
+ ACMatchArray newmatches;
+ guint i;
+ gchar *key0 = p->keys[0];
+ guint key0l = p->key_lengths[0];
+#ifdef DEBUG_TIME
+ GTimer *timer = g_timer_new ();
+#endif
+ DEBUG_MSG (("AC: refining\n"));
+
+#ifdef DEBUG_TIME
+ g_timer_start (timer);
+#endif
+ acma_init (&newmatches);
+
+ p->changed = FALSE;
+
+ for (i = 0; i < oldmatches.num_matches; i++)
+ {
+ EphyAutocompletionMatch *mi = &oldmatches.array[i];
+ if (mi->is_action ||
+ (mi->substring && g_strrstr (mi->match, p->keys[0])) ||
+ !strncmp (key0, mi->title + mi->offset, key0l))
+ {
+ acma_append (&newmatches, mi, mi->is_action);
+ }
+ else
+ {
+ p->changed = TRUE;
+ }
+ }
+
+ acma_destroy (&oldmatches);
+ p->matches = newmatches;
+
+#ifdef DEBUG_TIME
+ DEBUG_MSG (("AC: %f elapsed refining\n", g_timer_elapsed (timer, NULL)));
+ g_timer_destroy (timer);
+#endif
+ DEBUG_MSG (("AC: %d matches\n", p->matches.num_matches));
+}
+
+static void
+ephy_autocompletion_update_matches (EphyAutocompletion *ac)
+{
+ EphyAutocompletionPrivate *p = ac->priv;
+ if (p->status == GAS_UPDATED)
+ {
+ return;
+ }
+ if (p->status == GAS_NEEDS_FULL_UPDATE)
+ {
+ ephy_autocompletion_update_matches_full (ac);
+ }
+ if (p->status == GAS_NEEDS_REFINE)
+ {
+ /* FIXME we do full update for now */
+ ephy_autocompletion_refine_matches (ac);
+ }
+
+ g_free (p->common_prefix);
+ p->common_prefix = NULL;
+ p->status = GAS_UPDATED;
+}
+
+static void
+ephy_autocompletion_update_matches_full_item (EphyAutocompletionSource *source,
+ const char *item,
+ const char *title,
+ const char *target,
+ gboolean is_action,
+ gboolean substring,
+ guint32 score,
+ EphyAutocompletionPrivate *p)
+{
+ if (is_action ||
+ (substring && g_strrstr (item, p->keys[0])))
+ {
+ EphyAutocompletionMatch m;
+ m.match = item;
+ m.title = title;
+ m.target = target;
+ m.is_action = is_action;
+ m.substring = substring;
+ m.offset = 0;
+ m.score = score;
+ acma_append (&p->matches, &m, is_action);
+ }
+ else
+ {
+ guint i;
+ for (i = 0; p->keys[i]; ++i)
+ {
+ if (!strncmp (item, p->keys[i], p->key_lengths[i]))
+ {
+ EphyAutocompletionMatch m;
+ m.match = item;
+ m.title = title;
+ m.target = target;
+ m.is_action = is_action;
+ m.substring = substring;
+ m.offset = p->prefix_lengths[i];
+ m.score = score;
+ acma_append (&p->matches, &m, is_action);
+ }
+ }
+ }
+}
+
+static void
+ephy_autocompletion_update_matches_full (EphyAutocompletion *ac)
+{
+ EphyAutocompletionPrivate *p = ac->priv;
+ GSList *li;
+#ifdef DEBUG_TIME
+ GTimer *timer = g_timer_new ();
+#endif
+
+ DEBUG_MSG (("AC: fully updating\n"));
+ ephy_autocompletion_reset (ac);
+
+#ifdef DEBUG_TIME
+ g_timer_start (timer);
+#endif
+ for (li = p->sources; li; li = li->next)
+ {
+ EphyAutocompletionSource *s = EPHY_AUTOCOMPLETION_SOURCE (li->data);
+ g_assert (s);
+ ephy_autocompletion_source_foreach (s, p->keys[0],
+ (EphyAutocompletionSourceForeachFunc)
+ ephy_autocompletion_update_matches_full_item,
+ p);
+ }
+#ifdef DEBUG_TIME
+ DEBUG_MSG (("AC: %f elapsed fully updating\n", g_timer_elapsed (timer, NULL)));
+ g_timer_destroy (timer);
+#endif
+
+ p->sorted = FALSE;
+ p->changed = TRUE;
+
+ DEBUG_MSG (("AC: %d matches, fully updated\n", p->matches.num_matches));
+}
+
+static gint
+ephy_autocompletion_compare_scores (EphyAutocompletionMatch *a, EphyAutocompletionMatch *b)
+{
+ /* higher scores first */
+ return b->score - a->score;
+}
+
+static gint
+ephy_autocompletion_compare_scores_and_alpha (EphyAutocompletionMatch *a, EphyAutocompletionMatch *b)
+{
+ if (a->score == b->score)
+ {
+ return strcmp (a->title, b->title);
+ }
+ else
+ {
+ /* higher scores first */
+ return b->score - a->score;
+ }
+}
+
+static gboolean
+ephy_autocompletion_sort_by_score (EphyAutocompletion *ac)
+{
+ EphyAutocompletionPrivate *p = ac->priv;
+#ifdef DEBUG_TIME
+ GTimer *timer;
+#endif
+ gint (*comparer) (EphyAutocompletionMatch *m1, EphyAutocompletionMatch *m2);
+
+ if (p->sort_alpha)
+ {
+ comparer = ephy_autocompletion_compare_scores_and_alpha;
+ }
+ else
+ {
+ comparer = ephy_autocompletion_compare_scores;
+ }
+
+ ephy_autocompletion_update_matches (ac);
+ if (p->changed == FALSE) return FALSE;
+
+ DEBUG_MSG (("AC: sorting\n"));
+#ifdef DEBUG_TIME
+ timer = g_timer_new ();
+ g_timer_start (timer);
+#endif
+ if (p->matches.num_matches > 0)
+ {
+ qsort (p->matches.array, p->matches.num_matches,
+ sizeof (EphyAutocompletionMatch),
+ (void *) comparer);
+ }
+
+ p->sorted = TRUE;
+
+#ifdef DEBUG_TIME
+ DEBUG_MSG (("AC: %f elapsed sorting by score\n", g_timer_elapsed (timer, NULL)));
+ g_timer_destroy (timer);
+#endif
+ return TRUE;
+}
+
+static void
+ephy_autocompletion_data_changed_cb (EphyAutocompletionSource *s,
+ EphyAutocompletion *ac)
+{
+ DEBUG_MSG (("AC: data changed, reseting\n"));
+ ephy_autocompletion_reset (ac);
+
+ g_signal_emit (ac, EphyAutocompletionSignals[EPHY_AUTOCOMPLETION_SOURCES_CHANGED], 0);
+}
+
+void
+ephy_autocompletion_set_prefixes (EphyAutocompletion *ac,
+ const gchar **prefixes)
+{
+ EphyAutocompletionPrivate *p = ac->priv;
+ guint nprefixes = 0;
+ gchar *oldkey = g_strdup (p->keys[0]);
+ guint i;
+
+ /* count prefixes */
+ while (prefixes[nprefixes])
+ {
+ ++nprefixes;
+ }
+
+ nprefixes--;
+
+ g_strfreev (p->keys);
+ g_free (p->key_lengths);
+ g_strfreev (p->prefixes);
+ g_free (p->prefix_lengths);
+
+ p->prefixes = g_new0 (gchar *, nprefixes + 2);
+ p->prefix_lengths = g_new0 (guint, nprefixes + 2);
+ p->keys = g_new0 (gchar *, nprefixes + 2);
+ p->key_lengths = g_new0 (guint, nprefixes + 2);
+
+ p->prefixes[0] = g_strdup ("");
+ p->prefix_lengths[0] = 0;
+ p->keys[0] = oldkey;
+ p->key_lengths[0] = strlen (p->keys[0]);
+
+ for (i = 0; i < nprefixes; ++i)
+ {
+ p->prefixes[i + 1] = g_strdup (prefixes[i]);
+ p->prefix_lengths[i + 1] = strlen (prefixes[i]);
+ p->keys[i + 1] = g_strconcat (p->prefixes[i + 1], p->keys[0], NULL);
+ p->key_lengths[i + 1] = p->prefix_lengths[i + 1] + p->key_lengths[0];
+ }
+
+ p->nkeys = nprefixes;
+}
+
+
+/* ACMatchArray */
+
+static void
+acma_init (ACMatchArray *a)
+{
+ a->array = NULL;
+ a->array_size = 0;
+ a->num_matches = 0;
+}
+
+/**
+ * Does not free the struct itself, only its contents
+ */
+static void
+acma_destroy (ACMatchArray *a)
+{
+ g_free (a->array);
+ a->array = NULL;
+ a->array_size = 0;
+ a->num_matches = 0;
+ a->num_action_matches = 0;
+}
+
+static inline void
+acma_append (ACMatchArray *a,
+ EphyAutocompletionMatch *m,
+ gboolean action)
+{
+ if (a->array_size == a->num_matches)
+ {
+ acma_grow (a);
+ }
+
+ a->array[a->num_matches] = *m;
+ a->num_matches++;
+ if (action) a->num_action_matches++;
+}
+
+static void
+acma_grow (ACMatchArray *a)
+{
+ gint new_size;
+ EphyAutocompletionMatch *new_array;
+
+ new_size = a->array_size + ACMA_BASE_SIZE;
+ new_array = g_renew (EphyAutocompletionMatch, a->array, new_size);
+
+ a->array_size = new_size;
+ a->array = new_array;
+}
+
+
diff --git a/lib/ephy-autocompletion.h b/lib/ephy-autocompletion.h
new file mode 100644
index 000000000..06dcc71dc
--- /dev/null
+++ b/lib/ephy-autocompletion.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2002 Ricardo Fernández Pascual
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EPHY_AUTOCOMPLETION_H
+#define EPHY_AUTOCOMPLETION_H
+
+#include <glib-object.h>
+#include "ephy-autocompletion-source.h"
+
+G_BEGIN_DECLS
+
+/* object forward declarations */
+
+typedef struct _EphyAutocompletion EphyAutocompletion;
+typedef struct _EphyAutocompletionClass EphyAutocompletionClass;
+typedef struct _EphyAutocompletionPrivate EphyAutocompletionPrivate;
+typedef struct _EphyAutocompletionMatch EphyAutocompletionMatch;
+
+/**
+ * EphyAutocompletion object
+ */
+
+#define EPHY_TYPE_AUTOCOMPLETION (ephy_autocompletion_get_type())
+#define EPHY_AUTOCOMPLETION(object) (G_TYPE_CHECK_INSTANCE_CAST((object), \
+ EPHY_TYPE_AUTOCOMPLETION,\
+ EphyAutocompletion))
+#define EPHY_AUTOCOMPLETION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), \
+ EPHY_TYPE_AUTOCOMPLETION,\
+ EphyAutocompletionClass))
+#define EPHY_IS_AUTOCOMPLETION(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), \
+ EPHY_TYPE_AUTOCOMPLETION))
+#define EPHY_IS_AUTOCOMPLETION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), \
+ EPHY_TYPE_AUTOCOMPLETION))
+#define EPHY_AUTOCOMPLETION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), \
+ EPHY_TYPE_AUTOCOMPLETION,\
+ EphyAutocompletionClass))
+
+struct _EphyAutocompletionClass
+{
+ GObjectClass parent_class;
+
+ /* signals */
+ void (*sources_changed) (EphyAutocompletion *ac);
+};
+
+/* Remember: fields are public read-only */
+struct _EphyAutocompletion
+{
+ GObject parent_object;
+
+ EphyAutocompletionPrivate *priv;
+};
+
+struct _EphyAutocompletionMatch
+{
+ const char *match;
+ const char *title;
+ const char *target;
+ guint offset;
+ gint32 score;
+ gboolean is_action;
+ gboolean substring;
+};
+
+/* this is a set of usual prefixes for web browsing */
+#define EPHY_AUTOCOMPLETION_USUAL_WEB_PREFIXES \
+ "http://www.", \
+ "http://", \
+ "https://www.", \
+ "https://", \
+ "file://", \
+ "www."
+
+GType ephy_autocompletion_get_type (void);
+EphyAutocompletion * ephy_autocompletion_new (void);
+void ephy_autocompletion_add_source (EphyAutocompletion *ac,
+ EphyAutocompletionSource *s);
+void ephy_autocompletion_set_prefixes (EphyAutocompletion *ac,
+ const gchar **prefixes);
+void ephy_autocompletion_set_key (EphyAutocompletion *ac,
+ const gchar *key);
+gchar * ephy_autocompletion_get_common_prefix (EphyAutocompletion *ac);
+const EphyAutocompletionMatch *ephy_autocompletion_get_matches (EphyAutocompletion *ac);
+const EphyAutocompletionMatch *ephy_autocompletion_get_matches_sorted_by_score
+ (EphyAutocompletion *ac,
+ gboolean *changed);
+guint ephy_autocompletion_get_num_matches (EphyAutocompletion *ac);
+guint ephy_autocompletion_get_num_action_matches (EphyAutocompletion *ac);
+
+G_END_DECLS
+
+#endif
diff --git a/lib/ephy-bonobo-extensions.c b/lib/ephy-bonobo-extensions.c
new file mode 100644
index 000000000..e40b377cd
--- /dev/null
+++ b/lib/ephy-bonobo-extensions.c
@@ -0,0 +1,679 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+
+/* gul-bonobo-extensions.c - implementation of new functions that conceptually
+ belong in bonobo. Perhaps some of these will be
+ actually rolled into bonobo someday.
+
+ This file is based on nautilus-bonobo-extensions.c from
+ libnautilus-private.
+
+ Copyright (C) 2000, 2001 Eazel, Inc.
+
+ The Gnome Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The Gnome 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the Gnome Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Authors: John Sullivan <sullivan@eazel.com>
+ Darin Adler <darin@bentspoon.com>
+*/
+
+#include <config.h>
+
+#include "ephy-bonobo-extensions.h"
+#include "ephy-string.h"
+#include <string.h>
+
+#include <bonobo/bonobo-ui-util.h>
+#include <gtk/gtkmain.h>
+#include <libgnomevfs/gnome-vfs-utils.h>
+#include <bonobo/bonobo-control.h>
+
+typedef enum {
+ NUMBERED_MENU_ITEM_PLAIN,
+ NUMBERED_MENU_ITEM_TOGGLE,
+ NUMBERED_MENU_ITEM_RADIO
+} NumberedMenuItemType;
+
+void
+ephy_bonobo_set_accelerator (BonoboUIComponent *ui,
+ const char *path,
+ const char *accelerator)
+{
+ if (bonobo_ui_component_get_container (ui)) /* should not do this here... */
+ {
+ bonobo_ui_component_set_prop (ui, path, "accel", accelerator, NULL);
+ }
+}
+
+void
+ephy_bonobo_set_label (BonoboUIComponent *ui,
+ const char *path,
+ const char *label)
+{
+ if (bonobo_ui_component_get_container (ui)) /* should not do this here... */
+ {
+ bonobo_ui_component_set_prop (ui, path, "label", label, NULL);
+ }
+}
+
+void
+ephy_bonobo_set_tip (BonoboUIComponent *ui,
+ const char *path,
+ const char *tip)
+{
+ if (bonobo_ui_component_get_container (ui)) /* should not do this here... */
+ {
+ bonobo_ui_component_set_prop (ui, path, "tip", tip, NULL);
+ }
+}
+
+void
+ephy_bonobo_set_sensitive (BonoboUIComponent *ui,
+ const char *path,
+ gboolean sensitive)
+{
+ if (bonobo_ui_component_get_container (ui)) /* should not do this here... */
+ {
+ bonobo_ui_component_set_prop (ui, path, "sensitive", sensitive ? "1" : "0", NULL);
+ }
+}
+
+void
+ephy_bonobo_set_toggle_state (BonoboUIComponent *ui,
+ const char *path,
+ gboolean state)
+{
+ if (bonobo_ui_component_get_container (ui)) /* should not do this here... */
+ {
+ bonobo_ui_component_set_prop (ui, path, "state", state ? "1" : "0", NULL);
+ }
+}
+
+void
+ephy_bonobo_set_hidden (BonoboUIComponent *ui,
+ const char *path,
+ gboolean hidden)
+{
+ if (bonobo_ui_component_get_container (ui)) /* should not do this here... */
+ {
+ bonobo_ui_component_set_prop (ui, path, "hidden", hidden ? "1" : "0", NULL);
+ }
+}
+
+char *
+ephy_bonobo_get_label (BonoboUIComponent *ui,
+ const char *path)
+{
+ if (bonobo_ui_component_get_container (ui)) /* should not do this here... */
+ {
+ return bonobo_ui_component_get_prop (ui, path, "label", NULL);
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+gboolean
+ephy_bonobo_get_hidden (BonoboUIComponent *ui,
+ const char *path)
+{
+ char *value;
+ gboolean hidden;
+ CORBA_Environment ev;
+
+ g_return_val_if_fail (BONOBO_IS_UI_COMPONENT (ui), FALSE);
+ g_return_val_if_fail (path != NULL, FALSE);
+
+ CORBA_exception_init (&ev);
+ value = bonobo_ui_component_get_prop (ui, path, "hidden", &ev);
+ CORBA_exception_free (&ev);
+
+ if (value == NULL) {
+ /* No hidden attribute means not hidden. */
+ hidden = FALSE;
+ } else {
+ /* Anything other than "0" counts as TRUE */
+ hidden = strcmp (value, "0") != 0;
+ g_free (value);
+ }
+
+ return hidden;
+}
+
+static char *
+get_numbered_menu_item_name (guint index)
+{
+ return g_strdup_printf ("%u", index);
+}
+
+char *
+ephy_bonobo_get_numbered_menu_item_path (BonoboUIComponent *ui,
+ const char *container_path,
+ guint index)
+{
+ char *item_name;
+ char *item_path;
+
+ g_return_val_if_fail (BONOBO_IS_UI_COMPONENT (ui), NULL);
+ g_return_val_if_fail (container_path != NULL, NULL);
+
+ item_name = get_numbered_menu_item_name (index);
+ item_path = g_strconcat (container_path, "/", item_name, NULL);
+ g_free (item_name);
+
+ return item_path;
+}
+
+char *
+ephy_bonobo_get_numbered_menu_item_command (BonoboUIComponent *ui,
+ const char *container_path,
+ guint index)
+{
+ char *command_name;
+ char *path;
+
+ g_return_val_if_fail (BONOBO_IS_UI_COMPONENT (ui), NULL);
+ g_return_val_if_fail (container_path != NULL, NULL);
+
+ path = ephy_bonobo_get_numbered_menu_item_path (ui, container_path, index);
+ command_name = gnome_vfs_escape_string (path);
+ g_free (path);
+
+ return command_name;
+}
+
+guint
+ephy_bonobo_get_numbered_menu_item_index_from_command (const char *command)
+{
+ char *path;
+ char *index_string;
+ int index;
+ gboolean got_index;
+
+ path = gnome_vfs_unescape_string (command, NULL);
+ index_string = strrchr (path, '/');
+
+ if (index_string == NULL) {
+ got_index = FALSE;
+ } else {
+ got_index = ephy_str_to_int (index_string + 1, &index);
+ }
+ g_free (path);
+
+ g_return_val_if_fail (got_index, 0);
+
+ return index;
+}
+
+char *
+ephy_bonobo_get_numbered_menu_item_container_path_from_command (const char *command)
+{
+ char *path;
+ char *index_string;
+ char *container_path;
+
+ path = gnome_vfs_unescape_string (command, NULL);
+ index_string = strrchr (path, '/');
+
+ container_path = index_string == NULL
+ ? NULL
+ : g_strndup (path, index_string - path);
+ g_free (path);
+
+ return container_path;
+}
+
+static char *
+ephy_bonobo_add_numbered_menu_item_internal (BonoboUIComponent *ui,
+ const char *container_path,
+ guint index,
+ const char *label,
+ NumberedMenuItemType type,
+ GdkPixbuf *pixbuf,
+ const char *radio_group_name)
+{
+ char *xml_item, *xml_command;
+ char *command_name;
+ char *item_name, *pixbuf_data;
+ char *path;
+
+ g_assert (BONOBO_IS_UI_COMPONENT (ui));
+ g_assert (container_path != NULL);
+ g_assert (label != NULL);
+ g_assert (type == NUMBERED_MENU_ITEM_PLAIN || pixbuf == NULL);
+ g_assert (type == NUMBERED_MENU_ITEM_RADIO || radio_group_name == NULL);
+ g_assert (type != NUMBERED_MENU_ITEM_RADIO || radio_group_name != NULL);
+
+ item_name = get_numbered_menu_item_name (index);
+ command_name = ephy_bonobo_get_numbered_menu_item_command
+ (ui, container_path, index);
+
+ switch (type) {
+ case NUMBERED_MENU_ITEM_TOGGLE:
+ xml_item = g_strdup_printf ("<menuitem name=\"%s\" id=\"%s\" type=\"toggle\"/>\n",
+ item_name, command_name);
+ break;
+ case NUMBERED_MENU_ITEM_RADIO:
+ xml_item = g_strdup_printf ("<menuitem name=\"%s\" id=\"%s\" "
+ "type=\"radio\" group=\"%s\"/>\n",
+ item_name, command_name, radio_group_name);
+ break;
+ case NUMBERED_MENU_ITEM_PLAIN:
+ if (pixbuf != NULL) {
+ pixbuf_data = bonobo_ui_util_pixbuf_to_xml (pixbuf);
+ xml_item = g_strdup_printf ("<menuitem name=\"%s\" verb=\"%s\" "
+ "pixtype=\"pixbuf\" pixname=\"%s\"/>\n",
+ item_name, command_name, pixbuf_data);
+ g_free (pixbuf_data);
+ } else {
+ xml_item = g_strdup_printf ("<menuitem name=\"%s\" verb=\"%s\"/>\n",
+ item_name, command_name);
+ }
+ break;
+ default:
+ g_assert_not_reached ();
+ xml_item = NULL; /* keep compiler happy */
+ }
+
+ g_free (item_name);
+
+ bonobo_ui_component_set (ui, container_path, xml_item, NULL);
+
+ g_free (xml_item);
+
+ path = ephy_bonobo_get_numbered_menu_item_path (ui, container_path, index);
+ ephy_bonobo_set_label (ui, path, label);
+ g_free (path);
+
+ /* Make the command node here too, so callers can immediately set
+ * properties on it (otherwise it doesn't get created until some
+ * time later).
+ */
+ xml_command = g_strdup_printf ("<cmd name=\"%s\"/>\n", command_name);
+ bonobo_ui_component_set (ui, "/commands", xml_command, NULL);
+ g_free (xml_command);
+
+ g_free (command_name);
+
+ return item_name;
+}
+
+/* Add a menu item specified by number into a given path. Used for
+ * dynamically creating a related series of menu items. Each index
+ * must be unique (normal use is to call this in a loop, and
+ * increment the index for each item).
+ */
+void
+ephy_bonobo_add_numbered_menu_item (BonoboUIComponent *ui,
+ const char *container_path,
+ guint index,
+ const char *label,
+ GdkPixbuf *pixbuf)
+{
+ g_return_if_fail (BONOBO_IS_UI_COMPONENT (ui));
+ g_return_if_fail (container_path != NULL);
+ g_return_if_fail (label != NULL);
+
+ ephy_bonobo_add_numbered_menu_item_internal (ui, container_path, index, label,
+ NUMBERED_MENU_ITEM_PLAIN, pixbuf, NULL);
+}
+
+/* Add a menu item specified by number into a given path. Used for
+ * dynamically creating a related series of toggle menu items. Each index
+ * must be unique (normal use is to call this in a loop, and
+ * increment the index for each item).
+ */
+void
+ephy_bonobo_add_numbered_toggle_menu_item (BonoboUIComponent *ui,
+ const char *container_path,
+ guint index,
+ const char *label)
+{
+ g_return_if_fail (BONOBO_IS_UI_COMPONENT (ui));
+ g_return_if_fail (container_path != NULL);
+ g_return_if_fail (label != NULL);
+
+ ephy_bonobo_add_numbered_menu_item_internal (ui, container_path, index, label,
+ NUMBERED_MENU_ITEM_TOGGLE, NULL, NULL);
+}
+
+/* Add a menu item specified by number into a given path. Used for
+ * dynamically creating a related series of radio menu items. Each index
+ * must be unique (normal use is to call this in a loop, and
+ * increment the index for each item).
+ */
+void
+ephy_bonobo_add_numbered_radio_menu_item (BonoboUIComponent *ui,
+ const char *container_path,
+ guint index,
+ const char *label,
+ const char *radio_group_name)
+{
+ g_return_if_fail (BONOBO_IS_UI_COMPONENT (ui));
+ g_return_if_fail (container_path != NULL);
+ g_return_if_fail (label != NULL);
+
+ ephy_bonobo_add_numbered_menu_item_internal (ui, container_path, index, label,
+ NUMBERED_MENU_ITEM_RADIO, NULL, radio_group_name);
+}
+
+void
+ephy_bonobo_add_numbered_submenu (BonoboUIComponent *ui,
+ const char *container_path,
+ guint index,
+ const char *label,
+ GdkPixbuf *pixbuf)
+{
+ char *xml_string, *item_name, *pixbuf_data, *submenu_path, *command_name;
+
+ g_return_if_fail (BONOBO_IS_UI_COMPONENT (ui));
+ g_return_if_fail (container_path != NULL);
+ g_return_if_fail (label != NULL);
+ g_return_if_fail (pixbuf == NULL || GDK_IS_PIXBUF (pixbuf));
+
+ item_name = get_numbered_menu_item_name (index);
+ command_name = ephy_bonobo_get_numbered_menu_item_command (ui, container_path, index);
+
+ if (pixbuf != NULL) {
+ pixbuf_data = bonobo_ui_util_pixbuf_to_xml (pixbuf);
+ xml_string = g_strdup_printf ("<submenu name=\"%s\" pixtype=\"pixbuf\" pixname=\"%s\" "
+ "verb=\"%s\"/>\n",
+ item_name, pixbuf_data, command_name);
+ g_free (pixbuf_data);
+ } else {
+ xml_string = g_strdup_printf ("<submenu name=\"%s\" verb=\"%s\"/>\n", item_name,
+ command_name);
+ }
+
+ bonobo_ui_component_set (ui, container_path, xml_string, NULL);
+
+ g_free (xml_string);
+
+ submenu_path = ephy_bonobo_get_numbered_menu_item_path (ui, container_path, index);
+ ephy_bonobo_set_label (ui, submenu_path, label);
+ g_free (submenu_path);
+
+ g_free (item_name);
+ g_free (command_name);
+}
+
+void
+ephy_bonobo_add_numbered_submenu_no_verb (BonoboUIComponent *ui,
+ const char *container_path,
+ guint index,
+ const char *label,
+ GdkPixbuf *pixbuf)
+{
+ char *xml_string, *item_name, *pixbuf_data, *submenu_path;
+
+ g_return_if_fail (BONOBO_IS_UI_COMPONENT (ui));
+ g_return_if_fail (container_path != NULL);
+ g_return_if_fail (label != NULL);
+ g_return_if_fail (pixbuf == NULL || GDK_IS_PIXBUF (pixbuf));
+
+ item_name = get_numbered_menu_item_name (index);
+
+ if (pixbuf != NULL) {
+ pixbuf_data = bonobo_ui_util_pixbuf_to_xml (pixbuf);
+ xml_string = g_strdup_printf ("<submenu name=\"%s\" pixtype=\"pixbuf\" pixname=\"%s\" "
+ "/>\n",
+ item_name, pixbuf_data);
+ g_free (pixbuf_data);
+ } else {
+ xml_string = g_strdup_printf ("<submenu name=\"%s\"/>\n", item_name);
+ }
+
+ bonobo_ui_component_set (ui, container_path, xml_string, NULL);
+
+ g_free (xml_string);
+
+ submenu_path = ephy_bonobo_get_numbered_menu_item_path (ui, container_path, index);
+ ephy_bonobo_set_label (ui, submenu_path, label);
+ g_free (submenu_path);
+
+ g_free (item_name);
+}
+
+void
+ephy_bonobo_add_submenu (BonoboUIComponent *ui,
+ const char *path,
+ const char *label,
+ GdkPixbuf *pixbuf)
+{
+ char *xml_string, *name, *pixbuf_data, *submenu_path;
+
+ g_return_if_fail (BONOBO_IS_UI_COMPONENT (ui));
+ g_return_if_fail (path != NULL);
+ g_return_if_fail (label != NULL);
+ g_return_if_fail (pixbuf == NULL || GDK_IS_PIXBUF (pixbuf));
+
+ /* Labels may contain characters that are illegal in names. So
+ * we create the name by URI-encoding the label.
+ */
+ name = gnome_vfs_escape_string (label);
+
+ if (pixbuf != NULL) {
+ pixbuf_data = bonobo_ui_util_pixbuf_to_xml (pixbuf);
+ xml_string = g_strdup_printf ("<submenu name=\"%s\" pixtype=\"pixbuf\" pixname=\"%s\"/>\n",
+ name, pixbuf_data);
+ g_free (pixbuf_data);
+ } else {
+ xml_string = g_strdup_printf ("<submenu name=\"%s\"/>\n", name);
+ }
+
+ bonobo_ui_component_set (ui, path, xml_string, NULL);
+
+ g_free (xml_string);
+
+ submenu_path = g_strconcat (path, "/", name, NULL);
+ ephy_bonobo_set_label (ui, submenu_path, label);
+ g_free (submenu_path);
+
+ g_free (name);
+}
+
+void
+ephy_bonobo_add_menu_separator (BonoboUIComponent *ui, const char *path)
+{
+ static gint hack = 0;
+ gchar *xml;
+
+ g_return_if_fail (BONOBO_IS_UI_COMPONENT (ui));
+ g_return_if_fail (path != NULL);
+
+ xml = g_strdup_printf ("<separator name=\"sep%d\"/>", ++hack);
+ bonobo_ui_component_set (ui, path, xml, NULL);
+ g_free (xml);
+}
+
+static void
+remove_commands (BonoboUIComponent *ui, const char *container_path)
+{
+ BonoboUINode *path_node;
+ BonoboUINode *child_node;
+ char *verb_name;
+ char *id_name;
+
+ path_node = bonobo_ui_component_get_tree (ui, container_path, TRUE, NULL);
+ if (path_node == NULL) {
+ return;
+ }
+
+ bonobo_ui_component_freeze (ui, NULL);
+
+ for (child_node = bonobo_ui_node_children (path_node);
+ child_node != NULL;
+ child_node = bonobo_ui_node_next (child_node)) {
+ verb_name = bonobo_ui_node_get_attr (child_node, "verb");
+ if (verb_name != NULL) {
+ bonobo_ui_component_remove_verb (ui, verb_name);
+ bonobo_ui_node_free_string (verb_name);
+ } else {
+ /* Only look for an id if there's no verb */
+ id_name = bonobo_ui_node_get_attr (child_node, "id");
+ if (id_name != NULL) {
+ bonobo_ui_component_remove_listener (ui, id_name);
+ bonobo_ui_node_free_string (id_name);
+ }
+ }
+ }
+
+ bonobo_ui_component_thaw (ui, NULL);
+
+ bonobo_ui_node_free (path_node);
+}
+
+/**
+ * ephy_bonobo_remove_menu_items_and_verbs
+ *
+ * Removes all menu items contained in a menu or placeholder, and
+ * their verbs.
+ *
+ * @uih: The BonoboUIHandler for this menu item.
+ * @container_path: The standard bonobo-style path specifier for this placeholder or submenu.
+ */
+void
+ephy_bonobo_remove_menu_items_and_commands (BonoboUIComponent *ui,
+ const char *container_path)
+{
+ char *remove_wildcard;
+
+ g_return_if_fail (BONOBO_IS_UI_COMPONENT (ui));
+ g_return_if_fail (container_path != NULL);
+
+ remove_commands (ui, container_path);
+
+ /* For speed, remove menu items themselves all in one fell swoop,
+ * though we removed the verbs one-by-one.
+ */
+ remove_wildcard = g_strdup_printf ("%s/*", container_path);
+ bonobo_ui_component_rm (ui, remove_wildcard, NULL);
+ g_free (remove_wildcard);
+}
+
+/* Call to set the user-visible label of a menu item to a string
+ * containing an underscore accelerator. The underscore is stripped
+ * off before setting the label of the command, because pop-up menu
+ * and toolbar button labels shouldn't have the underscore.
+ */
+void
+ephy_bonobo_set_label_for_menu_item_and_command (BonoboUIComponent *ui,
+ const char *menu_item_path,
+ const char *command_path,
+ const char *label_with_underscore)
+{
+ char *label_no_underscore;
+
+ g_return_if_fail (BONOBO_IS_UI_COMPONENT (ui));
+ g_return_if_fail (menu_item_path != NULL);
+ g_return_if_fail (command_path != NULL);
+ g_return_if_fail (label_with_underscore != NULL);
+
+ label_no_underscore = ephy_str_strip_chr (label_with_underscore, '_');
+ ephy_bonobo_set_label (ui,
+ menu_item_path,
+ label_with_underscore);
+ ephy_bonobo_set_label (ui,
+ command_path,
+ label_no_underscore);
+
+ g_free (label_no_underscore);
+}
+
+gchar *
+ephy_bonobo_add_dockitem (BonoboUIComponent *uic,
+ const char *name,
+ int band_num)
+{
+ gchar *xml;
+ gchar *sname;
+ gchar *path;
+
+ sname = gnome_vfs_escape_string (name);
+ xml = g_strdup_printf ("<dockitem name=\"%s\" band_num=\"%d\" "
+ "config=\"0\" behavior=\"exclusive\"/>",
+ sname, band_num);
+ path = g_strdup_printf ("/%s", sname);
+ bonobo_ui_component_set (uic, "", xml, NULL);
+
+ g_free (sname);
+ g_free (xml);
+ return path;
+}
+
+BonoboControl *
+ephy_bonobo_add_numbered_control (BonoboUIComponent *uic, GtkWidget *w,
+ guint index, const char *container_path)
+{
+ BonoboControl *control;
+ char *xml_string, *item_name, *control_path;
+
+ g_return_val_if_fail (BONOBO_IS_UI_COMPONENT (uic), NULL);
+ g_return_val_if_fail (container_path != NULL, NULL);
+
+ item_name = get_numbered_menu_item_name (index);
+ xml_string = g_strdup_printf ("<control name=\"%s\"/>", item_name);
+
+ bonobo_ui_component_set (uic, container_path, xml_string, NULL);
+
+ g_free (xml_string);
+
+ control_path = ephy_bonobo_get_numbered_menu_item_path (uic, container_path, index);
+
+ control = bonobo_control_new (w);
+ bonobo_ui_component_object_set (uic, control_path, BONOBO_OBJREF (control), NULL);
+ bonobo_object_unref (control);
+
+ g_free (control_path);
+ g_free (item_name);
+
+ return control;
+}
+
+void
+ephy_bonobo_replace_path (BonoboUIComponent *uic, const gchar *path_src,
+ const char *path_dst)
+{
+ BonoboUINode *node;
+ const char *name;
+ char *path_dst_folder;
+
+ name = strrchr (path_dst, '/');
+ g_return_if_fail (name != NULL);
+ path_dst_folder = g_strndup (path_dst, name - path_dst);
+ name++;
+
+ node = bonobo_ui_component_get_tree (uic, path_src, TRUE, NULL);
+ bonobo_ui_node_set_attr (node, "name", name);
+
+ ephy_bonobo_clear_path (uic, path_dst);
+
+ bonobo_ui_component_set_tree (uic, path_dst_folder, node, NULL);
+
+ g_free (path_dst_folder);
+ bonobo_ui_node_free (node);
+}
+
+void
+ephy_bonobo_clear_path (BonoboUIComponent *uic,
+ const gchar *path)
+{
+ if (bonobo_ui_component_path_exists (uic, path, NULL))
+ {
+ char *remove_wildcard = g_strdup_printf ("%s/*", path);
+ bonobo_ui_component_rm (uic, remove_wildcard, NULL);
+ g_free (remove_wildcard);
+ }
+}
diff --git a/lib/ephy-bonobo-extensions.h b/lib/ephy-bonobo-extensions.h
new file mode 100644
index 000000000..86bb977f9
--- /dev/null
+++ b/lib/ephy-bonobo-extensions.h
@@ -0,0 +1,121 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+
+/* gul-bonobo-extensions.h - interface for new functions that conceptually
+ belong in bonobo. Perhaps some of these will be
+ actually rolled into bonobo someday.
+
+
+ This file is based on nautilus-bonobo-extensions.h from
+ libnautilus-private.
+
+
+ Copyright (C) 2000 Eazel, Inc.
+
+ The Gnome Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The Gnome 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the Gnome Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Author: John Sullivan <sullivan@eazel.com>
+*/
+
+#ifndef EPHY_BONOBO_EXTENSIONS_H
+#define EPHY_BONOBO_EXTENSIONS_H
+
+#include <bonobo/bonobo-ui-component.h>
+#include <bonobo/bonobo-control.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gtk/gtkwidget.h>
+
+void ephy_bonobo_set_accelerator (BonoboUIComponent *ui,
+ const char *path,
+ const char *accelerator);
+char *ephy_bonobo_get_label (BonoboUIComponent *ui,
+ const char *path);
+void ephy_bonobo_set_label (BonoboUIComponent *ui,
+ const char *path,
+ const char *label);
+void ephy_bonobo_set_tip (BonoboUIComponent *ui,
+ const char *path,
+ const char *tip);
+void ephy_bonobo_set_sensitive (BonoboUIComponent *ui,
+ const char *path,
+ gboolean sensitive);
+void ephy_bonobo_set_toggle_state (BonoboUIComponent *ui,
+ const char *path,
+ gboolean state);
+void ephy_bonobo_set_hidden (BonoboUIComponent *ui,
+ const char *path,
+ gboolean hidden);
+gboolean ephy_bonobo_get_hidden (BonoboUIComponent *ui,
+ const char *path);
+void ephy_bonobo_add_numbered_menu_item (BonoboUIComponent *ui,
+ const char *container_path,
+ guint index,
+ const char *label,
+ GdkPixbuf *pixbuf);
+void ephy_bonobo_add_numbered_toggle_menu_item (BonoboUIComponent *ui,
+ const char *container_path,
+ guint index,
+ const char *label);
+void ephy_bonobo_add_numbered_radio_menu_item (BonoboUIComponent *ui,
+ const char *container_path,
+ guint index,
+ const char *label,
+ const char *radio_group_name);
+char *ephy_bonobo_get_numbered_menu_item_command (BonoboUIComponent *ui,
+ const char *container_path,
+ guint index);
+char *ephy_bonobo_get_numbered_menu_item_path (BonoboUIComponent *ui,
+ const char *container_path,
+ guint index);
+guint ephy_bonobo_get_numbered_menu_item_index_from_command (const char *command);
+char *ephy_bonobo_get_numbered_menu_item_container_path_from_command (const char *command);
+void ephy_bonobo_add_submenu (BonoboUIComponent *ui,
+ const char *container_path,
+ const char *label,
+ GdkPixbuf *pixbuf);
+void ephy_bonobo_add_numbered_submenu (BonoboUIComponent *ui,
+ const char *container_path,
+ guint index,
+ const char *label,
+ GdkPixbuf *pixbuf);
+void ephy_bonobo_add_numbered_submenu_no_verb (BonoboUIComponent *ui,
+ const char *container_path,
+ guint index,
+ const char *label,
+ GdkPixbuf *pixbuf);
+void ephy_bonobo_add_menu_separator (BonoboUIComponent *ui,
+ const char *path);
+void ephy_bonobo_remove_menu_items_and_commands (BonoboUIComponent *ui,
+ const char *container_path);
+void ephy_bonobo_set_label_for_menu_item_and_command (BonoboUIComponent *ui,
+ const char *menu_item_path,
+ const char *command_path,
+ const char *label_with_underscore);
+void ephy_bonobo_set_icon (BonoboUIComponent *ui,
+ const char *path,
+ const char *icon_relative_path);
+gchar *ephy_bonobo_add_dockitem (BonoboUIComponent *uic,
+ const char *name,
+ int band_num);
+BonoboControl *ephy_bonobo_add_numbered_control (BonoboUIComponent *uic,
+ GtkWidget *w, guint index,
+ const char *path);
+void ephy_bonobo_clear_path (BonoboUIComponent *uic,
+ const gchar *path);
+void ephy_bonobo_replace_path (BonoboUIComponent *uic,
+ const gchar *path_src,
+ const char *path_dst);
+
+#endif /* EPHY_BONOBO_EXTENSIONS_H */
diff --git a/lib/ephy-dialog.c b/lib/ephy-dialog.c
new file mode 100644
index 000000000..8c8344dda
--- /dev/null
+++ b/lib/ephy-dialog.c
@@ -0,0 +1,943 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "ephy-dialog.h"
+#include "ephy-glade.h"
+#include "ephy-state.h"
+#include "ephy-prefs-utils.h"
+#include "ephy-gui.h"
+
+#include <string.h>
+#include <gtk/gtktogglebutton.h>
+
+static void
+ephy_dialog_class_init (EphyDialogClass *klass);
+static void
+ephy_dialog_init (EphyDialog *window);
+static void
+ephy_dialog_finalize (GObject *object);
+static void
+ephy_dialog_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void
+ephy_dialog_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+
+static void
+ephy_dialog_set_parent (EphyDialog *dialog,
+ GtkWidget *parent);
+
+static void
+impl_construct (EphyDialog *dialog,
+ const EphyDialogProperty *properties,
+ const char *file,
+ const char *name);
+
+static void
+impl_destruct (EphyDialog *dialog);
+
+static GtkWidget *
+impl_get_control (EphyDialog *dialog,
+ int property_id);
+static void
+impl_get_value (EphyDialog *dialog,
+ int property_id,
+ GValue *value);
+static gint
+impl_run (EphyDialog *dialog);
+static void
+impl_show (EphyDialog *dialog);
+void
+ephy_dialog_destroy_cb (GtkWidget *widget,
+ EphyDialog *dialog);
+
+enum
+{
+ PROP_0,
+ PROP_PARENT_WINDOW,
+ PROP_MODAL
+};
+
+typedef enum
+{
+ PT_TOGGLEBUTTON,
+ PT_RADIOBUTTON,
+ PT_SPINBUTTON,
+ PT_COLOR,
+ PT_OPTIONMENU,
+ PT_ENTRY,
+ PT_UNKNOWN
+} PrefType;
+
+typedef struct
+{
+ int id;
+ GtkWidget *widget;
+ const char *pref;
+ int *sg;
+ PropertyType type;
+} PropertyInfo;
+
+struct EphyDialogPrivate
+{
+ GtkWidget *parent;
+ GtkWidget *dialog;
+ GtkWidget *container;
+ PropertyInfo *props;
+ gboolean modal;
+ char *name;
+
+ int spin_item_id;
+ GTimer *spin_timer;
+};
+
+#define SPIN_DELAY 0.20
+
+static GObjectClass *parent_class = NULL;
+
+GType
+ephy_dialog_get_type (void)
+{
+ static GType ephy_dialog_type = 0;
+
+ if (ephy_dialog_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (EphyDialogClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) ephy_dialog_class_init,
+ NULL,
+ NULL, /* class_data */
+ sizeof (EphyDialog),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) ephy_dialog_init
+ };
+
+ ephy_dialog_type = g_type_register_static (G_TYPE_OBJECT,
+ "EphyDialog",
+ &our_info, 0);
+ }
+
+ return ephy_dialog_type;
+}
+
+static void
+ephy_dialog_class_init (EphyDialogClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = ephy_dialog_finalize;
+ object_class->set_property = ephy_dialog_set_property;
+ object_class->get_property = ephy_dialog_get_property;
+
+ klass->construct = impl_construct;
+ klass->get_control = impl_get_control;
+ klass->get_value = impl_get_value;
+ klass->run = impl_run;
+ klass->show = impl_show;
+ klass->destruct = impl_destruct;
+
+ g_object_class_install_property (object_class,
+ PROP_PARENT_WINDOW,
+ g_param_spec_object ("ParentWindow",
+ "ParentWindow",
+ "Parent window",
+ GTK_TYPE_WIDGET,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (object_class,
+ PROP_MODAL,
+ g_param_spec_boolean ("Modal",
+ "Modal",
+ "Modal dialog",
+ FALSE,
+ G_PARAM_READWRITE));
+}
+
+static PrefType
+get_pref_type_from_widget (GtkWidget *widget)
+{
+ if (GTK_IS_OPTION_MENU (widget))
+ {
+ return PT_OPTIONMENU;
+ }
+ else if (GTK_IS_SPIN_BUTTON (widget))
+ {
+ return PT_SPINBUTTON;
+ }
+ else if (GTK_IS_RADIO_BUTTON (widget))
+ {
+ return PT_RADIOBUTTON;
+ }
+ else if (GTK_IS_TOGGLE_BUTTON (widget))
+ {
+ return PT_TOGGLEBUTTON;
+ }
+ else if (GTK_IS_ENTRY (widget))
+ {
+ return PT_ENTRY;
+ }
+ else if (GNOME_IS_COLOR_PICKER (widget))
+ {
+ return PT_COLOR;
+ }
+
+ return PT_UNKNOWN;
+}
+
+static int *
+set_controls_sensitivity (EphyDialog *dialog,
+ int *sg, gboolean s)
+{
+ GtkWidget *widget;
+
+ while (*sg != SY_END_GROUP)
+ {
+ widget = ephy_dialog_get_control (dialog,
+ *sg);
+ gtk_widget_set_sensitive (widget, s);
+
+ sg++;
+ }
+
+ return sg;
+}
+
+static void
+prefs_set_group_sensitivity (GtkWidget *widget,
+ PrefType type, int *sg)
+{
+ int group = -1;
+ EphyDialog *dialog;
+ int i = 0;
+
+ if (sg == NULL) return;
+
+ dialog = EPHY_DIALOG (g_object_get_data
+ (G_OBJECT(widget), "dialog"));
+
+ if (GTK_IS_RADIO_BUTTON (widget))
+ {
+ group = ephy_gui_gtk_radio_button_get
+ (GTK_RADIO_BUTTON(widget));
+ }
+ else if (GTK_IS_TOGGLE_BUTTON (widget))
+ {
+ group = !gtk_toggle_button_get_active
+ (GTK_TOGGLE_BUTTON(widget));
+ }
+ else
+ {
+ g_assert (FALSE);
+ }
+
+ while (*sg != SY_END)
+ {
+ if ((*sg == SY_BEGIN_GROUP) ||
+ (*sg == SY_BEGIN_GROUP_INVERSE))
+ {
+ gboolean b;
+
+ b = (i == group);
+ if (*sg == SY_BEGIN_GROUP_INVERSE) b = !b;
+
+ sg++;
+ sg = set_controls_sensitivity
+ (dialog, sg, b);
+ }
+
+ i++;
+ sg++;
+ }
+}
+
+static void
+prefs_togglebutton_clicked_cb (GtkWidget *widget, PropertyInfo *pi)
+{
+ if (pi->type == PT_AUTOAPPLY)
+ {
+ ephy_pu_set_config_from_togglebutton (widget, pi->pref);
+ }
+
+ prefs_set_group_sensitivity (widget, pi->type, pi->sg);
+}
+
+static void
+prefs_radiobutton_clicked_cb (GtkWidget *widget, PropertyInfo *pi)
+{
+ if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(widget)))
+ {
+ return;
+ }
+
+ if (pi->type == PT_AUTOAPPLY)
+ {
+ ephy_pu_set_config_from_radiobuttongroup (widget, pi->pref);
+ }
+
+ prefs_set_group_sensitivity (widget, pi->type, pi->sg);
+}
+
+static gint
+prefs_spinbutton_timeout_cb (EphyDialog *dialog)
+{
+ PropertyInfo pi = dialog->priv->props[dialog->priv->spin_item_id];
+
+ /* timer still valid? */
+ if (dialog->priv->spin_timer == NULL)
+ {
+ return FALSE;
+ }
+
+ /* okay, we're ready to set */
+ if (g_timer_elapsed (dialog->priv->spin_timer, NULL) >= SPIN_DELAY)
+ {
+ /* kill off the timer */
+ g_timer_destroy (dialog->priv->spin_timer);
+ dialog->priv->spin_timer = NULL;
+
+ /* HACK update the spinbutton here so that the
+ * changes made directly in the entry are accepted
+ * and set in the pref. Otherwise the old value is used */
+ gtk_spin_button_update (GTK_SPIN_BUTTON(pi.widget));
+
+ /* set */
+ ephy_pu_set_config_from_spin_button (pi.widget,
+ pi.pref);
+
+ /* done now */
+ return FALSE;
+ }
+
+ /* call me again */
+ return TRUE;
+}
+
+static void
+prefs_spinbutton_changed_cb (GtkWidget *widget, PropertyInfo *pi)
+{
+ EphyDialog *dialog;
+
+ if (pi->type != PT_AUTOAPPLY) return;
+
+ dialog = EPHY_DIALOG (g_object_get_data
+ (G_OBJECT(widget), "dialog"));
+
+ dialog->priv->spin_item_id = pi->id;
+
+ /* destroy any existing timer */
+ if (dialog->priv->spin_timer != NULL)
+ {
+ g_timer_destroy (dialog->priv->spin_timer);
+ }
+
+ /* start the new one */
+ dialog->priv->spin_timer = g_timer_new();
+ g_timer_start (dialog->priv->spin_timer);
+ g_timeout_add (50, (GSourceFunc) prefs_spinbutton_timeout_cb,
+ dialog);
+}
+
+static void
+prefs_color_changed_cb (GtkWidget *widget, guint r, guint g,
+ guint b, guint a, const PropertyInfo *pi)
+{
+ if (pi->type == PT_AUTOAPPLY)
+ {
+ ephy_pu_set_config_from_color (widget, pi->pref);
+ }
+}
+
+static void
+prefs_entry_changed_cb (GtkWidget *widget, PropertyInfo *pi)
+{
+ if (pi->type == PT_AUTOAPPLY)
+ {
+ ephy_pu_set_config_from_editable (widget, pi->pref);
+ }
+}
+
+static void
+prefs_optionmenu_selected_cb (GtkWidget *widget, PropertyInfo *pi)
+{
+ if (pi->type == PT_AUTOAPPLY)
+ {
+ ephy_pu_set_config_from_optionmenu (widget, pi->pref);
+ }
+}
+
+static void
+prefs_connect_signals (EphyDialog *dialog)
+{
+ int i;
+ GSList *list;
+ PropertyInfo *props = dialog->priv->props;
+
+ for (i = 0; props[i].widget != NULL; i++)
+ {
+ PrefType type;
+ PropertyInfo *info;
+
+ if ((props[i].type != PT_AUTOAPPLY) &&
+ (props[i].sg == NULL))
+ continue;
+
+ info = &dialog->priv->props[i];
+ type = get_pref_type_from_widget
+ (dialog->priv->props[i].widget);
+
+ switch (type)
+ {
+ case PT_TOGGLEBUTTON:
+ g_object_set_data (G_OBJECT(info->widget), "dialog", dialog);
+ g_signal_connect (G_OBJECT (info->widget), "clicked",
+ G_CALLBACK(prefs_togglebutton_clicked_cb),
+ (gpointer)info);
+ break;
+ case PT_RADIOBUTTON:
+ list = gtk_radio_button_get_group
+ (GTK_RADIO_BUTTON(info->widget));
+ for (; list != NULL; list = list->next)
+ {
+ g_object_set_data (G_OBJECT(list->data),
+ "dialog", dialog);
+ g_signal_connect
+ (G_OBJECT (list->data), "clicked",
+ G_CALLBACK(prefs_radiobutton_clicked_cb),
+ (gpointer)info);
+ }
+ break;
+ case PT_SPINBUTTON:
+ g_object_set_data (G_OBJECT(info->widget), "dialog", dialog);
+ g_signal_connect (G_OBJECT (info->widget), "changed",
+ G_CALLBACK(prefs_spinbutton_changed_cb),
+ (gpointer)info);
+ break;
+ case PT_COLOR:
+ g_signal_connect (G_OBJECT (info->widget), "color_set",
+ G_CALLBACK(prefs_color_changed_cb),
+ (gpointer)info);
+ break;
+ case PT_OPTIONMENU:
+ g_signal_connect (G_OBJECT (info->widget),
+ "changed",
+ G_CALLBACK(prefs_optionmenu_selected_cb),
+ (gpointer)info);
+ break;
+ case PT_ENTRY:
+ g_signal_connect (G_OBJECT (info->widget), "changed",
+ G_CALLBACK(prefs_entry_changed_cb),
+ (gpointer)info);
+ break;
+ case PT_UNKNOWN:
+ break;
+ }
+ }
+}
+
+static void
+ephy_dialog_init (EphyDialog *dialog)
+{
+ dialog->priv = g_new0 (EphyDialogPrivate, 1);
+
+ dialog->priv->parent = NULL;
+ dialog->priv->dialog = NULL;
+ dialog->priv->props = NULL;
+ dialog->priv->spin_timer = NULL;
+ dialog->priv->name = NULL;
+}
+
+static void
+prefs_set_sensitivity (PropertyInfo *props)
+{
+ int i;
+
+ for (i=0 ; props[i].id >= 0; i++)
+ {
+ if (props[i].sg == NULL) continue;
+
+ g_return_if_fail (props[i].widget != NULL);
+
+ if (GTK_IS_RADIO_BUTTON(props[i].widget) ||
+ GTK_IS_TOGGLE_BUTTON(props[i].widget))
+ {
+ prefs_set_group_sensitivity (props[i].widget,
+ props[i].type,
+ props[i].sg);
+ }
+ }
+}
+
+static void
+load_props (PropertyInfo *props)
+{
+ int i;
+
+ for (i=0 ; props[i].id >= 0; i++)
+ {
+ if (props[i].pref == NULL) continue;
+
+ g_return_if_fail (props[i].widget != NULL);
+
+ if (GTK_IS_SPIN_BUTTON(props[i].widget))
+ {
+ ephy_pu_set_spin_button_from_config (props[i].widget,
+ props[i].pref);
+ }
+ else if (GTK_IS_RADIO_BUTTON(props[i].widget))
+ {
+ ephy_pu_set_radiobuttongroup_from_config (props[i].widget,
+ props[i].pref);
+ }
+ else if (GTK_IS_TOGGLE_BUTTON(props[i].widget))
+ {
+ ephy_pu_set_togglebutton_from_config (props[i].widget,
+ props[i].pref);
+ }
+ else if (GTK_IS_EDITABLE(props[i].widget))
+ {
+ ephy_pu_set_editable_from_config (props[i].widget,
+ props[i].pref);
+ }
+ else if (GTK_IS_OPTION_MENU(props[i].widget))
+ {
+ ephy_pu_set_optionmenu_from_config (props[i].widget,
+ props[i].pref);
+ }
+ else if (GNOME_IS_COLOR_PICKER(props[i].widget))
+ {
+ ephy_pu_set_color_from_config (props[i].widget,
+ props[i].pref);
+ }
+ }
+
+}
+
+static void
+save_props (PropertyInfo *props)
+{
+ int i;
+
+ for (i=0 ; props[i].id >= 0; i++)
+ {
+ if ((props[i].pref == NULL) ||
+ (props[i].type != PT_NORMAL)) continue;
+ g_return_if_fail (props[i].widget != NULL);
+
+ if (GTK_IS_SPIN_BUTTON(props[i].widget))
+ {
+ ephy_pu_set_config_from_spin_button (props[i].widget,
+ props[i].pref);
+ }
+ else if (GTK_IS_RADIO_BUTTON(props[i].widget))
+ {
+ ephy_pu_set_config_from_radiobuttongroup (props[i].widget,
+ props[i].pref);
+ }
+ else if (GTK_IS_TOGGLE_BUTTON(props[i].widget))
+ {
+ ephy_pu_set_config_from_togglebutton (props[i].widget,
+ props[i].pref);
+ }
+ else if (GTK_IS_EDITABLE(props[i].widget))
+ {
+ ephy_pu_set_config_from_editable (props[i].widget,
+ props[i].pref);
+ }
+ else if (GTK_IS_OPTION_MENU(props[i].widget))
+ {
+ ephy_pu_set_config_from_optionmenu (props[i].widget,
+ props[i].pref);
+ }
+ else if (GNOME_IS_COLOR_PICKER(props[i].widget))
+ {
+ ephy_pu_set_config_from_color (props[i].widget,
+ props[i].pref);
+ }
+ }
+}
+
+static void
+ephy_dialog_finalize (GObject *object)
+{
+ EphyDialog *dialog;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (IS_EPHY_DIALOG (object));
+
+ dialog = EPHY_DIALOG (object);
+
+ g_return_if_fail (dialog->priv != NULL);
+
+ if (dialog->priv->dialog)
+ {
+ ephy_dialog_destruct (dialog);
+ }
+
+ g_free (dialog->priv->name);
+ g_free (dialog->priv->props);
+ g_free (dialog->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+ephy_dialog_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EphyDialog *d = EPHY_DIALOG (object);
+
+ switch (prop_id)
+ {
+ case PROP_PARENT_WINDOW:
+ ephy_dialog_set_parent (d, g_value_get_object (value));
+ break;
+ case PROP_MODAL:
+ ephy_dialog_set_modal (d, g_value_get_boolean (value));
+ break;
+ }
+}
+
+static void
+ephy_dialog_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ EphyDialog *d = EPHY_DIALOG (object);
+
+ switch (prop_id)
+ {
+ case PROP_PARENT_WINDOW:
+ g_value_set_object (value, d->priv->parent);
+ break;
+ case PROP_MODAL:
+ g_value_set_boolean (value, d->priv->modal);
+ }
+}
+
+static void
+ephy_dialog_set_parent (EphyDialog *dialog,
+ GtkWidget *parent)
+{
+ g_return_if_fail (dialog->priv->parent == NULL);
+ g_return_if_fail (GTK_IS_WINDOW(parent));
+ g_return_if_fail (GTK_IS_WINDOW(dialog->priv->dialog));
+
+ dialog->priv->parent = parent;
+
+ gtk_window_set_transient_for (GTK_WINDOW (dialog->priv->dialog),
+ GTK_WINDOW (parent));
+}
+
+EphyDialog *
+ephy_dialog_new (void)
+{
+ return EPHY_DIALOG (g_object_new (EPHY_DIALOG_TYPE, NULL));
+}
+
+EphyDialog *
+ephy_dialog_new_with_parent (GtkWidget *parent_window)
+{
+ return EPHY_DIALOG (g_object_new (EPHY_DIALOG_TYPE,
+ "ParentWindow", parent_window,
+ NULL));
+}
+
+void ephy_dialog_show_embedded (EphyDialog *dialog,
+ GtkWidget *container)
+{
+ dialog->priv->container = container;
+ gtk_container_add (GTK_CONTAINER(container),
+ dialog->priv->dialog);
+ gtk_widget_show (dialog->priv->dialog);
+}
+
+void
+ephy_dialog_remove_embedded (EphyDialog *dialog)
+{
+ g_object_ref (G_OBJECT(dialog->priv->dialog));
+ gtk_container_remove (GTK_CONTAINER(dialog->priv->container),
+ dialog->priv->dialog);
+}
+
+static PropertyInfo *
+init_props (const EphyDialogProperty *properties, GladeXML *gxml)
+{
+ PropertyInfo *props;
+ int i;
+
+ for (i=0 ; properties[i].control_name != NULL; i++);
+
+ props = g_new0 (PropertyInfo, i+1);
+
+ for (i=0 ; properties[i].control_name != NULL; i++)
+ {
+ props[i].id = properties[i].id;
+ props[i].widget = glade_xml_get_widget
+ (gxml, properties[i].control_name);
+ props[i].pref = properties[i].state_pref;
+ props[i].sg = properties[i].sg;
+ props[i].type = properties[i].type;
+ }
+
+ props[i].id = -1;
+ props[i].widget = NULL;
+ props[i].pref = NULL;
+ props[i].sg = NULL;
+ props[i].type = 0;
+
+ return props;
+}
+
+static void
+dialog_destruction_notify (EphyDialog *dialog,
+ GObject *where_the_object_was)
+{
+ dialog->priv->dialog = NULL;
+ ephy_dialog_destruct (dialog);
+ g_object_unref (dialog);
+}
+
+static void
+dialog_destroy_cb (GtkWidget *widget, EphyDialog *dialog)
+{
+ if (dialog->priv->props &&
+ dialog->priv->dialog)
+ {
+ save_props (dialog->priv->props);
+ }
+}
+
+static void
+impl_construct (EphyDialog *dialog,
+ const EphyDialogProperty *properties,
+ const char *file,
+ const char *name)
+{
+ GladeXML *gxml;
+
+ gxml = ephy_glade_widget_new
+ (file, name, &(dialog->priv->dialog), dialog);
+
+ if (dialog->priv->name == NULL)
+ {
+ dialog->priv->name = g_strdup (name);
+ }
+
+ if (properties)
+ {
+ dialog->priv->props = init_props (properties, gxml);
+ }
+
+ g_signal_connect (dialog->priv->dialog,
+ "destroy",
+ G_CALLBACK(dialog_destroy_cb),
+ dialog);
+
+ g_object_unref (gxml);
+
+ g_object_weak_ref (G_OBJECT(dialog->priv->dialog),
+ (GWeakNotify)dialog_destruction_notify,
+ dialog);
+
+ if (dialog->priv->props)
+ {
+ load_props (dialog->priv->props);
+ prefs_connect_signals (dialog);
+ prefs_set_sensitivity (dialog->priv->props);
+ }
+}
+
+static void
+impl_destruct (EphyDialog *dialog)
+{
+ if (dialog->priv->dialog)
+ {
+ g_object_weak_unref (G_OBJECT(dialog->priv->dialog),
+ (GWeakNotify)dialog_destruction_notify,
+ dialog);
+ gtk_widget_destroy (dialog->priv->dialog);
+ dialog->priv->dialog = NULL;
+ }
+}
+
+static GtkWidget *
+impl_get_control (EphyDialog *dialog,
+ int property_id)
+{
+ return dialog->priv->props[property_id].widget;
+}
+
+static void
+impl_get_value (EphyDialog *dialog,
+ int property_id,
+ GValue *value)
+{
+ GtkWidget *widget = ephy_dialog_get_control (dialog,
+ property_id);
+
+ if (GTK_IS_SPIN_BUTTON (widget))
+ {
+ float val;
+ g_value_init (value, G_TYPE_FLOAT);
+ val = gtk_spin_button_get_value (GTK_SPIN_BUTTON(widget));
+ g_value_set_float (value, val);
+ }
+ else if (GTK_IS_RADIO_BUTTON (widget))
+ {
+ int val;
+ g_value_init (value, G_TYPE_INT);
+ val = ephy_gui_gtk_radio_button_get (GTK_RADIO_BUTTON(widget));
+ g_value_set_int (value, val);
+ }
+ else if (GTK_IS_TOGGLE_BUTTON (widget))
+ {
+ g_value_init (value, G_TYPE_BOOLEAN);
+ g_value_set_boolean (value, gtk_toggle_button_get_active
+ (GTK_TOGGLE_BUTTON(widget)));
+ }
+ else if (GTK_IS_EDITABLE (widget))
+ {
+ g_value_init (value, G_TYPE_STRING);
+ g_value_set_string (value, gtk_editable_get_chars
+ (GTK_EDITABLE (widget), 0, -1));
+ }
+ else if (GTK_IS_OPTION_MENU (widget))
+ {
+ int val;
+ g_value_init (value, G_TYPE_INT);
+ val = gtk_option_menu_get_history (GTK_OPTION_MENU(widget));
+ g_value_set_int (value, val);
+ }
+}
+
+static gboolean
+ephy_dialog_configure_event_cb (GtkWidget *widget,
+ GdkEventConfigure *event,
+ EphyDialog *dialog)
+{
+ ephy_state_save_window (widget, dialog->priv->name);
+
+ return FALSE;
+}
+
+static void
+setup_default_size (EphyDialog *dialog)
+{
+ ephy_state_load_window (dialog->priv->dialog,
+ dialog->priv->name, -1, -1, FALSE);
+
+ g_signal_connect (dialog->priv->dialog,
+ "configure_event",
+ G_CALLBACK (ephy_dialog_configure_event_cb),
+ dialog);
+}
+
+static gint
+impl_run (EphyDialog *dialog)
+{
+ setup_default_size (dialog);
+
+ return gtk_dialog_run (GTK_DIALOG(dialog->priv->dialog));
+}
+
+static void
+impl_show (EphyDialog *dialog)
+{
+ setup_default_size (dialog);
+
+ if (dialog->priv->parent)
+ {
+ /* make the dialog transient again, because it seems to get
+ * forgotten after gtk_widget_hide
+ */
+ gtk_window_set_transient_for (GTK_WINDOW (dialog->priv->dialog),
+ GTK_WINDOW (dialog->priv->parent));
+ }
+ gtk_window_present (GTK_WINDOW(dialog->priv->dialog));
+}
+
+void
+ephy_dialog_set_modal (EphyDialog *dialog,
+ gboolean is_modal)
+{
+ dialog->priv->modal = is_modal;
+
+ gtk_window_set_modal (GTK_WINDOW(dialog->priv->dialog),
+ is_modal);
+}
+
+void
+ephy_dialog_construct (EphyDialog *dialog,
+ const EphyDialogProperty *properties,
+ const char *file,
+ const char *name)
+{
+ EphyDialogClass *klass = EPHY_DIALOG_GET_CLASS (dialog);
+ return klass->construct (dialog, properties, file, name);
+}
+
+void
+ephy_dialog_destruct (EphyDialog *dialog)
+{
+ EphyDialogClass *klass = EPHY_DIALOG_GET_CLASS (dialog);
+ klass->destruct (dialog);
+}
+
+gint
+ephy_dialog_run (EphyDialog *dialog)
+{
+ EphyDialogClass *klass = EPHY_DIALOG_GET_CLASS (dialog);
+ return klass->run (dialog);
+}
+
+void
+ephy_dialog_show (EphyDialog *dialog)
+{
+ EphyDialogClass *klass = EPHY_DIALOG_GET_CLASS (dialog);
+ klass->show (dialog);
+}
+
+GtkWidget *
+ephy_dialog_get_control (EphyDialog *dialog,
+ int property_id)
+{
+ EphyDialogClass *klass = EPHY_DIALOG_GET_CLASS (dialog);
+ return klass->get_control (dialog, property_id);
+}
+
+void
+ephy_dialog_get_value (EphyDialog *dialog,
+ int property_id,
+ GValue *value)
+{
+ EphyDialogClass *klass = EPHY_DIALOG_GET_CLASS (dialog);
+ return klass->get_value (dialog, property_id, value);
+}
+
diff --git a/lib/ephy-dialog.h b/lib/ephy-dialog.h
new file mode 100644
index 000000000..24cb2cf5c
--- /dev/null
+++ b/lib/ephy-dialog.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EPHY_DIALOG_H
+#define EPHY_DIALOG_H
+
+#include <glib-object.h>
+#include <glib.h>
+#include <gtk/gtkwidget.h>
+
+G_BEGIN_DECLS
+
+typedef struct EphyDialogClass EphyDialogClass;
+
+#define EPHY_DIALOG_TYPE (ephy_dialog_get_type ())
+#define EPHY_DIALOG(obj) (GTK_CHECK_CAST ((obj), EPHY_DIALOG_TYPE, EphyDialog))
+#define EPHY_DIALOG_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), EPHY_DIALOG_TYPE, EphyDialogClass))
+#define IS_EPHY_DIALOG(obj) (GTK_CHECK_TYPE ((obj), EPHY_DIALOG_TYPE))
+#define IS_EPHY_DIALOG_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), EPHY_DIALOG))
+#define EPHY_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EPHY_DIALOG_TYPE, EphyDialogClass))
+
+typedef struct EphyDialog EphyDialog;
+typedef struct EphyDialogPrivate EphyDialogPrivate;
+
+#define SY_BEGIN_GROUP -20
+#define SY_END_GROUP -21
+#define SY_END -22
+#define SY_BEGIN_GROUP_INVERSE -23
+
+struct EphyDialog
+{
+ GObject parent;
+ EphyDialogPrivate *priv;
+};
+
+typedef enum
+{
+ PT_NORMAL,
+ PT_AUTOAPPLY
+} PropertyType;
+
+typedef struct
+{
+ int id;
+ const char *control_name;
+ const char *state_pref;
+ PropertyType type;
+ int *sg;
+} EphyDialogProperty;
+
+struct EphyDialogClass
+{
+ GObjectClass parent_class;
+
+ void (* construct) (EphyDialog *dialog,
+ const EphyDialogProperty *properties,
+ const char *file,
+ const char *name);
+ void (* destruct) (EphyDialog *dialog);
+ gint (* run) (EphyDialog *dialog);
+ void (* show) (EphyDialog *dialog);
+ GtkWidget * (* get_control) (EphyDialog *dialog,
+ int property_id);
+ void (* get_value) (EphyDialog *dialog,
+ int property_id,
+ GValue *value);
+};
+
+GType ephy_dialog_get_type (void);
+
+EphyDialog *ephy_dialog_new (void);
+
+EphyDialog *ephy_dialog_new_with_parent (GtkWidget *parent_window);
+
+void ephy_dialog_construct (EphyDialog *dialog,
+ const EphyDialogProperty *properties,
+ const char *file,
+ const char *name);
+
+void ephy_dialog_destruct (EphyDialog *dialog);
+
+gint ephy_dialog_run (EphyDialog *dialog);
+
+void ephy_dialog_show (EphyDialog *dialog);
+
+void ephy_dialog_show_embedded (EphyDialog *dialog,
+ GtkWidget *container);
+
+void ephy_dialog_remove_embedded (EphyDialog *dialog);
+
+void ephy_dialog_set_modal (EphyDialog *dialog,
+ gboolean is_modal);
+
+GtkWidget *ephy_dialog_get_control (EphyDialog *dialog,
+ int property_id);
+
+void ephy_dialog_get_value (EphyDialog *dialog,
+ int property_id,
+ GValue *value);
+
+G_END_DECLS
+
+#endif
+
diff --git a/lib/ephy-dnd.c b/lib/ephy-dnd.c
new file mode 100644
index 000000000..b70fa284a
--- /dev/null
+++ b/lib/ephy-dnd.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "ephy-dnd.h"
+
+#include <gtk/gtkselection.h>
+#include <gtk/gtktreeview.h>
+
+static GtkTargetEntry url_drag_types [] =
+{
+ { EPHY_DND_URI_LIST_TYPE, 0, EPHY_DND_URI_LIST },
+ { EPHY_DND_TEXT_TYPE, 0, EPHY_DND_TEXT },
+ { EPHY_DND_URL_TYPE, 0, EPHY_DND_URL }
+};
+
+/* Encode a "_NETSCAPE_URL_" selection.
+ * As far as I can tell, Netscape is expecting a single
+ * URL to be returned. I cannot discover a way to construct
+ * a list to be returned that Netscape can understand.
+ * GMC also fails to do this as well.
+ */
+static void
+add_one_netscape_url (const char *url, int x, int y, int w, int h, gpointer data)
+{
+ GString *result;
+
+ result = (GString *) data;
+ if (result->len == 0) {
+ g_string_append (result, url);
+ }
+}
+
+static void
+add_one_uri (const char *uri, int x, int y, int w, int h, gpointer data)
+{
+ GString *result;
+
+ result = (GString *) data;
+
+ g_string_append (result, uri);
+ g_string_append (result, "\r\n");
+}
+
+gboolean
+ephy_dnd_drag_data_get (GtkWidget *widget,
+ GdkDragContext *context,
+ GtkSelectionData *selection_data,
+ guint info,
+ guint32 time,
+ gpointer container_context,
+ EphyDragEachSelectedItemIterator each_selected_item_iterator)
+{
+ GString *result;
+
+ switch (info) {
+ case EPHY_DND_URI_LIST:
+ case EPHY_DND_TEXT:
+ result = g_string_new (NULL);
+ (* each_selected_item_iterator) (add_one_uri, container_context, result);
+ break;
+ case EPHY_DND_URL:
+ result = g_string_new (NULL);
+ (* each_selected_item_iterator) (add_one_netscape_url, container_context, result);
+ break;
+ default:
+ return FALSE;
+ }
+
+ gtk_selection_data_set (selection_data,
+ selection_data->target,
+ 8, result->str, result->len);
+
+ return TRUE;
+}
+
+void
+ephy_dnd_url_drag_source_set (GtkWidget *widget)
+{
+ gtk_drag_source_set (widget,
+ GDK_BUTTON1_MASK,
+ url_drag_types,
+ G_N_ELEMENTS (url_drag_types),
+ GDK_ACTION_COPY);
+}
+
+void
+ephy_dnd_enable_model_drag_source (GtkWidget *treeview)
+{
+ gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW (treeview),
+ GDK_BUTTON1_MASK,
+ url_drag_types, G_N_ELEMENTS (url_drag_types),
+ GDK_ACTION_COPY);
+}
+
diff --git a/lib/ephy-dnd.h b/lib/ephy-dnd.h
new file mode 100644
index 000000000..87b6008d9
--- /dev/null
+++ b/lib/ephy-dnd.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EPHY_DND_H
+#define EPHY_DND_H
+
+#include <glib.h>
+#include <gtk/gtkwidget.h>
+#include <gtk/gtkdnd.h>
+
+G_BEGIN_DECLS
+
+#define EPHY_DND_NODE_PROPERTY 3
+
+/* Drag & Drop target names. */
+#define EPHY_DND_URI_LIST_TYPE "text/uri-list"
+#define EPHY_DND_TEXT_TYPE "text/plain"
+#define EPHY_DND_URL_TYPE "_NETSCAPE_URL"
+#define EPHY_DND_EPHY_URL_TYPE "EPHY_URL"
+#define EPHY_DND_EPHY_BOOKMARK_TYPE "EPHY_BOOKMARK"
+
+/* Standard Drag & Drop types. */
+typedef enum {
+ EPHY_DND_URI_LIST,
+ EPHY_DND_URL,
+ EPHY_DND_TEXT,
+} EphyIconDndTargetType;
+
+typedef void (* EphyDragEachSelectedItemDataGet) (const char *url,
+ int x, int y, int w, int h,
+ gpointer data);
+
+typedef void (* EphyDragEachSelectedItemIterator) (EphyDragEachSelectedItemDataGet iteratee,
+ gpointer iterator_context,
+ gpointer data);
+
+gboolean ephy_dnd_drag_data_get (GtkWidget *widget,
+ GdkDragContext *context,
+ GtkSelectionData *selection_data,
+ guint info,
+ guint32 time,
+ gpointer container_context,
+ EphyDragEachSelectedItemIterator each_selected_item_iterator);
+
+void ephy_dnd_url_drag_source_set (GtkWidget *widget);
+
+void ephy_dnd_enable_model_drag_source (GtkWidget *treeview);
+
+
+G_END_DECLS
+
+#endif
diff --git a/lib/ephy-file-helpers.c b/lib/ephy-file-helpers.c
new file mode 100644
index 000000000..2e867e3f5
--- /dev/null
+++ b/lib/ephy-file-helpers.c
@@ -0,0 +1,326 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Id$
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <glib.h>
+#include <libgnome/gnome-i18n.h>
+#include <libgnome/gnome-init.h>
+#include <libgnome/gnome-exec.h>
+
+#include "ephy-file-helpers.h"
+
+static GHashTable *files = NULL;
+
+static char *dot_dir = NULL;
+
+char *
+ephy_file_tmp_filename (const char *base,
+ const char *extension)
+{
+ int fd;
+ char *name = g_strdup (base);
+
+ fd = mkstemp (name);
+
+ if (fd != -1)
+ {
+ unlink (name);
+ close (fd);
+ }
+ else
+ {
+ return NULL;
+ }
+
+ if (extension)
+ {
+ char *tmp;
+ tmp = g_strconcat (name, ".",
+ extension, NULL);
+ g_free (name);
+ name = tmp;
+ }
+
+ return name;
+}
+
+const char *
+ephy_file (const char *filename)
+{
+ char *ret;
+ int i;
+
+ static char *paths[] =
+ {
+ SHARE_DIR "/",
+ SHARE_DIR "/glade/",
+ SHARE_DIR "/art/",
+ SHARE_UNINSTALLED_DIR "/",
+ SHARE_UNINSTALLED_DIR "/glade/",
+ SHARE_UNINSTALLED_DIR "/art/"
+ };
+
+ g_assert (files != NULL);
+
+ ret = g_hash_table_lookup (files, filename);
+ if (ret != NULL)
+ return ret;
+
+ for (i = 0; i < (int) G_N_ELEMENTS (paths); i++)
+ {
+ ret = g_strconcat (paths[i], filename, NULL);
+ if (g_file_test (ret, G_FILE_TEST_EXISTS) == TRUE)
+ {
+ g_hash_table_insert (files, g_strdup (filename), ret);
+ return (const char *) ret;
+ }
+ g_free (ret);
+ }
+
+ g_warning (_("Failed to find %s"), filename);
+
+ return NULL;
+}
+
+const char *
+ephy_dot_dir (void)
+{
+ if (dot_dir == NULL)
+ {
+ dot_dir = g_build_filename (g_get_home_dir (),
+ GNOME_DOT_GNOME,
+ "epiphany",
+ NULL);
+ }
+
+ return dot_dir;
+}
+
+void
+ephy_file_helpers_init (void)
+{
+ files = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) g_free);
+}
+
+void
+ephy_file_helpers_shutdown (void)
+{
+ g_hash_table_destroy (files);
+
+ g_free (dot_dir);
+}
+
+static void
+gul_general_gnome_shell_execute (const char *command)
+{
+ GError *error = NULL;
+ if (!g_spawn_command_line_async (command, &error)) {
+ g_warning ("Error starting command '%s': %s\n", command, error->message);
+ g_error_free (error);
+ }
+}
+
+/* Return a command string containing the path to a terminal on this system. */
+
+static char *
+try_terminal_command (const char *program,
+ const char *args)
+{
+ char *program_in_path, *quoted, *result;
+
+ if (program == NULL) {
+ return NULL;
+ }
+
+ program_in_path = g_find_program_in_path (program);
+ if (program_in_path == NULL) {
+ return NULL;
+ }
+
+ quoted = g_shell_quote (program_in_path);
+ if (args == NULL || args[0] == '\0') {
+ return quoted;
+ }
+ result = g_strconcat (quoted, " ", args, NULL);
+ g_free (quoted);
+ return result;
+}
+
+static char *
+try_terminal_command_argv (int argc,
+ char **argv)
+{
+ GString *string;
+ int i;
+ char *quoted, *result;
+
+ if (argc == 0) {
+ return NULL;
+ }
+
+ if (argc == 1) {
+ return try_terminal_command (argv[0], NULL);
+ }
+
+ string = g_string_new (argv[1]);
+ for (i = 2; i < argc; i++) {
+ quoted = g_shell_quote (argv[i]);
+ g_string_append_c (string, ' ');
+ g_string_append (string, quoted);
+ g_free (quoted);
+ }
+ result = try_terminal_command (argv[0], string->str);
+ g_string_free (string, TRUE);
+
+ return result;
+}
+
+static char *
+get_terminal_command_prefix (gboolean for_command)
+{
+ int argc;
+ char **argv;
+ char *command;
+ guint i;
+ static const char *const commands[][3] = {
+ { "gnome-terminal", "-x", "" },
+ { "dtterm", "-e", "-ls" },
+ { "nxterm", "-e", "-ls" },
+ { "color-xterm", "-e", "-ls" },
+ { "rxvt", "-e", "-ls" },
+ { "xterm", "-e", "-ls" },
+ };
+
+ /* Try the terminal from preferences. Use without any
+ * arguments if we are just doing a standalone terminal.
+ */
+ argc = 0;
+ argv = g_new0 (char *, 1);
+ gnome_prepend_terminal_to_vector (&argc, &argv);
+
+ command = NULL;
+ if (argc != 0) {
+ if (for_command) {
+ command = try_terminal_command_argv (argc, argv);
+ } else {
+ /* Strip off the arguments in a lame attempt
+ * to make it be an interactive shell.
+ */
+ command = try_terminal_command (argv[0], NULL);
+ }
+ }
+
+ while (argc != 0) {
+ g_free (argv[--argc]);
+ }
+ g_free (argv);
+
+ if (command != NULL) {
+ return command;
+ }
+
+ /* Try well-known terminal applications in same order that gmc did. */
+ for (i = 0; i < G_N_ELEMENTS (commands); i++) {
+ command = try_terminal_command (commands[i][0],
+ commands[i][for_command ? 1 : 2]);
+ if (command != NULL) {
+ break;
+ }
+ }
+
+ return command;
+}
+
+static char *
+gul_general_gnome_make_terminal_command (const char *command)
+{
+ char *prefix, *quoted, *terminal_command;
+
+ if (command == NULL) {
+ return get_terminal_command_prefix (FALSE);
+ }
+ prefix = get_terminal_command_prefix (TRUE);
+ quoted = g_shell_quote (command);
+ terminal_command = g_strconcat (prefix, " /bin/sh -c ", quoted, NULL);
+ g_free (prefix);
+ g_free (quoted);
+ return terminal_command;
+}
+
+static void
+gul_general_gnome_open_terminal (const char *command)
+{
+ char *command_line;
+
+ command_line = gul_general_gnome_make_terminal_command (command);
+ if (command_line == NULL) {
+ g_message ("Could not start a terminal");
+ return;
+ }
+ gul_general_gnome_shell_execute (command_line);
+ g_free (command_line);
+}
+
+void
+ephy_file_launch_application (const char *command_string,
+ const char *parameter,
+ gboolean use_terminal)
+{
+ char *full_command;
+ char *quoted_parameter;
+
+ if (parameter != NULL) {
+ quoted_parameter = g_shell_quote (parameter);
+ full_command = g_strconcat (command_string, " ", quoted_parameter, NULL);
+ g_free (quoted_parameter);
+ } else {
+ full_command = g_strdup (command_string);
+ }
+
+ if (use_terminal) {
+ gul_general_gnome_open_terminal (full_command);
+ } else {
+ gul_general_gnome_shell_execute (full_command);
+ }
+
+ g_free (full_command);
+}
+
+void
+ephy_ensure_dir_exists (const char *dir)
+{
+ if (g_file_test (dir, G_FILE_TEST_IS_DIR) == FALSE)
+ {
+ if (g_file_test (dir, G_FILE_TEST_EXISTS) == TRUE)
+ g_error (_("%s exists, please move it out of the way."), dir);
+
+ if (mkdir (dir, 488) != 0)
+ g_error (_("Failed to create directory %s."), dir);
+ }
+}
diff --git a/lib/ephy-file-helpers.h b/lib/ephy-file-helpers.h
new file mode 100644
index 000000000..75f6a0e9e
--- /dev/null
+++ b/lib/ephy-file-helpers.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Id$
+ */
+
+#ifndef EPHY_FILE_HELPERS_H
+#define EPHY_FILE_HELPERS_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+const char *ephy_file (const char *filename);
+
+const char *ephy_dot_dir (void);
+
+void ephy_file_helpers_init (void);
+
+void ephy_file_helpers_shutdown (void);
+
+void ephy_file_launch_application (const char *command_string,
+ const char *parameter,
+ gboolean use_terminal);
+
+char *ephy_file_tmp_filename (const char *base,
+ const char *extension);
+
+void ephy_ensure_dir_exists (const char *dir);
+
+
+G_END_DECLS
+
+#endif /* EPHY_FILE_HELPERS_H */
diff --git a/lib/ephy-filesystem-autocompletion.c b/lib/ephy-filesystem-autocompletion.c
new file mode 100644
index 000000000..8b1cb84fb
--- /dev/null
+++ b/lib/ephy-filesystem-autocompletion.c
@@ -0,0 +1,343 @@
+/*
+ * Copyright (C) 2002 Ricardo Fernández Pascual
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "ephy-autocompletion-source.h"
+#include "ephy-filesystem-autocompletion.h"
+#include "ephy-gobject-misc.h"
+#include <string.h>
+
+#include <libgnomevfs/gnome-vfs-async-ops.h>
+
+#define NOT_IMPLEMENTED g_warning ("not implemented: " G_STRLOC);
+
+//#define DEBUG_MSG(x) g_print x
+#define DEBUG_MSG(x)
+
+/**
+ * Private data
+ */
+struct _EphyFilesystemAutocompletionPrivate {
+ gchar *current_dir;
+ gchar *base_dir;
+ GnomeVFSURI *base_dir_uri;
+ gchar *basic_key;
+ gchar *basic_key_dir;
+ GSList *files;
+
+ guint score;
+ GnomeVFSAsyncHandle *load_handle;
+};
+
+/**
+ * Private functions, only availble from this file
+ */
+static void ephy_filesystem_autocompletion_class_init (EphyFilesystemAutocompletionClass *klass);
+static void ephy_filesystem_autocompletion_init (EphyFilesystemAutocompletion *as);
+static void ephy_filesystem_autocompletion_finalize_impl (GObject *o);
+static void ephy_filesystem_autocompletion_autocompletion_source_init (EphyAutocompletionSourceIface *iface);
+static void ephy_filesystem_autocompletion_autocompletion_source_foreach (EphyAutocompletionSource *source,
+ const gchar *current_text,
+ EphyAutocompletionSourceForeachFunc func,
+ gpointer data);
+void ephy_filesystem_autocompletion_autocompletion_source_set_basic_key (EphyAutocompletionSource *source,
+ const gchar *basic_key);
+static void ephy_filesystem_autocompletion_emit_autocompletion_source_data_changed (EphyFilesystemAutocompletion *gh);
+static void ephy_filesystem_autocompletion_set_current_dir (EphyFilesystemAutocompletion *fa, const gchar *d);
+
+
+static gpointer g_object_class;
+
+/**
+ * FilesystemAutocompletion object
+ */
+MAKE_GET_TYPE_IFACE (ephy_filesystem_autocompletion, "EphyFilesystemAutocompletion", EphyFilesystemAutocompletion,
+ ephy_filesystem_autocompletion_class_init, ephy_filesystem_autocompletion_init, G_TYPE_OBJECT,
+ ephy_filesystem_autocompletion_autocompletion_source_init, EPHY_TYPE_AUTOCOMPLETION_SOURCE);
+
+static void
+ephy_filesystem_autocompletion_autocompletion_source_init (EphyAutocompletionSourceIface *iface)
+{
+ iface->foreach = ephy_filesystem_autocompletion_autocompletion_source_foreach;
+ iface->set_basic_key = ephy_filesystem_autocompletion_autocompletion_source_set_basic_key;
+}
+
+static void
+ephy_filesystem_autocompletion_class_init (EphyFilesystemAutocompletionClass *klass)
+{
+ G_OBJECT_CLASS (klass)->finalize = ephy_filesystem_autocompletion_finalize_impl;
+
+ g_object_class = g_type_class_peek_parent (klass);
+}
+
+static void
+ephy_filesystem_autocompletion_init (EphyFilesystemAutocompletion *e)
+{
+ EphyFilesystemAutocompletionPrivate *p = g_new0 (EphyFilesystemAutocompletionPrivate, 1);
+ e->priv = p;
+
+ p->score = G_MAXINT / 2;
+ p->base_dir = g_strdup ("");
+}
+
+static void
+ephy_filesystem_autocompletion_finalize_impl (GObject *o)
+{
+ EphyFilesystemAutocompletion *as = GUL_FILESYSTEM_AUTOCOMPLETION (o);
+ EphyFilesystemAutocompletionPrivate *p = as->priv;
+
+ DEBUG_MSG (("in ephy_filesystem_autocompletion_finalize_impl\n"));
+
+ g_free (p->basic_key);
+ g_free (p->basic_key_dir);
+ g_free (p->current_dir);
+ g_free (p->base_dir);
+ if (p->base_dir_uri)
+ {
+ gnome_vfs_uri_unref (p->base_dir_uri);
+ }
+
+ g_free (p);
+
+ G_OBJECT_CLASS (g_object_class)->finalize (o);
+}
+
+EphyFilesystemAutocompletion *
+ephy_filesystem_autocompletion_new (void)
+{
+ EphyFilesystemAutocompletion *ret = g_object_new (GUL_TYPE_FILESYSTEM_AUTOCOMPLETION, NULL);
+ return ret;
+}
+
+
+static gchar *
+gfa_get_nearest_dir (const gchar *path)
+{
+ gchar *ret;
+ const gchar *lastslash = rindex (path, '/');
+
+ if (lastslash)
+ {
+ if (!strcmp (path, "file://"))
+ {
+ /* without this, gnome-vfs does not recognize it as a dir */
+ ret = g_strdup ("file:///");
+ }
+ else
+ {
+ ret = g_strndup (path, lastslash - path + 1);
+ }
+ }
+ else
+ {
+ ret = g_strdup ("");
+ }
+
+ return ret;
+}
+
+static void
+ephy_filesystem_autocompletion_autocompletion_source_foreach (EphyAutocompletionSource *source,
+ const gchar *basic_key,
+ EphyAutocompletionSourceForeachFunc func,
+ gpointer data)
+{
+ EphyFilesystemAutocompletion *fa = GUL_FILESYSTEM_AUTOCOMPLETION (source);
+ EphyFilesystemAutocompletionPrivate *p = fa->priv;
+ GSList *li;
+
+ ephy_filesystem_autocompletion_autocompletion_source_set_basic_key (source, basic_key);
+
+ for (li = p->files; li; li = li->next)
+ {
+ func (source, li->data, li->data, li->data, FALSE, FALSE, p->score, data);
+ }
+
+}
+
+static void
+ephy_filesystem_autocompletion_emit_autocompletion_source_data_changed (EphyFilesystemAutocompletion *fa)
+{
+ g_signal_emit_by_name (fa, "data-changed");
+}
+
+static void
+gfa_load_directory_cb (GnomeVFSAsyncHandle *handle,
+ GnomeVFSResult result,
+ GList *list,
+ guint entries_read,
+ gpointer callback_data)
+{
+ EphyFilesystemAutocompletion *fa = callback_data;
+ EphyFilesystemAutocompletionPrivate *p = fa->priv;
+ GList *li;
+ gchar *cd;
+
+ g_return_if_fail (p->load_handle == handle);
+
+ DEBUG_MSG (("gfa_load_directory_cb, entries_read == %d\n", entries_read));
+
+ if (entries_read <= 0)
+ {
+ return;
+ }
+
+ if (p->basic_key_dir[strlen (p->basic_key_dir) - 1] == G_DIR_SEPARATOR
+ || p->basic_key_dir[0] == '\0')
+ {
+ cd = g_strdup (p->basic_key_dir);
+ }
+ else
+ {
+ cd = g_strconcat (p->basic_key_dir, G_DIR_SEPARATOR_S, NULL);
+ }
+
+ for (li = list; li; li = li->next)
+ {
+ GnomeVFSFileInfo *i = li->data;
+ if (!(i->name[0] == '.'
+ && (i->name[1] == '\0'
+ || (i->name[1] == '.'
+ && i->name[2] == '\0'))))
+ {
+ gchar *f = g_strconcat (cd, i->name, NULL);
+ p->files = g_slist_prepend (p->files, f);
+
+ DEBUG_MSG (("+ %s\n", f));
+ }
+ }
+
+ g_free (cd);
+
+ ephy_filesystem_autocompletion_emit_autocompletion_source_data_changed (fa);
+}
+
+static void
+ephy_filesystem_autocompletion_set_current_dir (EphyFilesystemAutocompletion *fa, const gchar *d)
+{
+ EphyFilesystemAutocompletionPrivate *p = fa->priv;
+ GnomeVFSURI *cd_uri;
+
+ if (p->base_dir_uri)
+ {
+ cd_uri = gnome_vfs_uri_append_path (p->base_dir_uri, d);
+ }
+ else
+ {
+ cd_uri = gnome_vfs_uri_new (d);
+ }
+
+ if (p->load_handle)
+ {
+ gnome_vfs_async_cancel (p->load_handle);
+ p->load_handle = NULL;
+ }
+
+ if (p->files)
+ {
+ g_slist_foreach (p->files, (GFunc) g_free, NULL);
+ g_slist_free (p->files);
+ p->files = NULL;
+
+ ephy_filesystem_autocompletion_emit_autocompletion_source_data_changed (fa);
+ }
+
+ if (!cd_uri)
+ {
+ DEBUG_MSG (("Can't load dir %s\n", d));
+ return;
+ }
+
+ g_free (p->current_dir);
+ p->current_dir = gnome_vfs_uri_to_string (cd_uri, GNOME_VFS_URI_HIDE_NONE);
+
+ DEBUG_MSG (("Loading dir: %s\n", p->current_dir));
+
+ gnome_vfs_async_load_directory_uri (&p->load_handle,
+ cd_uri,
+ GNOME_VFS_FILE_INFO_DEFAULT,
+ 100,
+ 0,
+ gfa_load_directory_cb,
+ fa);
+
+ gnome_vfs_uri_unref (cd_uri);
+}
+
+void
+ephy_filesystem_autocompletion_autocompletion_source_set_basic_key (EphyAutocompletionSource *source,
+ const gchar *basic_key)
+{
+ EphyFilesystemAutocompletion *fa = GUL_FILESYSTEM_AUTOCOMPLETION (source);
+ EphyFilesystemAutocompletionPrivate *p = fa->priv;
+ gchar *new_basic_key_dir;
+
+ if (p->basic_key && !strcmp (p->basic_key, basic_key))
+ {
+ return;
+ }
+
+ g_free (p->basic_key);
+ p->basic_key = g_strdup (basic_key);
+
+ new_basic_key_dir = gfa_get_nearest_dir (basic_key);
+ if (p->basic_key_dir && !strcmp (p->basic_key_dir, new_basic_key_dir))
+ {
+ g_free (new_basic_key_dir);
+ }
+ else
+ {
+ g_free (p->basic_key_dir);
+ p->basic_key_dir = new_basic_key_dir;
+ ephy_filesystem_autocompletion_set_current_dir (fa, p->basic_key_dir);
+ }
+}
+
+void
+ephy_filesystem_autocompletion_set_base_dir (EphyFilesystemAutocompletion *fa, const gchar *d)
+{
+ EphyFilesystemAutocompletionPrivate *p = fa->priv;
+
+ g_free (p->base_dir);
+ p->base_dir = g_strdup (d);
+
+ if (p->base_dir_uri)
+ {
+ gnome_vfs_uri_unref (p->base_dir_uri);
+ }
+
+ if (p->base_dir[0])
+ {
+ p->base_dir_uri = gnome_vfs_uri_new (p->base_dir);
+ }
+ else
+ {
+ p->base_dir_uri = NULL;
+ }
+
+ if (p->base_dir_uri)
+ {
+ gchar *t = gnome_vfs_uri_to_string (p->base_dir_uri, GNOME_VFS_URI_HIDE_NONE);
+ DEBUG_MSG (("base_dir: %s\n", t));
+ g_free (t);
+ }
+}
+
diff --git a/lib/ephy-filesystem-autocompletion.h b/lib/ephy-filesystem-autocompletion.h
new file mode 100644
index 000000000..ec047282f
--- /dev/null
+++ b/lib/ephy-filesystem-autocompletion.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2002 Ricardo Fernández Pascual
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EPHY_FILESYSTEM_AUTOCOMPLETION_H
+#define EPHY_FILESYSTEM_AUTOCOMPLETION_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+/* object forward declarations */
+
+typedef struct _EphyFilesystemAutocompletion EphyFilesystemAutocompletion;
+typedef struct _EphyFilesystemAutocompletionClass EphyFilesystemAutocompletionClass;
+typedef struct _EphyFilesystemAutocompletionPrivate EphyFilesystemAutocompletionPrivate;
+
+/**
+ * FilesystemAutocompletion object
+ */
+
+#define GUL_TYPE_FILESYSTEM_AUTOCOMPLETION (ephy_filesystem_autocompletion_get_type())
+#define GUL_FILESYSTEM_AUTOCOMPLETION(object) (G_TYPE_CHECK_INSTANCE_CAST((object), \
+ GUL_TYPE_FILESYSTEM_AUTOCOMPLETION,\
+ EphyFilesystemAutocompletion))
+#define GUL_FILESYSTEM_AUTOCOMPLETION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), \
+ GUL_TYPE_FILESYSTEM_AUTOCOMPLETION,\
+ EphyFilesystemAutocompletionClass))
+#define GUL_IS_FILESYSTEM_AUTOCOMPLETION(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), \
+ GUL_TYPE_FILESYSTEM_AUTOCOMPLETION))
+#define GUL_IS_FILESYSTEM_AUTOCOMPLETION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), \
+ GUL_TYPE_FILESYSTEM_AUTOCOMPLETION))
+#define GUL_FILESYSTEM_AUTOCOMPLETION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), \
+ GUL_TYPE_FILESYSTEM_AUTOCOMPLETION,\
+ EphyFilesystemAutocompletionClass))
+
+struct _EphyFilesystemAutocompletionClass
+{
+ GObjectClass parent_class;
+
+};
+
+struct _EphyFilesystemAutocompletion
+{
+ GObject parent_object;
+ EphyFilesystemAutocompletionPrivate *priv;
+};
+
+GType ephy_filesystem_autocompletion_get_type (void);
+EphyFilesystemAutocompletion * ephy_filesystem_autocompletion_new (void);
+void ephy_filesystem_autocompletion_set_base_dir (EphyFilesystemAutocompletion *fa,
+ const gchar *d);
+
+G_END_DECLS
+
+#endif
diff --git a/lib/ephy-glade.c b/lib/ephy-glade.c
new file mode 100644
index 000000000..beb91827f
--- /dev/null
+++ b/lib/ephy-glade.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2000 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "ephy-glade.h"
+#include "ephy-file-helpers.h"
+
+#include <glade/glade-xml.h>
+#include <gtk/gtkmenu.h>
+#include <gmodule.h>
+
+static void
+glade_signal_connect_func (const gchar *cb_name, GObject *obj,
+ const gchar *signal_name, const gchar *signal_data,
+ GObject *conn_obj, gboolean conn_after,
+ gpointer user_data);
+
+/**
+ * ephy_widget_new: build a new widget of the provided name, with all
+ * signals attached and data set to the provided parameter.
+ */
+GladeXML *
+ephy_glade_widget_new (const char *file, const char *widget_name,
+ GtkWidget **root, gpointer data)
+{
+ GladeXML *gxml;
+ const char *glade_file;
+
+ glade_file = ephy_file (file);
+ g_return_val_if_fail (glade_file != NULL, NULL);
+
+ /* build the widget */
+ /* note that libglade automatically caches the parsed file,
+ * so we don't need to worry about the efficiency of this */
+ gxml = glade_xml_new (glade_file, widget_name, NULL);
+ g_return_val_if_fail (gxml != NULL, NULL);
+
+ /* lookup the root widget if requested */
+ if (root != NULL)
+ {
+ *root = glade_xml_get_widget (gxml, widget_name);
+ }
+
+ /* connect signals and data */
+ glade_xml_signal_autoconnect_full
+ (gxml, (GladeXMLConnectFunc)glade_signal_connect_func, data);
+
+ /* return xml document for subsequent widget lookups */
+ return gxml;
+}
+
+/*
+ * glade_signal_connect_func: used by glade_xml_signal_autoconnect_full
+ */
+static void
+glade_signal_connect_func (const gchar *cb_name, GObject *obj,
+ const gchar *signal_name, const gchar *signal_data,
+ GObject *conn_obj, gboolean conn_after,
+ gpointer user_data)
+{
+ /** Module with all the symbols of the program */
+ static GModule *mod_self = NULL;
+ gpointer handler_func;
+
+ /* initialize gmodule */
+ if (mod_self == NULL)
+ {
+ mod_self = g_module_open (NULL, 0);
+ g_assert (mod_self != NULL);
+ }
+
+ /*g_print( "glade_signal_connect_func: cb_name = '%s', signal_name = '%s', signal_data = '%s'\n",
+ cb_name, signal_name, signal_data ); */
+
+ if (g_module_symbol (mod_self, cb_name, &handler_func))
+ {
+ /* found callback */
+ if (conn_obj)
+ {
+ if (conn_after)
+ {
+ g_signal_connect_object
+ (obj, signal_name,
+ handler_func, conn_obj,
+ G_CONNECT_AFTER);
+ }
+ else
+ {
+ g_signal_connect_object
+ (obj, signal_name,
+ handler_func, conn_obj,
+ G_CONNECT_SWAPPED);
+ }
+ }
+ else
+ {
+ /* no conn_obj; use standard connect */
+ gpointer data = NULL;
+
+ data = user_data;
+
+ if (conn_after)
+ {
+ g_signal_connect_after
+ (obj, signal_name,
+ handler_func, data);
+ }
+ else
+ {
+ g_signal_connect
+ (obj, signal_name,
+ handler_func, data);
+ }
+ }
+ }
+ else
+ {
+ g_warning("callback function not found: %s", cb_name);
+ }
+}
diff --git a/lib/ephy-glade.h b/lib/ephy-glade.h
new file mode 100644
index 000000000..cccf22f24
--- /dev/null
+++ b/lib/ephy-glade.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2000 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EPHY_GLADE_H
+#define EPHY_GLADE_H
+
+#include <glib.h>
+#include <gtk/gtk.h>
+#include <glade/glade-xml.h>
+
+typedef struct
+{
+ const gchar *name;
+ GtkWidget **ptr;
+} WidgetLookup;
+
+G_BEGIN_DECLS
+
+GladeXML *ephy_glade_widget_new (const char *file,
+ const char *widget_name,
+ GtkWidget **root,
+ gpointer data);
+
+G_END_DECLS
+
+#endif
diff --git a/lib/ephy-gobject-misc.h b/lib/ephy-gobject-misc.h
new file mode 100644
index 000000000..c14ef1ae7
--- /dev/null
+++ b/lib/ephy-gobject-misc.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2002 Ricardo Fernández Pascual
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define MAKE_GET_TYPE(l,str,t,ci,i,parent) \
+GType l##_get_type(void)\
+{\
+ static GType type = 0; \
+ if (!type) { \
+ static GTypeInfo const object_info = { \
+ sizeof (t##Class), \
+ \
+ (GBaseInitFunc) NULL, \
+ (GBaseFinalizeFunc) NULL, \
+ \
+ (GClassInitFunc) ci, \
+ (GClassFinalizeFunc) NULL, \
+ NULL, /* class_data */ \
+ \
+ sizeof (t), \
+ 0, /* n_preallocs */ \
+ (GInstanceInitFunc) i, \
+ }; \
+ type = g_type_register_static (parent, str, &object_info, 0); \
+ } \
+ return type; \
+}
+
+#define MAKE_GET_TYPE_IFACE(l,str,t,ci,i,parent,ii,iparent) \
+GType l##_get_type(void)\
+{\
+ static GType type = 0; \
+ if (!type) { \
+ static GTypeInfo const object_info = { \
+ sizeof (t##Class), \
+ \
+ (GBaseInitFunc) NULL, \
+ (GBaseFinalizeFunc) NULL, \
+ \
+ (GClassInitFunc) ci, \
+ (GClassFinalizeFunc) NULL, \
+ NULL, /* class_data */ \
+ \
+ sizeof (t), \
+ 0, /* n_preallocs */ \
+ (GInstanceInitFunc) i, \
+ }; \
+ \
+ static const GInterfaceInfo iface_info = { \
+ (GInterfaceInitFunc) ii, \
+ NULL, \
+ NULL \
+ }; \
+ \
+ type = g_type_register_static (parent, str, &object_info, (GTypeFlags)0); \
+ \
+ g_type_add_interface_static (type, \
+ iparent, \
+ &iface_info); \
+ } \
+ return type; \
+}
+
diff --git a/lib/ephy-gui.c b/lib/ephy-gui.c
new file mode 100644
index 000000000..fe4018d38
--- /dev/null
+++ b/lib/ephy-gui.c
@@ -0,0 +1,352 @@
+/*
+ * Copyright (C) 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "ephy-gui.h"
+#include "eel-gconf-extensions.h"
+
+#include <ctype.h>
+#include <string.h>
+#include <libgnome/gnome-i18n.h>
+#include <gtk/gtktreemodel.h>
+
+/* Styles for tab labels */
+GtkStyle *loading_text_style = NULL;
+GtkStyle *new_text_style = NULL;
+
+/**
+ * gul_gui_menu_position_under_widget:
+ */
+void
+ephy_gui_menu_position_under_widget (GtkMenu *menu,
+ gint *x,
+ gint *y,
+ gboolean *push_in,
+ gpointer user_data)
+{
+ GtkWidget *w = GTK_WIDGET (user_data);
+ gint width, height;
+ gint screen_width, screen_height;
+ GtkRequisition requisition;
+
+ gdk_drawable_get_size (w->window, &width, &height);
+ gdk_window_get_origin (w->window, x, y);
+ *y = *y + height;
+
+ gtk_widget_size_request (GTK_WIDGET (menu), &requisition);
+
+ screen_width = gdk_screen_width ();
+ screen_height = gdk_screen_height ();
+
+ *x = CLAMP (*x, 0, MAX (0, screen_width - requisition.width));
+ *y = CLAMP (*y, 0, MAX (0, screen_height - requisition.height));
+}
+
+/**
+ * gul_gui_gtk_radio_button_get: get the active member of a radiobutton
+ * group from one of the buttons in the group. This should be in GTK+!
+ */
+gint
+ephy_gui_gtk_radio_button_get (GtkRadioButton *radio_button)
+{
+ GtkToggleButton *toggle_button;
+ gint i, length;
+ GSList *list;
+
+ /* get group list */
+ list = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio_button));
+ length = g_slist_length (list);
+
+ /* iterate over list to find active button */
+ for (i = 0; list != NULL; i++, list = g_slist_next (list))
+ {
+ /* get button and text */
+ toggle_button = GTK_TOGGLE_BUTTON (list->data);
+ if (gtk_toggle_button_get_active (toggle_button))
+ {
+ break;
+ }
+ }
+
+ /* check we didn't run off end */
+ g_assert (list != NULL);
+
+ /* return index (reverse order!) */
+ return (length - 1) - i;
+}
+
+/**
+ * gul_gui_gtk_radio_button_set: set the active member of a radiobutton
+ * group from one of the buttons in the group. This should be in GTK+!
+ */
+void
+ephy_gui_gtk_radio_button_set (GtkRadioButton *radio_button, gint index)
+{
+ GtkToggleButton *button;
+ GSList *list;
+ gint length;
+
+ /* get the list */
+ list = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio_button));
+
+ /* check out the length */
+ length = g_slist_length (list);
+
+ /* new buttons are *preppended* to the list, so button added as first
+ * has last position in the list */
+ index = (length - 1) - index;
+
+ /* find the right button */
+ button = GTK_TOGGLE_BUTTON (g_slist_nth_data (list, index));
+
+ /* set it... this will de-activate the others in the group */
+ if (gtk_toggle_button_get_active (button) == FALSE)
+ {
+ gtk_toggle_button_set_active (button, TRUE);
+ }
+}
+
+GtkWidget *
+ephy_gui_append_new_menuitem (GtkWidget *menu,
+ const char *mnemonic,
+ GCallback callback,
+ gpointer data)
+{
+ GtkWidget *menu_item;
+
+ menu_item = gtk_menu_item_new_with_mnemonic (mnemonic);
+ gtk_widget_show (menu_item);
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu),
+ menu_item);
+
+ if (callback)
+ {
+ g_signal_connect (G_OBJECT (menu_item),
+ "activate",
+ callback, data);
+ }
+
+ return menu_item;
+}
+
+GtkWidget *
+ephy_gui_append_new_menuitem_stock (GtkWidget *menu,
+ const char *stock_id,
+ GCallback callback,
+ gpointer data)
+{
+ GtkWidget *menu_item;
+
+ menu_item = gtk_image_menu_item_new_from_stock (stock_id, NULL);
+ gtk_widget_show (menu_item);
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu),
+ menu_item);
+
+ if (callback)
+ {
+ g_signal_connect (G_OBJECT (menu_item),
+ "activate",
+ callback, data);
+ }
+
+ return menu_item;
+}
+
+GtkWidget *
+ephy_gui_append_new_menuitem_stock_icon (GtkWidget *menu,
+ const char *stock_id,
+ const char *mnemonic,
+ GCallback callback,
+ gpointer data)
+{
+ GtkWidget *menu_item;
+ GtkWidget *image;
+
+ menu_item = gtk_image_menu_item_new_with_mnemonic (mnemonic);
+ image = gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_MENU);
+ gtk_widget_show (image);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item), image);
+
+ gtk_widget_show (menu_item);
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu),
+ menu_item);
+
+ if (callback)
+ {
+ g_signal_connect (G_OBJECT (menu_item),
+ "activate",
+ callback, data);
+ }
+
+ return menu_item;
+}
+
+GtkWidget *
+ephy_gui_append_new_check_menuitem (GtkWidget *menu,
+ const char *mnemonic,
+ gboolean value,
+ GCallback callback,
+ gpointer data)
+{
+ GtkWidget *menu_item;
+
+ menu_item = gtk_check_menu_item_new_with_mnemonic (mnemonic);
+ gtk_widget_show (menu_item);
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu),
+ menu_item);
+
+ gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menu_item), value);
+
+ if (callback)
+ {
+ g_signal_connect (G_OBJECT (menu_item),
+ "activate",
+ callback, data);
+ }
+
+ return menu_item;
+}
+
+GtkWidget *
+ephy_gui_append_separator (GtkWidget *menu)
+{
+ GtkWidget *menu_item;
+
+ menu_item = gtk_menu_item_new ();
+ gtk_widget_show (menu_item);
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu),
+ menu_item);
+
+ return menu_item;
+}
+
+gboolean
+ephy_gui_confirm_overwrite_file (GtkWidget *parent, const char *filename)
+{
+ char *question;
+ GtkWidget *dialog;
+ gboolean res;
+
+ if (!g_file_test (filename, G_FILE_TEST_EXISTS))
+ {
+ return TRUE;
+ }
+
+ question = g_strdup_printf (_("File %s will be overwritten.\n"
+ "If you choose yes, the contents will be lost.\n\n"
+ "Do you want to continue?"), filename);
+ dialog = gtk_message_dialog_new (parent ? GTK_WINDOW(parent) : NULL,
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_QUESTION,
+ GTK_BUTTONS_YES_NO,
+ question);
+ res = (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_YES);
+ gtk_widget_destroy (dialog);
+ g_free (question);
+
+ return res;
+}
+
+static guint32
+shift_color_component (guchar component, float shift_by)
+{
+ guint32 result;
+ if (shift_by > 1.0) {
+ result = component * (2 - shift_by);
+ } else {
+ result = 0xff - shift_by * (0xff - component);
+ }
+
+ return result & 0xff;
+}
+
+/**
+ * ephy_gui_rgb_shift_color
+ * @color: A color.
+ * @shift_by: darken or lighten factor.
+ * Returns: An darkened or lightened rgb value.
+ *
+ * Darkens (@shift_by > 1) or lightens (@shift_by < 1)
+ * @color.
+ */
+guint32
+ephy_gui_rgb_shift_color (guint32 color, float shift_by)
+{
+ guint32 result;
+
+ /* shift red by shift_by */
+ result = shift_color_component((color & 0x00ff0000) >> 16, shift_by);
+ result <<= 8;
+ /* shift green by shift_by */
+ result |= shift_color_component((color & 0x0000ff00) >> 8, shift_by);
+ result <<= 8;
+ /* shift blue by shift_by */
+ result |= shift_color_component((color & 0x000000ff), shift_by);
+
+ /* alpha doesn't change */
+ result |= (0xff000000 & color);
+
+ return result;
+}
+
+static guint32
+rgb16_to_rgb (gushort r, gushort g, gushort b)
+{
+ guint32 result;
+
+ result = (0xff0000 | (r & 0xff00));
+ result <<= 8;
+ result |= ((g & 0xff00) | (b >> 8));
+
+ return result;
+}
+
+/**
+ * ephy_gui_gdk_color_to_rgb
+ * @color: A GdkColor style color.
+ * Returns: An rgb value.
+ *
+ * Converts from a GdkColor stlye color to a gdk_rgb one.
+ * Alpha gets set to fully opaque
+ */
+guint32
+ephy_gui_gdk_color_to_rgb (const GdkColor *color)
+{
+ return rgb16_to_rgb (color->red, color->green, color->blue);
+}
+
+/**
+ * ephy_gui_rgb_to_color
+ * @color: a gdk_rgb style value.
+ *
+ * Converts from a gdk_rgb value style to a GdkColor one.
+ * The gdk_rgb color alpha channel is ignored.
+ *
+ * Return value: A GdkColor structure version of the given RGB color.
+ */
+GdkColor
+ephy_gui_gdk_rgb_to_color (guint32 color)
+{
+ GdkColor result;
+
+ result.red = ((color >> 16) & 0xFF) * 0x101;
+ result.green = ((color >> 8) & 0xFF) * 0x101;
+ result.blue = (color & 0xff) * 0x101;
+ result.pixel = 0;
+
+ return result;
+}
diff --git a/lib/ephy-gui.h b/lib/ephy-gui.h
new file mode 100644
index 000000000..0d736592f
--- /dev/null
+++ b/lib/ephy-gui.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EPHY_GUI_H
+#define EPHY_GUI_H
+
+/* system includes */
+#include <gtk/gtk.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <libgnomeui/gnome-dialog.h>
+#include <gnome.h>
+
+G_BEGIN_DECLS
+
+void ephy_gui_menu_position_under_widget (GtkMenu *menu,
+ gint *x,
+ gint *y,
+ gboolean *push_in,
+ gpointer user_data);
+
+gint ephy_gui_gtk_radio_button_get (GtkRadioButton *radio_button);
+
+void ephy_gui_gtk_radio_button_set (GtkRadioButton *radio_button,
+ gint index);
+
+GList *ephy_gui_treeview_get_selection_refs (GtkTreeView *treeview);
+
+GtkWidget *ephy_gui_append_new_menuitem (GtkWidget *menu,
+ const char *mnemonic,
+ GCallback callback,
+ gpointer data);
+
+GtkWidget *ephy_gui_append_new_menuitem_stock (GtkWidget *menu,
+ const char *stock_id,
+ GCallback callback,
+ gpointer data);
+
+GtkWidget *ephy_gui_append_new_menuitem_stock_icon (GtkWidget *menu,
+ const char *stock_id,
+ const char *mnemonic,
+ GCallback callback,
+ gpointer data);
+
+GtkWidget *ephy_gui_append_new_check_menuitem (GtkWidget *menu,
+ const char *mnemonic,
+ gboolean value,
+ GCallback callback,
+ gpointer data);
+
+GtkWidget *ephy_gui_append_separator (GtkWidget *menu);
+
+gboolean ephy_gui_confirm_overwrite_file (GtkWidget *parent,
+ const char *filename);
+
+guint32 ephy_gui_rgb_shift_color (guint32 color,
+ float shift_by);
+
+guint32 ephy_gui_gdk_color_to_rgb (const GdkColor *color);
+
+GdkColor ephy_gui_gdk_rgb_to_color (guint32 color);
+
+G_END_DECLS
+
+#endif
diff --git a/lib/ephy-marshal.list b/lib/ephy-marshal.list
new file mode 100644
index 000000000..9082cae25
--- /dev/null
+++ b/lib/ephy-marshal.list
@@ -0,0 +1,16 @@
+VOID:VOID
+VOID:STRING
+VOID:OBJECT
+VOID:OBJECT,OBJECT,INT
+VOID:OBJECT,STRING,INT
+VOID:OBJECT,INT
+VOID:OBJECT,INT,INT
+VOID:POINTER,INT
+VOID:STRING,INT,INT
+VOID:STRING,INT
+VOID:STRING,STRING
+INT:STRING
+VOID:INT,INT
+VOID:INT,INT,INT
+INT:OBJECT
+VOID:POINTER,POINTER
diff --git a/lib/ephy-node-filter.c b/lib/ephy-node-filter.c
new file mode 100644
index 000000000..8f0bddbc0
--- /dev/null
+++ b/lib/ephy-node-filter.c
@@ -0,0 +1,461 @@
+/*
+ * Copyright (C) 2002 Olivier Martin <omartin@ifrance.com>
+ * (C) 2002 Jorn Baayen <jorn@nl.linux.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Id$
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include "ephy-node-filter.h"
+
+static void ephy_node_filter_class_init (EphyNodeFilterClass *klass);
+static void ephy_node_filter_init (EphyNodeFilter *node);
+static void ephy_node_filter_finalize (GObject *object);
+static gboolean ephy_node_filter_expression_evaluate (EphyNodeFilterExpression *expression,
+ EphyNode *node);
+
+enum
+{
+ CHANGED,
+ LAST_SIGNAL
+};
+
+struct EphyNodeFilterPrivate
+{
+ GPtrArray *levels;
+};
+
+struct EphyNodeFilterExpression
+{
+ EphyNodeFilterExpressionType type;
+
+ union
+ {
+ struct
+ {
+ EphyNode *a;
+ EphyNode *b;
+ } node_args;
+
+ struct
+ {
+ int prop_id;
+
+ union
+ {
+ EphyNode *node;
+ char *string;
+ int number;
+ } second_arg;
+ } prop_args;
+ } args;
+};
+
+static GObjectClass *parent_class = NULL;
+
+static guint ephy_node_filter_signals[LAST_SIGNAL] = { 0 };
+
+GType
+ephy_node_filter_get_type (void)
+{
+ static GType ephy_node_filter_type = 0;
+
+ if (ephy_node_filter_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (EphyNodeFilterClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) ephy_node_filter_class_init,
+ NULL,
+ NULL,
+ sizeof (EphyNodeFilter),
+ 0,
+ (GInstanceInitFunc) ephy_node_filter_init
+ };
+
+ ephy_node_filter_type = g_type_register_static (G_TYPE_OBJECT,
+ "EphyNodeFilter",
+ &our_info, 0);
+ }
+
+ return ephy_node_filter_type;
+}
+
+static void
+ephy_node_filter_class_init (EphyNodeFilterClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = ephy_node_filter_finalize;
+
+ ephy_node_filter_signals[CHANGED] =
+ g_signal_new ("changed",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EphyNodeFilterClass, changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+}
+
+static void
+ephy_node_filter_init (EphyNodeFilter *filter)
+{
+ filter->priv = g_new0 (EphyNodeFilterPrivate, 1);
+
+ filter->priv->levels = g_ptr_array_new ();
+}
+
+static void
+ephy_node_filter_finalize (GObject *object)
+{
+ EphyNodeFilter *filter;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (EPHY_IS_NODE_FILTER (object));
+
+ filter = EPHY_NODE_FILTER (object);
+
+ g_return_if_fail (filter->priv != NULL);
+
+ ephy_node_filter_empty (filter);
+
+ g_ptr_array_free (filter->priv->levels, FALSE);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+EphyNodeFilter *
+ephy_node_filter_new (void)
+{
+ EphyNodeFilter *filter;
+
+ filter = EPHY_NODE_FILTER (g_object_new (EPHY_TYPE_NODE_FILTER,
+ NULL));
+
+ g_return_val_if_fail (filter->priv != NULL, NULL);
+
+ return filter;
+}
+
+void
+ephy_node_filter_add_expression (EphyNodeFilter *filter,
+ EphyNodeFilterExpression *exp,
+ int level)
+{
+ while (level >= filter->priv->levels->len)
+ g_ptr_array_add (filter->priv->levels, NULL);
+
+ g_ptr_array_index (filter->priv->levels, level) =
+ g_list_append (g_ptr_array_index (filter->priv->levels, level), exp);
+}
+
+void
+ephy_node_filter_empty (EphyNodeFilter *filter)
+{
+ int i;
+
+ for (i = filter->priv->levels->len - 1; i >= 0; i--)
+ {
+ GList *list, *l;
+
+ list = g_ptr_array_index (filter->priv->levels, i);
+
+ for (l = list; l != NULL; l = g_list_next (l))
+ {
+ EphyNodeFilterExpression *exp;
+
+ exp = (EphyNodeFilterExpression *) l->data;
+
+ ephy_node_filter_expression_free (exp);
+ }
+
+ g_list_free (list);
+
+ g_ptr_array_remove_index (filter->priv->levels, i);
+ }
+}
+
+void
+ephy_node_filter_done_changing (EphyNodeFilter *filter)
+{
+ g_signal_emit (G_OBJECT (filter), ephy_node_filter_signals[CHANGED], 0);
+}
+
+/*
+ * We go through each level evaluating the filter expressions.
+ * Every time we get a match we immediately do a break and jump
+ * to the next level. We'll return FALSE if we arrive to a level
+ * without matches, TRUE otherwise.
+ */
+gboolean
+ephy_node_filter_evaluate (EphyNodeFilter *filter,
+ EphyNode *node)
+{
+ int i;
+
+ for (i = 0; i < filter->priv->levels->len; i++) {
+ GList *l, *list;
+ gboolean handled;
+
+ handled = FALSE;
+
+ list = g_ptr_array_index (filter->priv->levels, i);
+
+ for (l = list; l != NULL; l = g_list_next (l)) {
+ if (ephy_node_filter_expression_evaluate (l->data, node) == TRUE) {
+ handled = TRUE;
+ break;
+ }
+ }
+
+ if (handled == FALSE)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+EphyNodeFilterExpression *
+ephy_node_filter_expression_new (EphyNodeFilterExpressionType type,
+ ...)
+{
+ EphyNodeFilterExpression *exp;
+ va_list valist;
+
+ va_start (valist, type);
+
+ exp = g_new0 (EphyNodeFilterExpression, 1);
+
+ exp->type = type;
+
+ switch (type)
+ {
+ case EPHY_NODE_FILTER_EXPRESSION_NODE_EQUALS:
+ exp->args.node_args.a = va_arg (valist, EphyNode *);
+ exp->args.node_args.b = va_arg (valist, EphyNode *);
+ break;
+ case EPHY_NODE_FILTER_EXPRESSION_EQUALS:
+ case EPHY_NODE_FILTER_EXPRESSION_HAS_PARENT:
+ case EPHY_NODE_FILTER_EXPRESSION_HAS_CHILD:
+ exp->args.node_args.a = va_arg (valist, EphyNode *);
+ break;
+ case EPHY_NODE_FILTER_EXPRESSION_NODE_PROP_EQUALS:
+ case EPHY_NODE_FILTER_EXPRESSION_CHILD_PROP_EQUALS:
+ exp->args.prop_args.prop_id = va_arg (valist, int);
+ exp->args.prop_args.second_arg.node = va_arg (valist, EphyNode *);
+ break;
+ case EPHY_NODE_FILTER_EXPRESSION_STRING_PROP_CONTAINS:
+ case EPHY_NODE_FILTER_EXPRESSION_STRING_PROP_EQUALS:
+ exp->args.prop_args.prop_id = va_arg (valist, int);
+ exp->args.prop_args.second_arg.string = g_utf8_casefold (va_arg (valist, char *), -1);
+ break;
+ case EPHY_NODE_FILTER_EXPRESSION_KEY_PROP_CONTAINS:
+ case EPHY_NODE_FILTER_EXPRESSION_KEY_PROP_EQUALS:
+ {
+ char *folded;
+
+ exp->args.prop_args.prop_id = va_arg (valist, int);
+
+ folded = g_utf8_casefold (va_arg (valist, char *), -1);
+ exp->args.prop_args.second_arg.string = g_utf8_collate_key (folded, -1);
+ g_free (folded);
+ break;
+ }
+ case EPHY_NODE_FILTER_EXPRESSION_INT_PROP_EQUALS:
+ case EPHY_NODE_FILTER_EXPRESSION_INT_PROP_BIGGER_THAN:
+ case EPHY_NODE_FILTER_EXPRESSION_INT_PROP_LESS_THAN:
+ exp->args.prop_args.prop_id = va_arg (valist, int);
+ exp->args.prop_args.second_arg.number = va_arg (valist, int);
+ break;
+ default:
+ break;
+ }
+
+ va_end (valist);
+
+ return exp;
+}
+
+void
+ephy_node_filter_expression_free (EphyNodeFilterExpression *exp)
+{
+ switch (exp->type)
+ {
+ case EPHY_NODE_FILTER_EXPRESSION_STRING_PROP_CONTAINS:
+ case EPHY_NODE_FILTER_EXPRESSION_STRING_PROP_EQUALS:
+ case EPHY_NODE_FILTER_EXPRESSION_KEY_PROP_CONTAINS:
+ case EPHY_NODE_FILTER_EXPRESSION_KEY_PROP_EQUALS:
+ g_free (exp->args.prop_args.second_arg.string);
+ break;
+ default:
+ break;
+ }
+
+ g_free (exp);
+}
+
+static gboolean
+ephy_node_filter_expression_evaluate (EphyNodeFilterExpression *exp,
+ EphyNode *node)
+{
+ switch (exp->type)
+ {
+ case EPHY_NODE_FILTER_EXPRESSION_ALWAYS_TRUE:
+ return TRUE;
+ case EPHY_NODE_FILTER_EXPRESSION_NODE_EQUALS:
+ return (exp->args.node_args.a == exp->args.node_args.b);
+ case EPHY_NODE_FILTER_EXPRESSION_EQUALS:
+ return (exp->args.node_args.a == node);
+ case EPHY_NODE_FILTER_EXPRESSION_HAS_PARENT:
+ return ephy_node_has_child (exp->args.node_args.a, node);
+ case EPHY_NODE_FILTER_EXPRESSION_HAS_CHILD:
+ return ephy_node_has_child (node, exp->args.node_args.a);
+ case EPHY_NODE_FILTER_EXPRESSION_NODE_PROP_EQUALS:
+ {
+ EphyNode *prop;
+
+ prop = ephy_node_get_property_node (node,
+ exp->args.prop_args.prop_id);
+
+ return (prop == exp->args.prop_args.second_arg.node);
+ }
+ case EPHY_NODE_FILTER_EXPRESSION_CHILD_PROP_EQUALS:
+ {
+ EphyNode *prop;
+ GPtrArray *children;
+ int i;
+
+ children = ephy_node_get_children (node);
+ for (i = 0; i < children->len; i++)
+ {
+ EphyNode *child;
+
+ child = g_ptr_array_index (children, i);
+ prop = ephy_node_get_property_node
+ (child, exp->args.prop_args.prop_id);
+
+ if (prop == exp->args.prop_args.second_arg.node)
+ {
+ ephy_node_thaw (node);
+ return TRUE;
+ }
+ }
+
+ ephy_node_thaw (node);
+ return FALSE;
+ }
+ case EPHY_NODE_FILTER_EXPRESSION_STRING_PROP_CONTAINS:
+ {
+ const char *prop;
+ char *folded_case;
+ gboolean ret;
+
+ prop = ephy_node_get_property_string (node,
+ exp->args.prop_args.prop_id);
+ if (prop == NULL)
+ return FALSE;
+
+ folded_case = g_utf8_casefold (prop, -1);
+ ret = (strstr (folded_case, exp->args.prop_args.second_arg.string) != NULL);
+ g_free (folded_case);
+
+ return ret;
+ }
+ case EPHY_NODE_FILTER_EXPRESSION_STRING_PROP_EQUALS:
+ {
+ const char *prop;
+ char *folded_case;
+ gboolean ret;
+
+ prop = ephy_node_get_property_string (node,
+ exp->args.prop_args.prop_id);
+
+ if (prop == NULL)
+ return FALSE;
+
+ folded_case = g_utf8_casefold (prop, -1);
+ ret = (strcmp (folded_case, exp->args.prop_args.second_arg.string) == 0);
+ g_free (folded_case);
+
+ return ret;
+ }
+ case EPHY_NODE_FILTER_EXPRESSION_KEY_PROP_CONTAINS:
+ {
+ const char *prop;
+
+ prop = ephy_node_get_property_string (node,
+ exp->args.prop_args.prop_id);
+
+ if (prop == NULL)
+ return FALSE;
+
+ return (strstr (prop, exp->args.prop_args.second_arg.string) != NULL);
+ }
+ case EPHY_NODE_FILTER_EXPRESSION_KEY_PROP_EQUALS:
+ {
+ const char *prop;
+
+ prop = ephy_node_get_property_string (node,
+ exp->args.prop_args.prop_id);
+
+ if (prop == NULL)
+ return FALSE;
+
+ return (strcmp (prop, exp->args.prop_args.second_arg.string) == 0);
+ }
+ case EPHY_NODE_FILTER_EXPRESSION_INT_PROP_EQUALS:
+ {
+ int prop;
+
+ prop = ephy_node_get_property_int (node,
+ exp->args.prop_args.prop_id);
+
+ return (prop == exp->args.prop_args.second_arg.number);
+ }
+ case EPHY_NODE_FILTER_EXPRESSION_INT_PROP_BIGGER_THAN:
+ {
+ int prop;
+
+ prop = ephy_node_get_property_int (node,
+ exp->args.prop_args.prop_id);
+
+ return (prop > exp->args.prop_args.second_arg.number);
+ }
+ case EPHY_NODE_FILTER_EXPRESSION_INT_PROP_LESS_THAN:
+ {
+ int prop;
+
+ prop = ephy_node_get_property_int (node,
+ exp->args.prop_args.prop_id);
+ g_print ("%d %d\n", prop, exp->args.prop_args.second_arg.number);
+ return (prop < exp->args.prop_args.second_arg.number);
+ }
+ default:
+ break;
+ }
+
+ return FALSE;
+}
diff --git a/lib/ephy-node-filter.h b/lib/ephy-node-filter.h
new file mode 100644
index 000000000..1aedc16c6
--- /dev/null
+++ b/lib/ephy-node-filter.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2002 Olivier Martin <omartin@ifrance.com>
+ * (C) 2002 Jorn Baayen <jorn@nl.linux.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Id$
+ */
+
+#ifndef EPHY_NODE_FILTER_H
+#define EPHY_NODE_FILTER_H
+
+#include <glib-object.h>
+
+#include "ephy-node.h"
+
+G_BEGIN_DECLS
+
+#define EPHY_TYPE_NODE_FILTER (ephy_node_filter_get_type ())
+#define EPHY_NODE_FILTER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EPHY_TYPE_NODE_FILTER, EphyNodeFilter))
+#define EPHY_NODE_FILTER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EPHY_TYPE_NODE_FILTER, EphyNodeFilterClass))
+#define EPHY_IS_NODE_FILTER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EPHY_TYPE_NODE_FILTER))
+#define EPHY_IS_NODE_FILTER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EPHY_TYPE_NODE_FILTER))
+#define EPHY_NODE_FILTER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EPHY_TYPE_NODE_FILTER, EphyNodeFilterClass))
+
+typedef struct EphyNodeFilterPrivate EphyNodeFilterPrivate;
+
+typedef struct
+{
+ GObject parent;
+
+ EphyNodeFilterPrivate *priv;
+} EphyNodeFilter;
+
+typedef struct
+{
+ GObjectClass parent;
+
+ void (*changed) (EphyNodeFilter *filter);
+} EphyNodeFilterClass;
+
+typedef enum
+{
+ EPHY_NODE_FILTER_EXPRESSION_ALWAYS_TRUE, /* args: none */
+ EPHY_NODE_FILTER_EXPRESSION_NODE_EQUALS, /* args: EphyNode *a, EphyNode *b */
+ EPHY_NODE_FILTER_EXPRESSION_EQUALS, /* args: EphyNode *node */
+ EPHY_NODE_FILTER_EXPRESSION_HAS_PARENT, /* args: EphyNode *parent */
+ EPHY_NODE_FILTER_EXPRESSION_HAS_CHILD, /* args: EphyNode *child */
+ EPHY_NODE_FILTER_EXPRESSION_NODE_PROP_EQUALS, /* args: int prop_id, EphyNode *node */
+ EPHY_NODE_FILTER_EXPRESSION_CHILD_PROP_EQUALS, /* args: int prop_id, EphyNode *node */
+ EPHY_NODE_FILTER_EXPRESSION_STRING_PROP_CONTAINS, /* args: int prop_id, const char *string */
+ EPHY_NODE_FILTER_EXPRESSION_STRING_PROP_EQUALS, /* args: int prop_id, const char *string */
+ EPHY_NODE_FILTER_EXPRESSION_KEY_PROP_CONTAINS, /* args: int prop_id, const char *string */
+ EPHY_NODE_FILTER_EXPRESSION_KEY_PROP_EQUALS, /* args: int prop_id, const char *string */
+ EPHY_NODE_FILTER_EXPRESSION_INT_PROP_EQUALS, /* args: int prop_id, int int */
+ EPHY_NODE_FILTER_EXPRESSION_INT_PROP_BIGGER_THAN, /* args: int prop_id, int int */
+ EPHY_NODE_FILTER_EXPRESSION_INT_PROP_LESS_THAN /* args: int prop_id, int int */
+} EphyNodeFilterExpressionType;
+
+typedef struct EphyNodeFilterExpression EphyNodeFilterExpression;
+
+/* The filter starts iterating over all expressions at level 0,
+ * if one of them is TRUE it continues to level 1, etc.
+ * If it still has TRUE when there are no more expressions at the
+ * next level, the result is TRUE. Otherwise, it's FALSE.
+ */
+
+GType ephy_node_filter_get_type (void);
+
+EphyNodeFilter *ephy_node_filter_new (void);
+
+void ephy_node_filter_add_expression (EphyNodeFilter *filter,
+ EphyNodeFilterExpression *expression,
+ int level);
+
+void ephy_node_filter_empty (EphyNodeFilter *filter);
+
+void ephy_node_filter_done_changing (EphyNodeFilter *filter);
+
+gboolean ephy_node_filter_evaluate (EphyNodeFilter *filter,
+ EphyNode *node);
+
+EphyNodeFilterExpression *ephy_node_filter_expression_new (EphyNodeFilterExpressionType,
+ ...);
+/* no need to free unless you didn't add the expression to a filter */
+void ephy_node_filter_expression_free (EphyNodeFilterExpression *expression);
+
+G_END_DECLS
+
+#endif /* EPHY_NODE_FILTER_H */
diff --git a/lib/ephy-node.c b/lib/ephy-node.c
new file mode 100644
index 000000000..b75df9349
--- /dev/null
+++ b/lib/ephy-node.c
@@ -0,0 +1,1439 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen <jorn@nl.linux.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Id$
+ */
+
+#include <config.h>
+#include <libgnome/gnome-i18n.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <gdk/gdk.h>
+#include <time.h>
+
+#include "ephy-node.h"
+#include "ephy-string.h"
+#include "ephy-thread-helpers.h"
+
+static void ephy_node_class_init (EphyNodeClass *klass);
+static void ephy_node_init (EphyNode *node);
+static void ephy_node_finalize (GObject *object);
+static void ephy_node_dispose (GObject *object);
+static void ephy_node_set_object_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void ephy_node_get_object_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+static inline void id_factory_set_to (gulong new_factory_pos);
+static inline void real_set_property (EphyNode *node,
+ guint property_id,
+ GValue *value);
+static inline void real_remove_child (EphyNode *node,
+ EphyNode *child,
+ gboolean remove_from_parent,
+ gboolean remove_from_child);
+static inline void real_add_child (EphyNode *node,
+ EphyNode *child);
+static inline void read_lock_to_write_lock (EphyNode *node);
+static inline void write_lock_to_read_lock (EphyNode *node);
+static inline void lock_gdk (void);
+static inline void unlock_gdk (void);
+static inline EphyNode *node_from_id_real (gulong id);
+static inline int get_child_index_real (EphyNode *node,
+ EphyNode *child);
+
+typedef struct
+{
+ EphyNode *node;
+ guint index;
+} EphyNodeParent;
+
+struct EphyNodePrivate
+{
+ GStaticRWLock *lock;
+
+ int ref_count;
+
+ gulong id;
+
+ GPtrArray *properties;
+
+ GHashTable *parents;
+ GPtrArray *children;
+};
+
+enum
+{
+ PROP_0,
+ PROP_ID
+};
+
+enum
+{
+ DESTROYED,
+ RESTORED,
+ CHILD_ADDED,
+ CHILD_CHANGED,
+ CHILD_REMOVED,
+ LAST_SIGNAL
+};
+
+static GObjectClass *parent_class = NULL;
+
+static guint ephy_node_signals[LAST_SIGNAL] = { 0 };
+
+static GMutex *id_factory_lock = NULL;
+static long id_factory = 0;
+
+static GStaticRWLock *id_to_node_lock = NULL;
+static GPtrArray *id_to_node;
+
+GType
+ephy_node_get_type (void)
+{
+ static GType ephy_node_type = 0;
+
+ if (ephy_node_type == 0) {
+ static const GTypeInfo our_info = {
+ sizeof (EphyNodeClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) ephy_node_class_init,
+ NULL,
+ NULL,
+ sizeof (EphyNode),
+ 0,
+ (GInstanceInitFunc) ephy_node_init
+ };
+
+ ephy_node_type = g_type_register_static (G_TYPE_OBJECT,
+ "EphyNode",
+ &our_info, 0);
+ }
+
+ return ephy_node_type;
+}
+
+static void
+ephy_node_class_init (EphyNodeClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = ephy_node_finalize;
+ object_class->dispose = ephy_node_dispose;
+
+ object_class->set_property = ephy_node_set_object_property;
+ object_class->get_property = ephy_node_get_object_property;
+
+ g_object_class_install_property (object_class,
+ PROP_ID,
+ g_param_spec_long ("id",
+ "Node ID",
+ "Node ID",
+ 0, G_MAXLONG, 0,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+ ephy_node_signals[DESTROYED] =
+ g_signal_new ("destroyed",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EphyNodeClass, destroyed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+ ephy_node_signals[RESTORED] =
+ g_signal_new ("restored",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EphyNodeClass, restored),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+
+ ephy_node_signals[CHILD_ADDED] =
+ g_signal_new ("child_added",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EphyNodeClass, child_added),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE,
+ 1,
+ EPHY_TYPE_NODE);
+ ephy_node_signals[CHILD_CHANGED] =
+ g_signal_new ("child_changed",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EphyNodeClass, child_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE,
+ 1,
+ EPHY_TYPE_NODE);
+ ephy_node_signals[CHILD_REMOVED] =
+ g_signal_new ("child_removed",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EphyNodeClass, child_removed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE,
+ 1,
+ EPHY_TYPE_NODE);
+}
+
+static gboolean
+int_equal (gconstpointer a,
+ gconstpointer b)
+{
+ return GPOINTER_TO_INT (a) == GPOINTER_TO_INT (b);
+}
+
+static guint
+int_hash (gconstpointer a)
+{
+ return GPOINTER_TO_INT (a);
+}
+
+static void
+ephy_node_init (EphyNode *node)
+{
+ node->priv = g_new0 (EphyNodePrivate, 1);
+
+ node->priv->lock = g_new0 (GStaticRWLock, 1);
+ g_static_rw_lock_init (node->priv->lock);
+
+ node->priv->ref_count = 0;
+
+ node->priv->id = -1;
+
+ node->priv->properties = g_ptr_array_new ();
+
+ node->priv->parents = g_hash_table_new_full (int_hash,
+ int_equal,
+ NULL,
+ g_free);
+
+ node->priv->children = g_ptr_array_new ();
+}
+
+static void
+ephy_node_finalize (GObject *object)
+{
+ EphyNode *node;
+ guint i;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (EPHY_IS_NODE (object));
+
+ node = EPHY_NODE (object);
+
+ g_return_if_fail (node->priv != NULL);
+
+ for (i = 0; i < node->priv->properties->len; i++) {
+ GValue *val;
+
+ val = g_ptr_array_index (node->priv->properties, i);
+
+ if (val != NULL) {
+ g_value_unset (val);
+ g_free (val);
+ }
+ }
+ g_ptr_array_free (node->priv->properties, FALSE);
+
+ g_hash_table_destroy (node->priv->parents);
+
+ g_ptr_array_free (node->priv->children, FALSE);
+
+ g_static_rw_lock_free (node->priv->lock);
+
+ g_free (node->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+remove_child (long id,
+ EphyNodeParent *node_info,
+ EphyNode *node)
+{
+ g_static_rw_lock_writer_lock (node_info->node->priv->lock);
+
+ real_remove_child (node_info->node, node, TRUE, FALSE);
+
+ g_static_rw_lock_writer_unlock (node_info->node->priv->lock);
+}
+
+static void
+ephy_node_dispose (GObject *object)
+{
+ EphyNode *node;
+ guint i;
+
+ node = EPHY_NODE (object);
+
+ /* remove from id table */
+ g_static_rw_lock_writer_lock (id_to_node_lock);
+
+ g_ptr_array_index (id_to_node, node->priv->id) = NULL;
+
+ g_static_rw_lock_writer_unlock (id_to_node_lock);
+
+ lock_gdk ();
+
+ /* remove from DAG */
+ g_hash_table_foreach (node->priv->parents,
+ (GHFunc) remove_child,
+ node);
+
+ for (i = 0; i < node->priv->children->len; i++) {
+ EphyNode *child;
+
+ child = g_ptr_array_index (node->priv->children, i);
+
+ g_static_rw_lock_writer_lock (child->priv->lock);
+
+ real_remove_child (node, child, FALSE, TRUE);
+
+ g_static_rw_lock_writer_unlock (child->priv->lock);
+ }
+
+ g_static_rw_lock_writer_unlock (node->priv->lock);
+
+ g_signal_emit (G_OBJECT (node), ephy_node_signals[DESTROYED], 0);
+
+ unlock_gdk ();
+
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+ephy_node_set_object_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EphyNode *node = EPHY_NODE (object);
+
+ switch (prop_id)
+ {
+ case PROP_ID:
+ node->priv->id = g_value_get_long (value);
+
+ g_static_rw_lock_writer_lock (id_to_node_lock);
+
+ /* resize array if needed */
+ if (node->priv->id >= id_to_node->len)
+ g_ptr_array_set_size (id_to_node, node->priv->id + 1);
+
+ g_ptr_array_index (id_to_node, node->priv->id) = node;
+
+ g_static_rw_lock_writer_unlock (id_to_node_lock);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+ephy_node_get_object_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ EphyNode *node = EPHY_NODE (object);
+
+ switch (prop_id)
+ {
+ case PROP_ID:
+ g_value_set_long (value, node->priv->id);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+EphyNode *
+ephy_node_new (void)
+{
+ EphyNode *node;
+
+ node = EPHY_NODE (g_object_new (EPHY_TYPE_NODE,
+ "id", ephy_node_new_id (),
+ NULL));
+
+ g_return_val_if_fail (node->priv != NULL, NULL);
+
+ return node;
+}
+
+long
+ephy_node_get_id (EphyNode *node)
+{
+ long ret;
+
+ g_return_val_if_fail (EPHY_IS_NODE (node), -1);
+
+ g_static_rw_lock_reader_lock (node->priv->lock);
+
+ ret = node->priv->id;
+
+ g_static_rw_lock_reader_unlock (node->priv->lock);
+
+ return ret;
+}
+
+static inline EphyNode *
+node_from_id_real (gulong id)
+{
+ EphyNode *ret = NULL;
+
+ if (id < id_to_node->len)
+ ret = g_ptr_array_index (id_to_node, id);;
+
+ return ret;
+}
+
+EphyNode *
+ephy_node_get_from_id (gulong id)
+{
+ EphyNode *ret = NULL;
+
+ g_return_val_if_fail (id > 0, NULL);
+
+ g_static_rw_lock_reader_lock (id_to_node_lock);
+
+ ret = node_from_id_real (id);
+
+ g_static_rw_lock_reader_unlock (id_to_node_lock);
+
+ return ret;
+}
+
+void
+ephy_node_ref (EphyNode *node)
+{
+ g_return_if_fail (EPHY_IS_NODE (node));
+
+ g_static_rw_lock_writer_lock (node->priv->lock);
+
+ node->priv->ref_count++;
+
+ g_static_rw_lock_writer_unlock (node->priv->lock);
+}
+
+void
+ephy_node_unref (EphyNode *node)
+{
+ g_return_if_fail (EPHY_IS_NODE (node));
+
+ g_static_rw_lock_writer_lock (node->priv->lock);
+
+ node->priv->ref_count--;
+
+ if (node->priv->ref_count <= 0) {
+ g_object_unref (G_OBJECT (node));
+ } else {
+ g_static_rw_lock_writer_unlock (node->priv->lock);
+ }
+}
+
+void
+ephy_node_freeze (EphyNode *node)
+{
+ g_return_if_fail (EPHY_IS_NODE (node));
+
+ g_static_rw_lock_reader_lock (node->priv->lock);
+}
+
+void
+ephy_node_thaw (EphyNode *node)
+{
+ g_return_if_fail (EPHY_IS_NODE (node));
+
+ g_static_rw_lock_reader_unlock (node->priv->lock);
+}
+
+static void
+child_changed (gulong id,
+ EphyNodeParent *node_info,
+ EphyNode *node)
+{
+ g_static_rw_lock_reader_lock (node_info->node->priv->lock);
+
+ g_signal_emit (G_OBJECT (node_info->node), ephy_node_signals[CHILD_CHANGED], 0, node);
+
+ g_static_rw_lock_reader_unlock (node_info->node->priv->lock);
+}
+
+static inline void
+real_set_property (EphyNode *node,
+ guint property_id,
+ GValue *value)
+{
+ GValue *old;
+
+ if (property_id >= node->priv->properties->len) {
+ g_ptr_array_set_size (node->priv->properties, property_id + 1);
+ }
+
+ old = g_ptr_array_index (node->priv->properties, property_id);
+ if (old != NULL) {
+ g_value_unset (old);
+ g_free (old);
+ }
+
+ g_ptr_array_index (node->priv->properties, property_id) = value;
+}
+
+void
+ephy_node_set_property (EphyNode *node,
+ guint property_id,
+ const GValue *value)
+{
+ GValue *new;
+
+ g_return_if_fail (EPHY_IS_NODE (node));
+ g_return_if_fail (property_id >= 0);
+ g_return_if_fail (value != NULL);
+
+ lock_gdk ();
+
+ g_static_rw_lock_writer_lock (node->priv->lock);
+
+ new = g_new0 (GValue, 1);
+ g_value_init (new, G_VALUE_TYPE (value));
+ g_value_copy (value, new);
+
+ real_set_property (node, property_id, new);
+
+ write_lock_to_read_lock (node);
+
+ g_hash_table_foreach (node->priv->parents,
+ (GHFunc) child_changed,
+ node);
+
+ g_static_rw_lock_reader_unlock (node->priv->lock);
+
+ unlock_gdk ();
+}
+
+gboolean
+ephy_node_get_property (EphyNode *node,
+ guint property_id,
+ GValue *value)
+{
+ GValue *ret;
+
+ g_return_val_if_fail (EPHY_IS_NODE (node), FALSE);
+ g_return_val_if_fail (property_id >= 0, FALSE);
+ g_return_val_if_fail (value != NULL, FALSE);
+
+ g_static_rw_lock_reader_lock (node->priv->lock);
+
+ if (property_id >= node->priv->properties->len) {
+ g_static_rw_lock_reader_unlock (node->priv->lock);
+ return FALSE;
+ }
+
+ ret = g_ptr_array_index (node->priv->properties, property_id);
+ if (ret == NULL) {
+ g_static_rw_lock_reader_unlock (node->priv->lock);
+ return FALSE;
+ }
+
+ g_value_init (value, G_VALUE_TYPE (ret));
+ g_value_copy (ret, value);
+
+ g_static_rw_lock_reader_unlock (node->priv->lock);
+
+ return TRUE;
+}
+
+const char *
+ephy_node_get_property_string (EphyNode *node,
+ guint property_id)
+{
+ GValue *ret;
+ const char *retval;
+
+ g_return_val_if_fail (EPHY_IS_NODE (node), NULL);
+ g_return_val_if_fail (property_id >= 0, NULL);
+
+ g_static_rw_lock_reader_lock (node->priv->lock);
+
+ if (property_id >= node->priv->properties->len) {
+ g_static_rw_lock_reader_unlock (node->priv->lock);
+ return NULL;
+ }
+
+ ret = g_ptr_array_index (node->priv->properties, property_id);
+ if (ret == NULL) {
+ g_static_rw_lock_reader_unlock (node->priv->lock);
+ return NULL;
+ }
+
+ retval = g_value_get_string (ret);
+
+ g_static_rw_lock_reader_unlock (node->priv->lock);
+
+ return retval;
+}
+
+gboolean
+ephy_node_get_property_boolean (EphyNode *node,
+ guint property_id)
+{
+ GValue *ret;
+ gboolean retval;
+
+ g_return_val_if_fail (EPHY_IS_NODE (node), FALSE);
+ g_return_val_if_fail (property_id >= 0, FALSE);
+
+ g_static_rw_lock_reader_lock (node->priv->lock);
+
+ if (property_id >= node->priv->properties->len) {
+ g_static_rw_lock_reader_unlock (node->priv->lock);
+ return FALSE;
+ }
+
+ ret = g_ptr_array_index (node->priv->properties, property_id);
+ if (ret == NULL) {
+ g_static_rw_lock_reader_unlock (node->priv->lock);
+ return FALSE;
+ }
+
+ retval = g_value_get_boolean (ret);
+
+ g_static_rw_lock_reader_unlock (node->priv->lock);
+
+ return retval;
+}
+
+long
+ephy_node_get_property_long (EphyNode *node,
+ guint property_id)
+{
+ GValue *ret;
+ long retval;
+
+ g_return_val_if_fail (EPHY_IS_NODE (node), -1);
+ g_return_val_if_fail (property_id >= 0, -1);
+
+ g_static_rw_lock_reader_lock (node->priv->lock);
+
+ if (property_id >= node->priv->properties->len) {
+ g_static_rw_lock_reader_unlock (node->priv->lock);
+ return -1;
+ }
+
+ ret = g_ptr_array_index (node->priv->properties, property_id);
+ if (ret == NULL) {
+ g_static_rw_lock_reader_unlock (node->priv->lock);
+ return -1;
+ }
+
+ retval = g_value_get_long (ret);
+
+ g_static_rw_lock_reader_unlock (node->priv->lock);
+
+ return retval;
+}
+
+int
+ephy_node_get_property_int (EphyNode *node,
+ guint property_id)
+{
+ GValue *ret;
+ int retval;
+
+ g_return_val_if_fail (EPHY_IS_NODE (node), -1);
+ g_return_val_if_fail (property_id >= 0, -1);
+
+ g_static_rw_lock_reader_lock (node->priv->lock);
+
+ if (property_id >= node->priv->properties->len) {
+ g_static_rw_lock_reader_unlock (node->priv->lock);
+ return -1;
+ }
+
+ ret = g_ptr_array_index (node->priv->properties, property_id);
+ if (ret == NULL) {
+ g_static_rw_lock_reader_unlock (node->priv->lock);
+ return -1;
+ }
+
+ retval = g_value_get_int (ret);
+
+ g_static_rw_lock_reader_unlock (node->priv->lock);
+
+ return retval;
+}
+
+double
+ephy_node_get_property_double (EphyNode *node,
+ guint property_id)
+{
+ GValue *ret;
+ double retval;
+
+ g_return_val_if_fail (EPHY_IS_NODE (node), -1);
+ g_return_val_if_fail (property_id >= 0, -1);
+
+ g_static_rw_lock_reader_lock (node->priv->lock);
+
+ if (property_id >= node->priv->properties->len) {
+ g_static_rw_lock_reader_unlock (node->priv->lock);
+ return -1;
+ }
+
+ ret = g_ptr_array_index (node->priv->properties, property_id);
+ if (ret == NULL) {
+ g_static_rw_lock_reader_unlock (node->priv->lock);
+ return -1;
+ }
+
+ retval = g_value_get_double (ret);
+
+ g_static_rw_lock_reader_unlock (node->priv->lock);
+
+ return retval;
+}
+
+float
+ephy_node_get_property_float (EphyNode *node,
+ guint property_id)
+{
+ GValue *ret;
+ float retval;
+
+ g_return_val_if_fail (EPHY_IS_NODE (node), -1);
+ g_return_val_if_fail (property_id >= 0, -1);
+
+ g_static_rw_lock_reader_lock (node->priv->lock);
+
+ if (property_id >= node->priv->properties->len) {
+ g_static_rw_lock_reader_unlock (node->priv->lock);
+ return -1;
+ }
+
+ ret = g_ptr_array_index (node->priv->properties, property_id);
+ if (ret == NULL) {
+ g_static_rw_lock_reader_unlock (node->priv->lock);
+ return -1;
+ }
+
+ retval = g_value_get_float (ret);
+
+ g_static_rw_lock_reader_unlock (node->priv->lock);
+
+ return retval;
+}
+
+EphyNode *
+ephy_node_get_property_node (EphyNode *node,
+ guint property_id)
+{
+ GValue *ret;
+ EphyNode *retval;
+
+ g_return_val_if_fail (EPHY_IS_NODE (node), NULL);
+ g_return_val_if_fail (property_id >= 0, NULL);
+
+ g_static_rw_lock_reader_lock (node->priv->lock);
+
+ if (property_id >= node->priv->properties->len) {
+ g_static_rw_lock_reader_unlock (node->priv->lock);
+ return NULL;
+ }
+
+ ret = g_ptr_array_index (node->priv->properties, property_id);
+ if (ret == NULL) {
+ g_static_rw_lock_reader_unlock (node->priv->lock);
+ return NULL;
+ }
+
+ retval = g_value_get_pointer (ret);
+
+ g_static_rw_lock_reader_unlock (node->priv->lock);
+
+ return retval;
+}
+
+char *
+ephy_node_get_property_time (EphyNode *node,
+ guint property_id)
+{
+ GValue *ret;
+ long mtime;
+ char *retval;
+
+ g_return_val_if_fail (EPHY_IS_NODE (node), NULL);
+ g_return_val_if_fail (property_id >= 0, NULL);
+
+ g_static_rw_lock_reader_lock (node->priv->lock);
+
+ if (property_id >= node->priv->properties->len) {
+ g_static_rw_lock_reader_unlock (node->priv->lock);
+ return g_strdup (_("Never"));
+ }
+
+ ret = g_ptr_array_index (node->priv->properties, property_id);
+ if (ret == NULL) {
+ g_static_rw_lock_reader_unlock (node->priv->lock);
+ return g_strdup (_("Never"));
+ }
+
+ mtime = g_value_get_long (ret);
+
+ if (retval >= 0) {
+ GDate *now, *file_date;
+ guint32 file_date_age;
+ const char *format = NULL;
+
+ now = g_date_new ();
+ g_date_set_time (now, time (NULL));
+
+ file_date = g_date_new ();
+ g_date_set_time (file_date, mtime);
+
+ file_date_age = (g_date_get_julian (now) - g_date_get_julian (file_date));
+
+ g_date_free (file_date);
+ g_date_free (now);
+
+ if (file_date_age == 0) {
+ format = _("Today at %-H:%M");
+ } else if (file_date_age == 1) {
+ format = _("Yesterday at %-H:%M");
+ } else {
+ format = _("%A, %B %-d %Y at %-H:%M");
+ }
+
+ retval = ephy_string_time_to_string (file_date, format);
+ } else {
+ retval = g_strdup (_("Never"));
+ }
+
+ g_static_rw_lock_reader_unlock (node->priv->lock);
+
+ return retval;
+}
+
+static void
+save_parent (gulong id,
+ EphyNodeParent *node_info,
+ xmlNodePtr xml_node)
+{
+ xmlNodePtr parent_xml_node;
+ char *xml;
+
+ parent_xml_node = xmlNewChild (xml_node, NULL, "parent", NULL);
+
+ g_static_rw_lock_reader_lock (node_info->node->priv->lock);
+
+ xml = g_strdup_printf ("%ld", node_info->node->priv->id);
+ xmlSetProp (parent_xml_node, "id", xml);
+ g_free (xml);
+
+ g_static_rw_lock_reader_unlock (node_info->node->priv->lock);
+}
+
+void
+ephy_node_save_to_xml (EphyNode *node,
+ xmlNodePtr parent_xml_node)
+{
+ xmlNodePtr xml_node;
+ char *xml;
+ guint i;
+
+ g_return_if_fail (EPHY_IS_NODE (node));
+ g_return_if_fail (parent_xml_node != NULL);
+
+ g_static_rw_lock_reader_lock (node->priv->lock);
+
+ xml_node = xmlNewChild (parent_xml_node, NULL, "node", NULL);
+
+ xml = g_strdup_printf ("%ld", node->priv->id);
+ xmlSetProp (xml_node, "id", xml);
+ g_free (xml);
+
+ xmlSetProp (xml_node, "type", G_OBJECT_TYPE_NAME (node));
+
+ for (i = 0; i < node->priv->properties->len; i++) {
+ GValue *value;
+ xmlNodePtr value_xml_node;
+
+ value = g_ptr_array_index (node->priv->properties, i);
+ if (value == NULL)
+ continue;
+
+ value_xml_node = xmlNewChild (xml_node, NULL, "property", NULL);
+
+ xml = g_strdup_printf ("%d", i);
+ xmlSetProp (value_xml_node, "id", xml);
+ g_free (xml);
+
+ xmlSetProp (value_xml_node, "value_type", g_type_name (G_VALUE_TYPE (value)));
+
+ switch (G_VALUE_TYPE (value))
+ {
+ case G_TYPE_STRING:
+ xml = xmlEncodeEntitiesReentrant (NULL,
+ g_value_get_string (value));
+ xmlNodeSetContent (value_xml_node, xml);
+ g_free (xml);
+ break;
+ case G_TYPE_BOOLEAN:
+ xml = g_strdup_printf ("%d", g_value_get_boolean (value));
+ xmlNodeSetContent (value_xml_node, xml);
+ g_free (xml);
+ break;
+ case G_TYPE_INT:
+ xml = g_strdup_printf ("%d", g_value_get_int (value));
+ xmlNodeSetContent (value_xml_node, xml);
+ g_free (xml);
+ break;
+ case G_TYPE_LONG:
+ xml = g_strdup_printf ("%ld", g_value_get_long (value));
+ xmlNodeSetContent (value_xml_node, xml);
+ g_free (xml);
+ break;
+ case G_TYPE_FLOAT:
+ xml = g_strdup_printf ("%f", g_value_get_float (value));
+ xmlNodeSetContent (value_xml_node, xml);
+ g_free (xml);
+ break;
+ case G_TYPE_DOUBLE:
+ xml = g_strdup_printf ("%f", g_value_get_double (value));
+ xmlNodeSetContent (value_xml_node, xml);
+ g_free (xml);
+ break;
+ case G_TYPE_POINTER:
+ {
+ EphyNode *prop_node;
+
+ prop_node = g_value_get_pointer (value);
+
+ g_assert (prop_node != NULL);
+
+ g_static_rw_lock_reader_lock (prop_node->priv->lock);
+
+ xml = g_strdup_printf ("%ld", prop_node->priv->id);
+ xmlNodeSetContent (value_xml_node, xml);
+ g_free (xml);
+
+ g_static_rw_lock_reader_unlock (prop_node->priv->lock);
+ break;
+ }
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ }
+
+ g_hash_table_foreach (node->priv->parents,
+ (GHFunc) save_parent,
+ xml_node);
+
+ g_static_rw_lock_reader_unlock (node->priv->lock);
+}
+
+/* this function assumes it's safe to not lock anything while loading,
+ * this is at least true for the case where we're loading the library xml file
+ * from the main loop */
+EphyNode *
+ephy_node_new_from_xml (xmlNodePtr xml_node)
+{
+ EphyNode *node;
+ xmlNodePtr xml_child;
+ char *xml;
+ long id;
+ GType type;
+
+ g_return_val_if_fail (xml_node != NULL, NULL);
+
+ xml = xmlGetProp (xml_node, "id");
+ if (xml == NULL)
+ return NULL;
+ id = atol (xml);
+ g_free (xml);
+
+ id_factory_set_to (id);
+
+ xml = xmlGetProp (xml_node, "type");
+ type = g_type_from_name (xml);
+ g_free (xml);
+
+ node = EPHY_NODE (g_object_new (type,
+ "id", id,
+ NULL));
+
+ g_return_val_if_fail (node->priv != NULL, NULL);
+
+ for (xml_child = xml_node->children; xml_child != NULL; xml_child = xml_child->next) {
+ if (strcmp (xml_child->name, "parent") == 0) {
+ EphyNode *parent;
+ long parent_id;
+
+ xml = xmlGetProp (xml_child, "id");
+ g_assert (xml != NULL);
+ parent_id = atol (xml);
+ g_free (xml);
+
+ parent = node_from_id_real (parent_id);
+
+ if (parent != NULL)
+ {
+ real_add_child (parent, node);
+
+ g_signal_emit (G_OBJECT (parent), ephy_node_signals[CHILD_ADDED],
+ 0, node);
+ }
+ } else if (strcmp (xml_child->name, "property") == 0) {
+ GType value_type;
+ GValue *value;
+ int property_id;
+
+ xml = xmlGetProp (xml_child, "id");
+ property_id = atoi (xml);
+ g_free (xml);
+
+ xml = xmlGetProp (xml_child, "value_type");
+ value_type = g_type_from_name (xml);
+ g_free (xml);
+
+ xml = xmlNodeGetContent (xml_child);
+ value = g_new0 (GValue, 1);
+ g_value_init (value, value_type);
+
+ switch (value_type)
+ {
+ case G_TYPE_STRING:
+ g_value_set_string (value, xml);
+ break;
+ case G_TYPE_INT:
+ g_value_set_int (value, atoi (xml));
+ break;
+ case G_TYPE_BOOLEAN:
+ g_value_set_boolean (value, atoi (xml));
+ break;
+ case G_TYPE_LONG:
+ g_value_set_long (value, atol (xml));
+ break;
+ case G_TYPE_FLOAT:
+ g_value_set_float (value, atof (xml));
+ break;
+ case G_TYPE_DOUBLE:
+ g_value_set_double (value, atof (xml));
+ break;
+ case G_TYPE_POINTER:
+ {
+ EphyNode *property_node;
+
+ property_node = node_from_id_real (atol (xml));
+
+ g_value_set_pointer (value, property_node);
+ break;
+ }
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ real_set_property (node, property_id, value);
+
+ g_free (xml);
+ }
+ }
+
+ g_signal_emit (G_OBJECT (node), ephy_node_signals[RESTORED], 0);
+
+ return node;
+}
+
+static inline void
+real_add_child (EphyNode *node,
+ EphyNode *child)
+{
+ EphyNodeParent *node_info;
+
+ if (g_hash_table_lookup (child->priv->parents,
+ GINT_TO_POINTER (node->priv->id)) != NULL) {
+ return;
+ }
+
+ g_ptr_array_add (node->priv->children, child);
+
+ node_info = g_new0 (EphyNodeParent, 1);
+ node_info->node = node;
+ node_info->index = node->priv->children->len - 1;
+
+ g_hash_table_insert (child->priv->parents,
+ GINT_TO_POINTER (node->priv->id),
+ node_info);
+}
+
+void
+ephy_node_add_child (EphyNode *node,
+ EphyNode *child)
+{
+ g_return_if_fail (EPHY_IS_NODE (node));
+ g_return_if_fail (EPHY_IS_NODE (child));
+
+ lock_gdk ();
+
+ g_static_rw_lock_writer_lock (node->priv->lock);
+ g_static_rw_lock_writer_lock (child->priv->lock);
+
+ real_add_child (node, child);
+
+ write_lock_to_read_lock (node);
+ write_lock_to_read_lock (child);
+
+ g_signal_emit (G_OBJECT (node), ephy_node_signals[CHILD_ADDED], 0, child);
+
+ g_static_rw_lock_reader_unlock (node->priv->lock);
+ g_static_rw_lock_reader_unlock (child->priv->lock);
+
+ unlock_gdk ();
+}
+
+static inline void
+real_remove_child (EphyNode *node,
+ EphyNode *child,
+ gboolean remove_from_parent,
+ gboolean remove_from_child)
+{
+ EphyNodeParent *node_info;
+
+ write_lock_to_read_lock (node);
+ write_lock_to_read_lock (child);
+
+ g_signal_emit (G_OBJECT (node), ephy_node_signals[CHILD_REMOVED], 0, child);
+
+ read_lock_to_write_lock (node);
+ read_lock_to_write_lock (child);
+
+ node_info = g_hash_table_lookup (child->priv->parents,
+ GINT_TO_POINTER (node->priv->id));
+
+ if (remove_from_parent) {
+ guint i;
+
+ g_ptr_array_remove_index (node->priv->children,
+ node_info->index);
+
+ /* correct indices on kids */
+ for (i = node_info->index; i < node->priv->children->len; i++) {
+ EphyNode *borked_node;
+ EphyNodeParent *borked_node_info;
+
+ borked_node = g_ptr_array_index (node->priv->children, i);
+
+ g_static_rw_lock_writer_lock (borked_node->priv->lock);
+
+ borked_node_info = g_hash_table_lookup (borked_node->priv->parents,
+ GINT_TO_POINTER (node->priv->id));
+ borked_node_info->index--;
+
+ g_static_rw_lock_writer_unlock (borked_node->priv->lock);
+ }
+ }
+
+ if (remove_from_child) {
+ g_hash_table_remove (child->priv->parents,
+ GINT_TO_POINTER (node->priv->id));
+ }
+}
+
+void
+ephy_node_remove_child (EphyNode *node,
+ EphyNode *child)
+{
+ g_return_if_fail (EPHY_IS_NODE (node));
+ g_return_if_fail (EPHY_IS_NODE (child));
+
+ lock_gdk ();
+
+ g_static_rw_lock_writer_lock (node->priv->lock);
+ g_static_rw_lock_writer_lock (child->priv->lock);
+
+ real_remove_child (node, child, TRUE, TRUE);
+
+ g_static_rw_lock_writer_unlock (node->priv->lock);
+ g_static_rw_lock_writer_unlock (child->priv->lock);
+
+ unlock_gdk ();
+}
+
+gboolean
+ephy_node_has_child (EphyNode *node,
+ EphyNode *child)
+{
+ gboolean ret;
+
+ g_return_val_if_fail (EPHY_IS_NODE (node), FALSE);
+ g_return_val_if_fail (EPHY_IS_NODE (child), FALSE);
+
+ g_static_rw_lock_reader_lock (node->priv->lock);
+ g_static_rw_lock_reader_lock (child->priv->lock);
+
+ ret = (g_hash_table_lookup (child->priv->parents,
+ GINT_TO_POINTER (node->priv->id)) != NULL);
+
+ g_static_rw_lock_reader_unlock (node->priv->lock);
+ g_static_rw_lock_reader_unlock (child->priv->lock);
+
+ return ret;
+}
+
+GPtrArray *
+ephy_node_get_children (EphyNode *node)
+{
+ g_return_val_if_fail (EPHY_IS_NODE (node), NULL);
+
+ g_static_rw_lock_reader_lock (node->priv->lock);
+
+ return node->priv->children;
+}
+
+int
+ephy_node_get_n_children (EphyNode *node)
+{
+ int ret;
+
+ g_return_val_if_fail (EPHY_IS_NODE (node), -1);
+
+ g_static_rw_lock_reader_lock (node->priv->lock);
+
+ ret = node->priv->children->len;
+
+ g_static_rw_lock_reader_unlock (node->priv->lock);
+
+ return ret;
+}
+
+EphyNode *
+ephy_node_get_nth_child (EphyNode *node,
+ guint n)
+{
+ EphyNode *ret;
+
+ g_return_val_if_fail (EPHY_IS_NODE (node), NULL);
+ g_return_val_if_fail (n >= 0, NULL);
+
+ g_static_rw_lock_reader_lock (node->priv->lock);
+
+ if (n < node->priv->children->len) {
+ ret = g_ptr_array_index (node->priv->children, n);
+ } else {
+ ret = NULL;
+ }
+
+ g_static_rw_lock_reader_unlock (node->priv->lock);
+
+ return ret;
+}
+
+static inline int
+get_child_index_real (EphyNode *node,
+ EphyNode *child)
+{
+ EphyNodeParent *node_info;
+
+ node_info = g_hash_table_lookup (child->priv->parents,
+ GINT_TO_POINTER (node->priv->id));
+
+ if (node_info == NULL)
+ return -1;
+
+ return node_info->index;
+}
+
+int
+ephy_node_get_child_index (EphyNode *node,
+ EphyNode *child)
+{
+ EphyNodeParent *node_info;
+ int ret;
+
+ g_return_val_if_fail (EPHY_IS_NODE (node), -1);
+ g_return_val_if_fail (EPHY_IS_NODE (child), -1);
+
+ g_static_rw_lock_reader_lock (node->priv->lock);
+ g_static_rw_lock_reader_lock (child->priv->lock);
+
+ node_info = g_hash_table_lookup (child->priv->parents,
+ GINT_TO_POINTER (node->priv->id));
+
+ if (node_info == NULL)
+ return -1;
+
+ ret = node_info->index;
+
+ g_static_rw_lock_reader_unlock (node->priv->lock);
+ g_static_rw_lock_reader_unlock (child->priv->lock);
+
+ return ret;
+}
+
+EphyNode *
+ephy_node_get_next_child (EphyNode *node,
+ EphyNode *child)
+{
+ EphyNode *ret;
+ guint idx;
+
+ g_return_val_if_fail (EPHY_IS_NODE (node), NULL);
+ g_return_val_if_fail (EPHY_IS_NODE (child), NULL);
+
+ g_static_rw_lock_reader_lock (node->priv->lock);
+ g_static_rw_lock_reader_lock (child->priv->lock);
+
+ idx = get_child_index_real (node, child);
+
+ if ((idx + 1) < node->priv->children->len) {
+ ret = g_ptr_array_index (node->priv->children, idx + 1);
+ } else {
+ ret = NULL;
+ }
+
+ g_static_rw_lock_reader_unlock (node->priv->lock);
+ g_static_rw_lock_reader_unlock (child->priv->lock);
+
+ return ret;
+}
+
+EphyNode *
+ephy_node_get_previous_child (EphyNode *node,
+ EphyNode *child)
+{
+ EphyNode *ret;
+ int idx;
+
+ g_return_val_if_fail (EPHY_IS_NODE (node), NULL);
+ g_return_val_if_fail (EPHY_IS_NODE (child), NULL);
+
+ g_static_rw_lock_reader_lock (node->priv->lock);
+ g_static_rw_lock_reader_lock (child->priv->lock);
+
+ idx = get_child_index_real (node, child);
+
+ if ((idx - 1) >= 0) {
+ ret = g_ptr_array_index (node->priv->children, idx - 1);
+ } else {
+ ret = NULL;
+ }
+
+ g_static_rw_lock_reader_unlock (node->priv->lock);
+ g_static_rw_lock_reader_unlock (child->priv->lock);
+
+ return ret;
+}
+
+void
+ephy_node_system_init (void)
+{
+ /* id to node */
+ id_to_node = g_ptr_array_new ();
+
+ id_to_node_lock = g_new0 (GStaticRWLock, 1);
+ g_static_rw_lock_init (id_to_node_lock);
+
+ /* id factory */
+ id_factory = 0;
+ id_factory_lock = g_mutex_new ();
+}
+
+void
+ephy_node_system_shutdown (void)
+{
+ g_ptr_array_free (id_to_node, FALSE);
+
+ g_static_rw_lock_free (id_to_node_lock);
+
+ g_mutex_free (id_factory_lock);
+}
+
+long
+ephy_node_new_id (void)
+{
+ long ret;
+
+ g_mutex_lock (id_factory_lock);
+
+ id_factory++;
+
+ ret = id_factory;
+
+ g_mutex_unlock (id_factory_lock);
+
+ return ret;
+}
+
+static void
+id_factory_set_to (gulong new_factory_pos)
+{
+ id_factory = new_factory_pos + 1;
+}
+
+/* evillish hacks to temporarily readlock->writelock and v.v. */
+static inline void
+write_lock_to_read_lock (EphyNode *node)
+{
+ g_static_mutex_lock (&node->priv->lock->mutex);
+ node->priv->lock->read_counter++;
+ g_static_mutex_unlock (&node->priv->lock->mutex);
+
+ g_static_rw_lock_writer_unlock (node->priv->lock);
+}
+
+static inline void
+read_lock_to_write_lock (EphyNode *node)
+{
+ g_static_mutex_lock (&node->priv->lock->mutex);
+ node->priv->lock->read_counter--;
+ g_static_mutex_unlock (&node->priv->lock->mutex);
+
+ g_static_rw_lock_writer_lock (node->priv->lock);
+}
+
+static inline void
+lock_gdk (void)
+{
+ if (ephy_thread_helpers_in_main_thread () == FALSE)
+ GDK_THREADS_ENTER ();
+}
+
+static inline void
+unlock_gdk (void)
+{
+ if (ephy_thread_helpers_in_main_thread () == FALSE)
+ GDK_THREADS_LEAVE ();
+}
diff --git a/lib/ephy-node.h b/lib/ephy-node.h
new file mode 100644
index 000000000..2e5f92210
--- /dev/null
+++ b/lib/ephy-node.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen <jorn@nl.linux.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Id$
+ */
+
+#ifndef EPHY_NODE_H
+#define EPHY_NODE_H
+
+#include <glib-object.h>
+
+#include <libxml/tree.h>
+
+G_BEGIN_DECLS
+
+#define EPHY_TYPE_NODE (ephy_node_get_type ())
+#define EPHY_NODE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EPHY_TYPE_NODE, EphyNode))
+#define EPHY_NODE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EPHY_TYPE_NODE, EphyNodeClass))
+#define EPHY_IS_NODE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EPHY_TYPE_NODE))
+#define EPHY_IS_NODE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EPHY_TYPE_NODE))
+#define EPHY_NODE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EPHY_TYPE_NODE, EphyNodeClass))
+
+typedef struct EphyNodePrivate EphyNodePrivate;
+
+typedef struct
+{
+ GObject parent;
+
+ EphyNodePrivate *priv;
+} EphyNode;
+
+typedef struct
+{
+ GObjectClass parent;
+
+ /* signals */
+ void (*destroyed) (EphyNode *node);
+ void (*restored) (EphyNode *node);
+
+ void (*child_added) (EphyNode *node, EphyNode *child);
+ void (*child_changed) (EphyNode *node, EphyNode *child);
+ void (*child_reordered) (EphyNode *node, EphyNode *child,
+ int old_index, int new_index);
+ void (*child_removed) (EphyNode *node, EphyNode *child);
+} EphyNodeClass;
+
+GType ephy_node_get_type (void);
+
+EphyNode *ephy_node_new (void);
+
+/* unique node ID */
+long ephy_node_get_id (EphyNode *node);
+
+EphyNode *ephy_node_get_from_id (gulong id);
+
+/* refcounting */
+void ephy_node_ref (EphyNode *node);
+void ephy_node_unref (EphyNode *node);
+
+/* locking */
+void ephy_node_freeze (EphyNode *node);
+void ephy_node_thaw (EphyNode *node);
+
+/* property interface */
+enum
+{
+ EPHY_NODE_PROP_NAME = 0,
+ EPHY_NODE_PROP_NAME_SORT_KEY = 1
+};
+
+void ephy_node_set_property (EphyNode *node,
+ guint property_id,
+ const GValue *value);
+gboolean ephy_node_get_property (EphyNode *node,
+ guint property_id,
+ GValue *value);
+
+const char *ephy_node_get_property_string (EphyNode *node,
+ guint property_id);
+gboolean ephy_node_get_property_boolean (EphyNode *node,
+ guint property_id);
+long ephy_node_get_property_long (EphyNode *node,
+ guint property_id);
+int ephy_node_get_property_int (EphyNode *node,
+ guint property_id);
+double ephy_node_get_property_double (EphyNode *node,
+ guint property_id);
+float ephy_node_get_property_float (EphyNode *node,
+ guint property_id);
+EphyNode *ephy_node_get_property_node (EphyNode *node,
+ guint property_id);
+/* free return value */
+char *ephy_node_get_property_time (EphyNode *node,
+ guint property_id);
+
+/* xml storage */
+void ephy_node_save_to_xml (EphyNode *node,
+ xmlNodePtr parent_xml_node);
+EphyNode *ephy_node_new_from_xml (xmlNodePtr xml_node);
+
+/* DAG structure */
+void ephy_node_add_child (EphyNode *node,
+ EphyNode *child);
+void ephy_node_remove_child (EphyNode *node,
+ EphyNode *child);
+gboolean ephy_node_has_child (EphyNode *node,
+ EphyNode *child);
+
+/* Note that ephy_node_get_children freezes the node; you'll have to thaw it when done.
+ * This is to prevent the data getting changed from another thread. */
+GPtrArray *ephy_node_get_children (EphyNode *node);
+int ephy_node_get_n_children (EphyNode *node);
+EphyNode *ephy_node_get_nth_child (EphyNode *node,
+ guint n);
+int ephy_node_get_child_index (EphyNode *node,
+ EphyNode *child);
+EphyNode *ephy_node_get_next_child (EphyNode *node,
+ EphyNode *child);
+EphyNode *ephy_node_get_previous_child (EphyNode *node,
+ EphyNode *child);
+
+/* node id services */
+void ephy_node_system_init (void);
+void ephy_node_system_shutdown (void);
+
+long ephy_node_new_id (void);
+
+G_END_DECLS
+
+#endif /* __EPHY_NODE_H */
diff --git a/lib/ephy-prefs-utils.c b/lib/ephy-prefs-utils.c
new file mode 100644
index 000000000..0e0cf4a50
--- /dev/null
+++ b/lib/ephy-prefs-utils.c
@@ -0,0 +1,285 @@
+/*
+ * Copyright (C) 2000 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "ephy-prefs-utils.h"
+#include "ephy-gui.h"
+#include "eel-gconf-extensions.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <gtk/gtkmenu.h>
+#include <gtk/gtkmenushell.h>
+#include <gtk/gtkspinbutton.h>
+#include <gtk/gtktogglebutton.h>
+#include <gtk/gtkoptionmenu.h>
+#include <gtk/gtklist.h>
+#include <libgnomeui/gnome-color-picker.h>
+
+void
+ephy_pu_set_config_from_editable (GtkWidget *editable, const char *config_name)
+{
+ GConfValue *gcvalue = eel_gconf_get_value (config_name);
+ GConfValueType value_type;
+ char *value;
+ gint ivalue;
+ gfloat fvalue;
+
+ if (gcvalue == NULL) {
+ /* ugly hack around what appears to be a gconf bug
+ * it returns a NULL GConfValue for a valid string pref
+ * which is "" by default */
+ value_type = GCONF_VALUE_STRING;
+ } else {
+ value_type = gcvalue->type;
+ gconf_value_free (gcvalue);
+ }
+
+ /* get all the text into a new string */
+ value = gtk_editable_get_chars (GTK_EDITABLE(editable), 0, -1);
+
+ switch (value_type) {
+ case GCONF_VALUE_STRING:
+ eel_gconf_set_string (config_name,
+ value);
+ break;
+ /* FIXME : handle possible errors in the input for int and float */
+ case GCONF_VALUE_INT:
+ ivalue = atoi (value);
+ eel_gconf_set_integer (config_name, ivalue);
+ break;
+ case GCONF_VALUE_FLOAT:
+ fvalue = strtod (value, (char**)NULL);
+ eel_gconf_set_float (config_name, fvalue);
+ break;
+ default:
+ break;
+ }
+
+ /* free the allocated strings */
+ g_free (value);
+}
+
+void
+ephy_pu_set_config_from_optionmenu (GtkWidget *optionmenu, const char *config_name)
+{
+ int index = ephy_pu_get_int_from_optionmenu (optionmenu);
+
+ eel_gconf_set_integer (config_name, index);
+}
+
+void
+ephy_pu_set_config_from_radiobuttongroup (GtkWidget *radiobutton, const char *config_name)
+{
+ gint index;
+
+ /* get value from radio button group */
+ index = ephy_gui_gtk_radio_button_get (GTK_RADIO_BUTTON (radiobutton));
+
+ eel_gconf_set_integer (config_name, index);
+}
+
+void
+ephy_pu_set_config_from_spin_button (GtkWidget *spinbutton, const char *config_name)
+{
+ gdouble value;
+ gboolean use_int;
+
+ /* read the value as an integer */
+ value = gtk_spin_button_get_value (GTK_SPIN_BUTTON(spinbutton));
+
+ use_int = (gtk_spin_button_get_digits (GTK_SPIN_BUTTON(spinbutton)) == 0);
+
+ if (use_int)
+ {
+ eel_gconf_set_integer (config_name, value);
+ }
+ else
+ {
+ eel_gconf_set_float (config_name, value);
+ }
+}
+
+void
+ephy_pu_set_config_from_togglebutton (GtkWidget *togglebutton, const char *config_name)
+{
+ gboolean value;
+
+ /* read the value */
+ value = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(togglebutton));
+
+ eel_gconf_set_boolean (config_name, value);
+}
+
+void
+ephy_pu_set_config_from_color (GtkWidget *colorpicker, const char *config_name)
+{
+ guint8 r, g, b, a;
+ gchar color_string[9];
+
+ /* get color values from color picker */
+ gnome_color_picker_get_i8 (GNOME_COLOR_PICKER (colorpicker),
+ &r, &g, &b, &a);
+
+ /* write into string (bounded size) */
+ snprintf (color_string, 9, "#%02X%02X%02X", r, g, b);
+
+ /* set the configuration value */
+ eel_gconf_set_string (config_name, color_string);
+}
+
+void
+ephy_pu_set_editable_from_config (GtkWidget *editable, const char *config_name)
+{
+ GConfValue *gcvalue = eel_gconf_get_value (config_name);
+ GConfValueType value_type;
+ gchar *value;
+
+ if (gcvalue == NULL)
+ {
+ /* ugly hack around what appears to be a gconf bug
+ * it returns a NULL GConfValue for a valid string pref
+ * which is "" by default */
+ value_type = GCONF_VALUE_STRING;
+ }
+ else
+ {
+ value_type = gcvalue->type;
+ gconf_value_free (gcvalue);
+ }
+
+ switch (value_type)
+ {
+ case GCONF_VALUE_STRING:
+ value = eel_gconf_get_string (config_name);
+ break;
+ case GCONF_VALUE_INT:
+ value = g_strdup_printf ("%d",eel_gconf_get_integer (config_name));
+ break;
+ case GCONF_VALUE_FLOAT:
+ value = g_strdup_printf ("%.2f",eel_gconf_get_float (config_name));
+ break;
+ default:
+ value = NULL;
+ }
+
+ /* set this string value in the widget */
+ if (value)
+ {
+ gtk_entry_set_text(GTK_ENTRY(editable), value);
+ }
+
+ /* free the allocated string */
+ g_free (value);
+}
+
+void
+ephy_pu_set_optionmenu_from_config (GtkWidget *optionmenu, const char *config_name)
+{
+ gint index;
+
+ /* get the current value from the configuration space */
+ index = eel_gconf_get_integer (config_name);
+
+ /* set this option value in the widget */
+ gtk_option_menu_set_history (GTK_OPTION_MENU (optionmenu), index);
+}
+
+void
+ephy_pu_set_radiobuttongroup_from_config (GtkWidget *radiobutton, const char *config_name)
+{
+ gint index;
+
+ /* get the current value from the configuration space */
+ index = eel_gconf_get_integer (config_name);
+
+ /* set it (finds the group for us) */
+ ephy_gui_gtk_radio_button_set (GTK_RADIO_BUTTON (radiobutton), index);
+}
+
+void
+ephy_pu_set_spin_button_from_config (GtkWidget *spinbutton, const char *config_name)
+{
+ gdouble value;
+ gint use_int;
+
+ use_int = (gtk_spin_button_get_digits (GTK_SPIN_BUTTON(spinbutton)) == 0);
+
+ if (use_int)
+ {
+ /* get the current value from the configuration space */
+ value = eel_gconf_get_integer (config_name);
+ }
+ else
+ {
+ /* get the current value from the configuration space */
+ value = eel_gconf_get_float (config_name);
+ }
+
+ /* set this option value in the widget */
+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinbutton), value);
+}
+
+void
+ephy_pu_set_togglebutton_from_config (GtkWidget *togglebutton, const char *config_name)
+{
+ gboolean value;
+
+ /* get the current value from the configuration space */
+ value = eel_gconf_get_boolean (config_name);
+
+ /* set this option value in the widget */
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (togglebutton), value);
+}
+
+void
+ephy_pu_set_color_from_config (GtkWidget *colorpicker, const char *config_name)
+{
+ gchar *color_string;
+ guint r, g, b;
+
+ /* get the string from config */
+ color_string = eel_gconf_get_string (config_name);
+
+ if (color_string)
+ {
+ /* parse it and setup the color picker */
+ sscanf (color_string, "#%2X%2X%2X", &r, &g, &b);
+ gnome_color_picker_set_i8 (GNOME_COLOR_PICKER (colorpicker),
+ r, g, b, 0);
+ /* free the string */
+ g_free (color_string);
+ }
+}
+
+int
+ephy_pu_get_int_from_optionmenu (GtkWidget *optionmenu)
+{
+ GtkWidget *menu;
+ GList *list;
+ gpointer item;
+ gint index;
+
+ /* extract the selection */
+ menu = GTK_OPTION_MENU(optionmenu)->menu;
+ list = GTK_MENU_SHELL(menu)->children;
+ item = gtk_menu_get_active (GTK_MENU(menu));
+ index = g_list_index (list, item);
+
+ return index;
+}
diff --git a/lib/ephy-prefs-utils.h b/lib/ephy-prefs-utils.h
new file mode 100644
index 000000000..13ac1e4d7
--- /dev/null
+++ b/lib/ephy-prefs-utils.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2000 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <gtk/gtkwidget.h>
+
+G_BEGIN_DECLS
+
+void ephy_pu_set_config_from_editable (GtkWidget *editable,
+ const char *config_name);
+
+void ephy_pu_set_config_from_optionmenu (GtkWidget *optionmenu,
+ const char *config_name);
+
+void ephy_pu_set_config_from_radiobuttongroup (GtkWidget *radiobutton,
+ const char *config_name);
+
+void ephy_pu_set_config_from_spin_button (GtkWidget *spinbutton,
+ const char *config_name);
+
+void ephy_pu_set_config_from_togglebutton (GtkWidget *togglebutton,
+ const char *config_name);
+
+void ephy_pu_set_config_from_color (GtkWidget *colorpicker,
+ const char *config_name);
+
+void ephy_pu_set_editable_from_config (GtkWidget *editable,
+ const char *config_name);
+
+void ephy_pu_set_optionmenu_from_config (GtkWidget *optionmenu,
+ const char *config_name);
+
+void ephy_pu_set_radiobuttongroup_from_config (GtkWidget *radiobutton,
+ const char *config_name);
+
+void ephy_pu_set_togglebutton_from_config (GtkWidget *togglebutton,
+ const char *config_name);
+
+void ephy_pu_set_spin_button_from_config (GtkWidget *spinbutton,
+ const char *config_name);
+
+void ephy_pu_set_color_from_config (GtkWidget *colorpicker,
+ const char *config_name);
+
+int ephy_pu_get_int_from_optionmenu (GtkWidget *optionmenu);
+
+G_END_DECLS
diff --git a/lib/ephy-prefs.h b/lib/ephy-prefs.h
new file mode 100644
index 000000000..3c0562a1f
--- /dev/null
+++ b/lib/ephy-prefs.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2000-2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EPHY_PREFS_H
+#define EPHY_PREFS_H
+
+G_BEGIN_DECLS
+
+/* General */
+#define CONF_GENERAL_HOMEPAGE "/apps/epiphany/general/start_page"
+#define CONF_GENERAL_NEWPAGE_TYPE "/apps/epiphany/general/newpage_type"
+
+/* Interface */
+#define CONF_TABS_TABBED "/apps/epiphany/interface/open_in_tab"
+#define CONF_TABS_TABBED_POPUPS "/apps/epiphany/interface/popups_in_tab"
+#define CONF_TABS_TABBED_AUTOJUMP "/apps/epiphany/interface/jumpto_tab"
+#define CONF_WINDOWS_SIDEBAR_PAGE "/apps/epiphany/interface/sidebar_page"
+#define CONF_WINDOWS_SIDEBAR_SIZE "/apps/epiphany/interface/sidebar_size"
+#define CONF_WINDOWS_FS_SHOW_SIDEBAR "/apps/epiphany/interface/show_sidebar_in_fullscreen"
+#define CONF_WINDOWS_FS_SHOW_TOOLBARS "/apps/epiphany/interface/show_toolbars_in_fullscreen"
+#define CONF_WINDOWS_FS_SHOW_STATUSBAR "/apps/epiphany/interface/show_statusbar_in_fullscreen"
+#define CONF_WINDOWS_SHOW_SIDEBAR "/apps/epiphany/interface/show_sidebar"
+#define CONF_WINDOWS_SHOW_TOOLBARS "/apps/epiphany/interface/show_toolbars"
+#define CONF_WINDOWS_SHOW_STATUSBAR "/apps/epiphany/interface/show_statusbar"
+#define CONF_TOOLBAR_SETUP "/apps/epiphany/interface/toolbar_setup"
+#define CONF_TOOLBAR_SPINNER_THEME "/apps/epiphany/interface/spinner_theme"
+
+/* Downloader */
+#define CONF_DOWNLOADING_SHOW_DETAILS "/apps/epiphany/downloader/show_details"
+
+/* Directories */
+#define CONF_STATE_SAVE_DIR "/apps/epiphany/directories/save"
+#define CONF_STATE_SAVE_IMAGE_DIR "/apps/epiphany/directories/saveimage"
+#define CONF_STATE_OPEN_DIR "/apps/epiphany/directories/open"
+#define CONF_STATE_DOWNLOADING_DIR "/apps/epiphany/directories/downloading"
+
+/* System prefs */
+#define CONF_DESKTOP_FTP_HANDLER "/desktop/gnome/url-handlers/ftp/command"
+#define CONF_DESKTOP_TOOLBAR_STYLE "/desktop/gnome/interface/toolbar_style"
+
+G_END_DECLS
+
+#endif
diff --git a/lib/ephy-state.c b/lib/ephy-state.c
new file mode 100644
index 000000000..245cc38b1
--- /dev/null
+++ b/lib/ephy-state.c
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2001 Matthew Mueller
+ * (C) 2002 Jorn Baayen <jorn@nl.linux.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Id$
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <gtk/gtkpaned.h>
+#include <gtk/gtkwindow.h>
+#include <gtk/gtktreeview.h>
+#include <libgnomeui/gnome-app.h>
+#include <bonobo/bonobo-dock.h>
+#include <bonobo/bonobo-dock-layout.h>
+
+#include "ephy-state.h"
+#include "eel-gconf-extensions.h"
+
+#define CONF_GUL_STATE_PATH "/apps/epiphany/state"
+
+static void
+window_save_size (GtkWidget *window, const gchar *name)
+{
+ int width, height;
+ gchar *buf;
+
+ gtk_window_get_size (GTK_WINDOW(window),
+ &width, &height);
+
+ buf = g_strdup_printf (CONF_GUL_STATE_PATH "/%s/width",name);
+ eel_gconf_set_integer (buf, width);
+ g_free (buf);
+
+ buf = g_strdup_printf (CONF_GUL_STATE_PATH "/%s/height",name);
+ eel_gconf_set_integer (buf, height);
+ g_free (buf);
+}
+
+/**
+ * ephy_state_save_window: save the window dimensions
+ */
+void
+ephy_state_save_window (GtkWidget *window,
+ const gchar *name)
+{
+ GdkWindowState state;
+ gboolean maximized;
+ gchar *buf;
+
+ state = gdk_window_get_state (GTK_WIDGET (window)->window);
+ maximized = state && GDK_WINDOW_STATE_MAXIMIZED;
+
+ buf = g_strdup_printf (CONF_GUL_STATE_PATH "/%s/maximized",name);
+ eel_gconf_set_boolean (buf, maximized);
+ g_free (buf);
+
+ if (!maximized)
+ {
+ window_save_size (window, name);
+ }
+}
+
+/**
+ * ephy_window_load_state: load the window state
+ */
+void
+ephy_state_load_window (GtkWidget *window,
+ const gchar *name,
+ int default_width,
+ int default_height,
+ gboolean position)
+{
+ gchar *buf;
+ gint width, height;
+ gboolean maximized;
+
+ buf = g_strdup_printf (CONF_GUL_STATE_PATH "/%s/maximized",name);
+ maximized = eel_gconf_get_boolean (buf);
+ g_free (buf);
+
+ buf = g_strdup_printf (CONF_GUL_STATE_PATH "/%s/width",name);
+ width = eel_gconf_get_integer (buf);
+ g_free (buf);
+
+ buf = g_strdup_printf (CONF_GUL_STATE_PATH "/%s/height",name);
+ height = eel_gconf_get_integer (buf);
+ g_free (buf);
+
+ /* try default size */
+ if (width == 0 && height == 0 &&
+ default_width != -1 && default_height != -1)
+ {
+ width = default_width;
+ height = default_height;
+ }
+
+ if (width != 0 && height != 0)
+ {
+ gtk_window_set_default_size
+ (GTK_WINDOW (window), width, height);
+ }
+
+ if (maximized)
+ {
+ gtk_window_maximize (GTK_WINDOW(window));
+ }
+}
+
+/**
+ * ephy_state_load_pane_pos: load the paned position
+ */
+void
+ephy_state_load_pane_pos (GtkWidget *pane,
+ const gchar *name)
+{
+ if (pane != NULL)
+ {
+ gint pane_pos;
+ gchar *buf = g_strdup_printf (CONF_GUL_STATE_PATH "/%s", name);
+ pane_pos = eel_gconf_get_integer (buf);
+ g_free (buf);
+
+ if (pane_pos != -1)
+ gtk_paned_set_position (GTK_PANED (pane), pane_pos);
+ }
+}
+
+/**
+ * gul_state_save_pane_pos: save the paned position
+ */
+void
+ephy_state_save_pane_pos (GtkWidget *pane,
+ const gchar *name)
+{
+ if (pane != NULL)
+ {
+ gchar *buf = g_strdup_printf (CONF_GUL_STATE_PATH "/%s", name);
+ eel_gconf_set_integer (buf, GTK_PANED (pane)->child1_size);
+ g_free (buf);
+ }
+}
diff --git a/lib/ephy-state.h b/lib/ephy-state.h
new file mode 100644
index 000000000..508e986be
--- /dev/null
+++ b/lib/ephy-state.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2001 Matthew Mueller
+ * (C) 2002 Jorn Baayen <jorn@nl.linux.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Id$
+ */
+
+#ifndef EPHY_STATE_H
+#define EPHY_STATE_H
+
+G_BEGIN_DECLS
+
+void ephy_state_save_window (GtkWidget *window,
+ const gchar *name);
+
+void ephy_state_load_window (GtkWidget *window,
+ const gchar *name,
+ int default_width,
+ int default_heigth,
+ gboolean position);
+
+void ephy_state_save_pane_pos (GtkWidget *pane,
+ const gchar *name);
+
+void ephy_state_load_pane_pos (GtkWidget *pane,
+ const gchar *name);
+
+G_END_DECLS
+
+#endif /* EPHY_STATE_H */
diff --git a/lib/ephy-stock-icons.c b/lib/ephy-stock-icons.c
new file mode 100644
index 000000000..0d9ff902c
--- /dev/null
+++ b/lib/ephy-stock-icons.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Id$
+ */
+
+#include <gtk/gtk.h>
+#include <glib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "ephy-file-helpers.h"
+#include "ephy-stock-icons.h"
+
+void
+ephy_stock_icons_init (void)
+{
+ GtkIconFactory *factory;
+ int i;
+
+ static const char *items[] =
+ {
+ EPHY_STOCK_SECURE,
+ EPHY_STOCK_UNSECURE
+ };
+
+ factory = gtk_icon_factory_new ();
+ gtk_icon_factory_add_default (factory);
+
+ for (i = 0; i < (int) G_N_ELEMENTS (items); i++)
+ {
+ GtkIconSet *icon_set;
+ GdkPixbuf *pixbuf;
+ char *fn;
+
+ fn = g_strconcat (items[i], ".png", NULL);
+ pixbuf = gdk_pixbuf_new_from_file (ephy_file (fn), NULL);
+ g_free (fn);
+
+ icon_set = gtk_icon_set_new_from_pixbuf (pixbuf);
+ gtk_icon_factory_add (factory, items[i], icon_set);
+ gtk_icon_set_unref (icon_set);
+
+ g_object_unref (G_OBJECT (pixbuf));
+ }
+
+ g_object_unref (G_OBJECT (factory));
+}
diff --git a/lib/ephy-stock-icons.h b/lib/ephy-stock-icons.h
new file mode 100644
index 000000000..c68be46c9
--- /dev/null
+++ b/lib/ephy-stock-icons.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Id$
+ */
+
+#ifndef EPHY_STOCK_ICONS_H
+#define EPHY_STOCK_ICONS_H
+
+G_BEGIN_DECLS
+
+#define EPHY_STOCK_SECURE "epiphany-secure"
+#define EPHY_STOCK_UNSECURE "epiphany-unsecure"
+
+void ephy_stock_icons_init (void);
+
+G_END_DECLS
+
+#endif /* __RB_STOCK_ICONS_H */
diff --git a/lib/ephy-string.c b/lib/ephy-string.c
new file mode 100644
index 000000000..7ca28cf1f
--- /dev/null
+++ b/lib/ephy-string.c
@@ -0,0 +1,446 @@
+/*
+ * Copyright (C) 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "ephy-string.h"
+
+#include <string.h>
+#include <glib.h>
+#include <libgnome/libgnome.h>
+#include <libgnome/gnome-i18n.h>
+#include <libgnomevfs/gnome-vfs-mime.h>
+#include <libxml/parser.h>
+
+/**
+ * ephy_string_shorten: returns a newly allocated shortened version of str.
+ * the new string will be no longer than target_length characters, and will
+ * be of the form "http://blahblah...blahblah.html".
+ */
+gchar *
+ephy_string_shorten (const gchar *str, gint target_length)
+{
+ gchar *new_str;
+ gint actual_length, first_length, second_length;
+
+ if (!str) return NULL;
+
+ actual_length = strlen (str);
+
+ /* if the string is already short enough, or if it's too short for
+ * us to shorten it, return a new copy */
+ if (actual_length <= target_length ||
+ actual_length <= 3)
+ return g_strdup (str);
+
+ /* allocate new string */
+ new_str = g_new (gchar, target_length + 1);
+
+ /* calc lengths to take from beginning and ending of str */
+ second_length = (target_length - 3) / 2;
+ first_length = target_length - 3 - second_length;
+
+ /* create string */
+ strncpy (new_str, str, first_length);
+ strncpy (new_str + first_length, "...", 3);
+ strncpy (new_str + first_length + 3,
+ str + actual_length - second_length, second_length);
+ new_str[target_length] = '\0';
+
+ return new_str;
+}
+
+char *
+ephy_string_double_underscores (const char *string)
+{
+ int underscores;
+ const char *p;
+ char *q;
+ char *escaped;
+
+ if (string == NULL) {
+ return NULL;
+ }
+
+ underscores = 0;
+ for (p = string; *p != '\0'; p++) {
+ underscores += (*p == '_');
+ }
+
+ if (underscores == 0) {
+ return g_strdup (string);
+ }
+
+ escaped = g_new (char, strlen (string) + underscores + 1);
+ for (p = string, q = escaped; *p != '\0'; p++, q++) {
+ /* Add an extra underscore. */
+ if (*p == '_') {
+ *q++ = '_';
+ }
+ *q = *p;
+ }
+ *q = '\0';
+
+ return escaped;
+}
+
+/**
+ * ephy_string_store_time_in_string:
+ * NOTE: str must be at least 256 chars long
+ */
+void
+ephy_string_store_time_in_string (GDate *t, gchar *str, const char *format)
+{
+ int length;
+
+ if (t > 0)
+ {
+ /* format into string */
+ /* this is used whenever a brief date is needed, like
+ * in the history (for last visited, first time visited) */
+ length = g_date_strftime (str, 255,
+ format ? format : _("%Y-%m-%d"), t);
+ str[length] = '\0';
+ }
+ else
+ {
+ str[0] = '\0';
+ }
+}
+
+/**
+ * ephy_string_time_to_string:
+ */
+gchar *
+ephy_string_time_to_string (GDate *t,
+ const char *format)
+{
+ gchar str[256];
+
+ /* write into stack string */
+ ephy_string_store_time_in_string (t, str, format);
+
+ /* copy in heap and return */
+ return g_strdup (str);
+}
+
+gboolean
+ephy_str_to_int (const char *string, int *integer)
+{
+ long result;
+ char *parse_end;
+
+ /* Check for the case of an empty string. */
+ if (string == NULL || *string == '\0') {
+ return FALSE;
+ }
+
+ /* Call the standard library routine to do the conversion. */
+ errno = 0;
+ result = strtol (string, &parse_end, 0);
+
+ /* Check that the result is in range. */
+ if ((result == G_MINLONG || result == G_MAXLONG) && errno == ERANGE) {
+ return FALSE;
+ }
+ if (result < G_MININT || result > G_MAXINT) {
+ return FALSE;
+ }
+
+ /* Check that all the trailing characters are spaces. */
+ while (*parse_end != '\0') {
+ if (!g_ascii_isspace (*parse_end++)) {
+ return FALSE;
+ }
+ }
+
+ /* Return the result. */
+ *integer = result;
+ return TRUE;
+}
+
+/**
+ * ephy_str_strip_chr:
+ * Remove all occurrences of a character from a string.
+ *
+ * @source: The string to be stripped.
+ * @remove_this: The char to remove from @source
+ *
+ * Return value: A copy of @source, after removing all occurrences
+ * of @remove_this.
+ */
+char *
+ephy_str_strip_chr (const char *source, char remove_this)
+{
+ char *result, *out;
+ const char *in;
+
+ if (source == NULL) {
+ return NULL;
+ }
+
+ result = g_new (char, strlen (source) + 1);
+ in = source;
+ out = result;
+ do {
+ if (*in != remove_this) {
+ *out++ = *in;
+ }
+ } while (*in++ != '\0');
+
+ return result;
+}
+
+int
+ephy_strcasecmp (const char *string_a, const char *string_b)
+{
+ return g_ascii_strcasecmp (string_a == NULL ? "" : string_a,
+ string_b == NULL ? "" : string_b);
+}
+
+int
+ephy_strcasecmp_compare_func (gconstpointer string_a, gconstpointer string_b)
+{
+ return ephy_strcasecmp ((const char *) string_a,
+ (const char *) string_b);
+}
+
+/**
+ * like strpbrk but ignores chars preceded by slashes, unless the
+ * slash is also preceded by a slash unless that later slash is
+ * preceded by another slash... ;-)
+ */
+static char *
+ephy_strpbrk_unescaped (const char *s, const char *accept)
+{
+ gchar *ret = strpbrk (s, accept);
+
+ if (!ret || ret == s || *(ret - 1) != '\\')
+ {
+ return ret;
+ }
+ else
+ {
+ gchar *c = ret - 1;
+ g_assert (*c == '\\');
+
+ while (c >= s && *c == '\\') c--;
+
+ if ((ret - c) % 2 == 0)
+ {
+ return ephy_strpbrk_unescaped (ret + 1, accept);
+ }
+ else
+ {
+ return ret;
+ }
+ }
+}
+
+/**
+ * like strstr but supports quoting, ignoring matches inside quoted text
+ */
+static char *
+ephy_strstr_with_quotes (const char *haystack, const char *needle,
+ const char *quotes)
+{
+ gchar *quot = ephy_strpbrk_unescaped (haystack, quotes);
+ gchar *ret = strstr (haystack, needle);
+
+ if (!quot || !ret || ret < quot)
+ {
+ return ret;
+ }
+
+ quot = ephy_strpbrk_unescaped (quot + 1, quotes);
+
+ if (quot)
+ {
+ return ephy_strstr_with_quotes (quot + 1, needle, quotes);
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+/**
+ * like strpbrk but supports quoting, ignoring matches inside quoted text
+ */
+static char *
+ephy_strpbrk_with_quotes (const char *haystack, const char *needles,
+ const char *quotes)
+{
+ gchar *quot = ephy_strpbrk_unescaped (haystack, quotes);
+ gchar *ret = strpbrk (haystack, needles);
+
+ if (!quot || !ret || ret < quot)
+ {
+ return ret;
+ }
+
+ quot = ephy_strpbrk_unescaped (quot + 1, quotes);
+
+ if (quot)
+ {
+ return ephy_strpbrk_with_quotes (quot + 1, needles, quotes);
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+/**
+ * Like g_strsplit, but does not split tokens betwen quotes. Ignores
+ * quotes preceded by '\'.
+ */
+gchar **
+ephy_strsplit_with_quotes (const gchar *string,
+ const gchar *delimiter,
+ gint max_tokens,
+ const gchar *quotes)
+{
+ GSList *string_list = NULL, *slist;
+ gchar **str_array, *s;
+ guint n = 0;
+ const gchar *remainder;
+
+ g_return_val_if_fail (string != NULL, NULL);
+ g_return_val_if_fail (delimiter != NULL, NULL);
+ g_return_val_if_fail (delimiter[0] != '\0', NULL);
+
+ if (quotes == NULL)
+ {
+ return g_strsplit (string, delimiter, max_tokens);
+ }
+
+ if (max_tokens < 1)
+ {
+ max_tokens = G_MAXINT;
+ }
+
+ remainder = string;
+ s = ephy_strstr_with_quotes (remainder, delimiter, quotes);
+ if (s)
+ {
+ gsize delimiter_len = strlen (delimiter);
+
+ while (--max_tokens && s)
+ {
+ gsize len;
+ gchar *new_string;
+
+ len = s - remainder;
+ new_string = g_new (gchar, len + 1);
+ strncpy (new_string, remainder, len);
+ new_string[len] = 0;
+ string_list = g_slist_prepend (string_list, new_string);
+ n++;
+ remainder = s + delimiter_len;
+ s = ephy_strstr_with_quotes (remainder, delimiter, quotes);
+ }
+ }
+ if (*string)
+ {
+ n++;
+ string_list = g_slist_prepend (string_list, g_strdup (remainder));
+ }
+
+ str_array = g_new (gchar*, n + 1);
+
+ str_array[n--] = NULL;
+ for (slist = string_list; slist; slist = slist->next)
+ {
+ str_array[n--] = slist->data;
+ }
+
+ g_slist_free (string_list);
+
+ return str_array;
+}
+
+/**
+ * like ephy_strsplit_with_quotes, but matches any char in 'delimiters' as delimiter
+ * and does not return empty tokens
+ */
+gchar **
+ephy_strsplit_multiple_delimiters_with_quotes (const gchar *string,
+ const gchar *delimiters,
+ gint max_tokens,
+ const gchar *quotes)
+{
+ GSList *string_list = NULL, *slist;
+ gchar **str_array, *s;
+ guint n = 0;
+ const gchar *remainder;
+
+ g_return_val_if_fail (string != NULL, NULL);
+ g_return_val_if_fail (delimiters != NULL, NULL);
+ g_return_val_if_fail (delimiters[0] != '\0', NULL);
+
+ if (quotes == NULL)
+ {
+ quotes = "";
+ }
+
+ if (max_tokens < 1)
+ {
+ max_tokens = G_MAXINT;
+ }
+
+ remainder = string;
+ s = ephy_strpbrk_with_quotes (remainder, delimiters, quotes);
+ if (s)
+ {
+ const gsize delimiter_len = 1; /* only chars */
+
+ while (--max_tokens && s)
+ {
+ gsize len;
+ gchar *new_string;
+
+ len = s - remainder;
+ if (len > 0) /* ignore empty strings */
+ {
+ new_string = g_new (gchar, len + 1);
+ strncpy (new_string, remainder, len);
+ new_string[len] = 0;
+ string_list = g_slist_prepend (string_list, new_string);
+ n++;
+ }
+ remainder = s + delimiter_len;
+ s = ephy_strpbrk_with_quotes (remainder, delimiters, quotes);
+ }
+ }
+ if (*string)
+ {
+ n++;
+ string_list = g_slist_prepend (string_list, g_strdup (remainder));
+ }
+
+ str_array = g_new (gchar*, n + 1);
+
+ str_array[n--] = NULL;
+ for (slist = string_list; slist; slist = slist->next)
+ {
+ str_array[n--] = slist->data;
+ }
+
+ g_slist_free (string_list);
+
+ return str_array;
+}
diff --git a/lib/ephy-string.h b/lib/ephy-string.h
new file mode 100644
index 000000000..cc60bd638
--- /dev/null
+++ b/lib/ephy-string.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EPHY_STRING_H
+#define EPHY_STRING_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+char * ephy_string_double_underscores (const char *string);
+
+void ephy_string_store_time_in_string (GDate *t,
+ gchar *str,
+ const char *format);
+
+gchar *ephy_string_time_to_string (GDate *t,
+ const char *format);
+
+gboolean ephy_str_to_int (const char *string,
+ int *integer);
+
+char *ephy_str_strip_chr (const char *source,
+ char remove_this);
+
+int ephy_strcasecmp (const char *string_a,
+ const char *string_b);
+
+int ephy_strcasecmp_compare_func (gconstpointer string_a,
+ gconstpointer string_b);
+
+char **ephy_strsplit_with_quotes (const gchar *string,
+ const gchar *delimiter,
+ gint max_tokens,
+ const gchar *quotes);
+
+gchar *ephy_string_shorten (const gchar *str,
+ gint target_length);
+
+char **ephy_strsplit_multiple_delimiters_with_quotes (const gchar *string,
+ const gchar *delimiters,
+ gint max_tokens,
+ const gchar *quotes);
+
+
+G_END_DECLS
+
+#endif
diff --git a/lib/ephy-thread-helpers.c b/lib/ephy-thread-helpers.c
new file mode 100644
index 000000000..720358968
--- /dev/null
+++ b/lib/ephy-thread-helpers.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Id$
+ */
+
+#include "ephy-thread-helpers.h"
+
+static GThread *main_thread = NULL;
+
+void
+ephy_thread_helpers_init (void)
+{
+ main_thread = g_thread_self ();
+}
+
+gboolean
+ephy_thread_helpers_in_main_thread (void)
+{
+ return (main_thread == g_thread_self ());
+}
diff --git a/lib/ephy-thread-helpers.h b/lib/ephy-thread-helpers.h
new file mode 100644
index 000000000..2b23156a3
--- /dev/null
+++ b/lib/ephy-thread-helpers.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Id$
+ */
+
+#include <glib/gthread.h>
+
+#ifndef EPHY_THREAD_HELPERS_H
+#define EPHY_THREAD_HELPERS_H
+
+G_BEGIN_DECLS
+
+void ephy_thread_helpers_init (void);
+
+gboolean ephy_thread_helpers_in_main_thread (void);
+
+G_END_DECLS
+
+#endif /* EPHY_THREAD_HELPERS_H */
diff --git a/lib/ephy-types.h b/lib/ephy-types.h
new file mode 100644
index 000000000..70ce681e0
--- /dev/null
+++ b/lib/ephy-types.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EPHY_TYPES_H
+#define EPHY_TYPES_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef enum
+{
+ G_OK,
+ G_FAILED,
+ G_NOT_IMPLEMENTED
+} gresult;
+
+G_END_DECLS
+
+#endif
diff --git a/lib/toolbar/.cvsignore b/lib/toolbar/.cvsignore
new file mode 100644
index 000000000..20e4cb0c8
--- /dev/null
+++ b/lib/toolbar/.cvsignore
@@ -0,0 +1,6 @@
+Makefile
+Makefile.in
+*.lo
+.deps
+.libs
+*.la
diff --git a/lib/toolbar/Makefile.am b/lib/toolbar/Makefile.am
new file mode 100644
index 000000000..a6affaa04
--- /dev/null
+++ b/lib/toolbar/Makefile.am
@@ -0,0 +1,41 @@
+INCLUDES = \
+ -I$(top_srcdir)/lib \
+ -I$(top_srcdir)/lib/widgets \
+ $(WARN_CFLAGS) \
+ $(EPIPHANY_DEPENDENCY_CFLAGS) \
+ -DSHARE_DIR=\"$(pkgdatadir)\" \
+ -DG_DISABLE_DEPRECATED \
+ -DGDK_DISABLE_DEPRECATED \
+ -DGTK_DISABLE_DEPRECATED \
+ -DGDK_PIXBUF_DISABLE_DEPRECATED \
+ -DGNOME_DISABLE_DEPRECATED
+
+noinst_LTLIBRARIES = libephytoolbar.la
+
+libephytoolbar_la_SOURCES = \
+ ephy-toolbar.h \
+ ephy-toolbar.c \
+ ephy-toolbar-item.h \
+ ephy-toolbar-item.c \
+ ephy-toolbar-item-factory.h \
+ ephy-toolbar-item-factory.c \
+ ephy-tbi-zoom.h \
+ ephy-tbi-zoom.c \
+ ephy-tbi-separator.h \
+ ephy-tbi-separator.c \
+ ephy-tbi-favicon.h \
+ ephy-tbi-favicon.c \
+ ephy-tbi-spinner.h \
+ ephy-tbi-spinner.c \
+ ephy-tbi-location.h \
+ ephy-tbi-location.c \
+ ephy-tbi-navigation-history.h \
+ ephy-tbi-navigation-history.c \
+ ephy-tbi-std-toolitem.h \
+ ephy-tbi-std-toolitem.c \
+ ephy-toolbar-bonobo-view.c \
+ ephy-toolbar-bonobo-view.h \
+ ephy-toolbar-tree-model.h \
+ ephy-toolbar-tree-model.c \
+ ephy-toolbar-editor.h \
+ ephy-toolbar-editor.c
diff --git a/lib/toolbar/ephy-tbi-favicon.c b/lib/toolbar/ephy-tbi-favicon.c
new file mode 100644
index 000000000..d072e3ec6
--- /dev/null
+++ b/lib/toolbar/ephy-tbi-favicon.c
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2002 Ricardo Fernández Pascual
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <libgnome/gnome-i18n.h>
+#include <gtk/gtkeventbox.h>
+
+#include "ephy-gobject-misc.h"
+#include "ephy-marshal.h"
+#include "ephy-bonobo-extensions.h"
+#include "ephy-tbi-favicon.h"
+
+#define NOT_IMPLEMENTED g_warning ("not implemented: " G_STRLOC);
+//#define DEBUG_MSG(x) g_print x
+#define DEBUG_MSG(x)
+
+/**
+ * Private data
+ */
+struct _EphyTbiFaviconPrivate
+{
+ GtkWidget *widget;
+};
+
+/**
+ * Private functions, only availble from this file
+ */
+static void ephy_tbi_favicon_class_init (EphyTbiFaviconClass *klass);
+static void ephy_tbi_favicon_init (EphyTbiFavicon *tb);
+static void ephy_tbi_favicon_finalize_impl (GObject *o);
+static GtkWidget * ephy_tbi_favicon_get_widget_impl (EphyTbItem *i);
+static GdkPixbuf * ephy_tbi_favicon_get_icon_impl (EphyTbItem *i);
+static gchar * ephy_tbi_favicon_get_name_human_impl (EphyTbItem *i);
+static gchar * ephy_tbi_favicon_to_string_impl (EphyTbItem *i);
+static gboolean ephy_tbi_favicon_is_unique_impl (EphyTbItem *i);
+static EphyTbItem * ephy_tbi_favicon_clone_impl (EphyTbItem *i);
+static void ephy_tbi_favicon_parse_properties_impl (EphyTbItem *i, const gchar *props);
+static void ephy_tbi_favicon_add_to_bonobo_tb_impl (EphyTbItem *i,
+ BonoboUIComponent *ui,
+ const char *container_path,
+ guint index);
+
+static gpointer ephy_tb_item_class;
+
+/**
+ * TbiFavicon object
+ */
+
+MAKE_GET_TYPE (ephy_tbi_favicon, "EphyTbiFavicon", EphyTbiFavicon, ephy_tbi_favicon_class_init,
+ ephy_tbi_favicon_init, EPHY_TYPE_TB_ITEM);
+
+static void
+ephy_tbi_favicon_class_init (EphyTbiFaviconClass *klass)
+{
+ G_OBJECT_CLASS (klass)->finalize = ephy_tbi_favicon_finalize_impl;
+
+ EPHY_TB_ITEM_CLASS (klass)->get_widget = ephy_tbi_favicon_get_widget_impl;
+ EPHY_TB_ITEM_CLASS (klass)->get_icon = ephy_tbi_favicon_get_icon_impl;
+ EPHY_TB_ITEM_CLASS (klass)->get_name_human = ephy_tbi_favicon_get_name_human_impl;
+ EPHY_TB_ITEM_CLASS (klass)->to_string = ephy_tbi_favicon_to_string_impl;
+ EPHY_TB_ITEM_CLASS (klass)->is_unique = ephy_tbi_favicon_is_unique_impl;
+ EPHY_TB_ITEM_CLASS (klass)->clone = ephy_tbi_favicon_clone_impl;
+ EPHY_TB_ITEM_CLASS (klass)->parse_properties = ephy_tbi_favicon_parse_properties_impl;
+ EPHY_TB_ITEM_CLASS (klass)->add_to_bonobo_tb = ephy_tbi_favicon_add_to_bonobo_tb_impl;
+
+ ephy_tb_item_class = g_type_class_peek_parent (klass);
+}
+
+static void
+ephy_tbi_favicon_init (EphyTbiFavicon *tb)
+{
+ EphyTbiFaviconPrivate *p = g_new0 (EphyTbiFaviconPrivate, 1);
+ tb->priv = p;
+}
+
+EphyTbiFavicon *
+ephy_tbi_favicon_new (void)
+{
+ EphyTbiFavicon *ret = g_object_new (EPHY_TYPE_TBI_FAVICON, NULL);
+ return ret;
+}
+
+static void
+ephy_tbi_favicon_finalize_impl (GObject *o)
+{
+ EphyTbiFavicon *it = EPHY_TBI_FAVICON (o);
+ EphyTbiFaviconPrivate *p = it->priv;
+
+ if (p->widget)
+ {
+ g_object_unref (p->widget);
+ }
+
+ g_free (p);
+
+ DEBUG_MSG (("EphyTbiFavicon finalized\n"));
+
+ G_OBJECT_CLASS (ephy_tb_item_class)->finalize (o);
+}
+
+static GtkWidget *
+ephy_tbi_favicon_get_widget_impl (EphyTbItem *i)
+{
+ EphyTbiFavicon *iz = EPHY_TBI_FAVICON (i);
+ EphyTbiFaviconPrivate *p = iz->priv;
+
+ if (!p->widget)
+ {
+ /* here, we create only the event_box. */
+ p->widget = gtk_event_box_new ();
+ g_object_ref (p->widget);
+ gtk_object_sink (GTK_OBJECT (p->widget));
+ }
+
+ return p->widget;
+}
+
+static GdkPixbuf *
+ephy_tbi_favicon_get_icon_impl (EphyTbItem *i)
+{
+ /* need an icon for this */
+ return NULL;
+}
+
+static gchar *
+ephy_tbi_favicon_get_name_human_impl (EphyTbItem *i)
+{
+ return g_strdup (_("Drag Handle"));
+}
+
+static gchar *
+ephy_tbi_favicon_to_string_impl (EphyTbItem *i)
+{
+ /* if it had any properties, the string should include them */
+ return g_strdup_printf ("%s=favicon", i->id);
+}
+
+static gboolean
+ephy_tbi_favicon_is_unique_impl (EphyTbItem *i)
+{
+ return TRUE;
+}
+
+static EphyTbItem *
+ephy_tbi_favicon_clone_impl (EphyTbItem *i)
+{
+ EphyTbItem *ret = EPHY_TB_ITEM (ephy_tbi_favicon_new ());
+
+ ephy_tb_item_set_id (ret, i->id);
+
+ /* should copy properties too, if any */
+
+ return ret;
+}
+
+static void
+ephy_tbi_favicon_add_to_bonobo_tb_impl (EphyTbItem *i, BonoboUIComponent *ui,
+ const char *container_path, guint index)
+{
+ GtkWidget *w = ephy_tb_item_get_widget (i);
+ gtk_widget_show (w);
+ ephy_bonobo_add_numbered_control (ui, w, index, container_path);
+}
+
+static void
+ephy_tbi_favicon_parse_properties_impl (EphyTbItem *it, const gchar *props)
+{
+ /* we have no properties */
+}
+
diff --git a/lib/toolbar/ephy-tbi-favicon.h b/lib/toolbar/ephy-tbi-favicon.h
new file mode 100644
index 000000000..7cea6f634
--- /dev/null
+++ b/lib/toolbar/ephy-tbi-favicon.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2002 Ricardo Fernández Pascual
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EPHY_TBI_FAVICON_H
+#define EPHY_TBI_FAVICON_H
+
+#include "ephy-toolbar-item.h"
+
+G_BEGIN_DECLS
+
+/* object forward declarations */
+
+typedef struct _EphyTbiFavicon EphyTbiFavicon;
+typedef struct _EphyTbiFaviconClass EphyTbiFaviconClass;
+typedef struct _EphyTbiFaviconPrivate EphyTbiFaviconPrivate;
+
+/**
+ * TbiFavicon object
+ */
+
+#define EPHY_TYPE_TBI_FAVICON (ephy_tbi_favicon_get_type())
+#define EPHY_TBI_FAVICON(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EPHY_TYPE_TBI_FAVICON,\
+ EphyTbiFavicon))
+#define EPHY_TBI_FAVICON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EPHY_TYPE_TBI_FAVICON,\
+ EphyTbiFaviconClass))
+#define EPHY_IS_TBI_FAVICON(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EPHY_TYPE_TBI_FAVICON))
+#define EPHY_IS_TBI_FAVICON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), EPHY_TYPE_TBI_FAVICON))
+#define EPHY_TBI_FAVICON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EPHY_TYPE_TBI_FAVICON,\
+ EphyTbiFaviconClass))
+
+struct _EphyTbiFaviconClass
+{
+ EphyTbItemClass parent_class;
+};
+
+/* Remember: fields are public read-only */
+struct _EphyTbiFavicon
+{
+ EphyTbItem parent_object;
+
+ EphyTbiFaviconPrivate *priv;
+};
+
+/* this class is abstract */
+
+GType ephy_tbi_favicon_get_type (void);
+EphyTbiFavicon * ephy_tbi_favicon_new (void);
+
+G_END_DECLS
+
+#endif
diff --git a/lib/toolbar/ephy-tbi-location.c b/lib/toolbar/ephy-tbi-location.c
new file mode 100644
index 000000000..0ccbaf83a
--- /dev/null
+++ b/lib/toolbar/ephy-tbi-location.c
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2002 Ricardo Fernández Pascual
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <libgnome/gnome-i18n.h>
+#include "ephy-gobject-misc.h"
+#include "ephy-marshal.h"
+#include "ephy-bonobo-extensions.h"
+#include "ephy-tbi-location.h"
+#include "ephy-location-entry.h"
+
+#define NOT_IMPLEMENTED g_warning ("not implemented: " G_STRLOC);
+//#define DEBUG_MSG(x) g_print x
+#define DEBUG_MSG(x)
+
+/**
+ * Private data
+ */
+struct _EphyTbiLocationPrivate
+{
+ GtkWidget *widget;
+};
+
+/**
+ * Private functions, only availble from this file
+ */
+static void ephy_tbi_location_class_init (EphyTbiLocationClass *klass);
+static void ephy_tbi_location_init (EphyTbiLocation *tb);
+static void ephy_tbi_location_finalize_impl (GObject *o);
+static GtkWidget * ephy_tbi_location_get_widget_impl (EphyTbItem *i);
+static GdkPixbuf * ephy_tbi_location_get_icon_impl (EphyTbItem *i);
+static gchar * ephy_tbi_location_get_name_human_impl (EphyTbItem *i);
+static gchar * ephy_tbi_location_to_string_impl (EphyTbItem *i);
+static gboolean ephy_tbi_location_is_unique_impl (EphyTbItem *i);
+static EphyTbItem * ephy_tbi_location_clone_impl (EphyTbItem *i);
+static void ephy_tbi_location_parse_properties_impl (EphyTbItem *i, const gchar *props);
+static void ephy_tbi_location_add_to_bonobo_tb_impl (EphyTbItem *i,
+ BonoboUIComponent *ui,
+ const char *container_path,
+ guint index);
+
+static gpointer ephy_tb_item_class;
+
+/**
+ * TbiLocation object
+ */
+
+MAKE_GET_TYPE (ephy_tbi_location, "EphyTbiLocation", EphyTbiLocation, ephy_tbi_location_class_init,
+ ephy_tbi_location_init, EPHY_TYPE_TB_ITEM);
+
+static void
+ephy_tbi_location_class_init (EphyTbiLocationClass *klass)
+{
+ G_OBJECT_CLASS (klass)->finalize = ephy_tbi_location_finalize_impl;
+
+ EPHY_TB_ITEM_CLASS (klass)->get_widget = ephy_tbi_location_get_widget_impl;
+ EPHY_TB_ITEM_CLASS (klass)->get_icon = ephy_tbi_location_get_icon_impl;
+ EPHY_TB_ITEM_CLASS (klass)->get_name_human = ephy_tbi_location_get_name_human_impl;
+ EPHY_TB_ITEM_CLASS (klass)->to_string = ephy_tbi_location_to_string_impl;
+ EPHY_TB_ITEM_CLASS (klass)->is_unique = ephy_tbi_location_is_unique_impl;
+ EPHY_TB_ITEM_CLASS (klass)->clone = ephy_tbi_location_clone_impl;
+ EPHY_TB_ITEM_CLASS (klass)->parse_properties = ephy_tbi_location_parse_properties_impl;
+ EPHY_TB_ITEM_CLASS (klass)->add_to_bonobo_tb = ephy_tbi_location_add_to_bonobo_tb_impl;
+
+ ephy_tb_item_class = g_type_class_peek_parent (klass);
+}
+
+static void
+ephy_tbi_location_init (EphyTbiLocation *tb)
+{
+ EphyTbiLocationPrivate *p = g_new0 (EphyTbiLocationPrivate, 1);
+ tb->priv = p;
+}
+
+EphyTbiLocation *
+ephy_tbi_location_new (void)
+{
+ EphyTbiLocation *ret = g_object_new (EPHY_TYPE_TBI_LOCATION, NULL);
+ return ret;
+}
+
+static void
+ephy_tbi_location_finalize_impl (GObject *o)
+{
+ EphyTbiLocation *it = EPHY_TBI_LOCATION (o);
+ EphyTbiLocationPrivate *p = it->priv;
+
+ if (p->widget)
+ {
+ g_object_unref (p->widget);
+ }
+
+ g_free (p);
+
+ DEBUG_MSG (("EphyTbiLocation finalized\n"));
+
+ G_OBJECT_CLASS (ephy_tb_item_class)->finalize (o);
+}
+
+static GtkWidget *
+ephy_tbi_location_get_widget_impl (EphyTbItem *i)
+{
+ EphyTbiLocation *iz = EPHY_TBI_LOCATION (i);
+ EphyTbiLocationPrivate *p = iz->priv;
+
+ if (!p->widget)
+ {
+ p->widget = GTK_WIDGET (ephy_location_entry_new ());
+ g_object_ref (p->widget);
+ gtk_object_sink (GTK_OBJECT (p->widget));
+ }
+
+ return p->widget;
+}
+
+static GdkPixbuf *
+ephy_tbi_location_get_icon_impl (EphyTbItem *i)
+{
+ return NULL;
+}
+
+static gchar *
+ephy_tbi_location_get_name_human_impl (EphyTbItem *i)
+{
+ return g_strdup (_("Location entry"));
+}
+
+static gchar *
+ephy_tbi_location_to_string_impl (EphyTbItem *i)
+{
+ /* if it had any properties, the string should include them */
+ return g_strdup_printf ("%s=location", i->id);
+}
+
+static gboolean
+ephy_tbi_location_is_unique_impl (EphyTbItem *i)
+{
+ return TRUE;
+}
+
+static EphyTbItem *
+ephy_tbi_location_clone_impl (EphyTbItem *i)
+{
+ EphyTbItem *ret = EPHY_TB_ITEM (ephy_tbi_location_new ());
+
+ ephy_tb_item_set_id (ret, i->id);
+
+ /* should copy properties too, if any */
+ /* the location value is not copied, not sure if it should... */
+
+ return ret;
+}
+
+static void
+ephy_tbi_location_add_to_bonobo_tb_impl (EphyTbItem *i, BonoboUIComponent *uic,
+ const char *container_path, guint index)
+{
+ GtkWidget *w = ephy_tb_item_get_widget (i);
+ BonoboControl *control;
+ char *xml_string, *control_path;
+
+ gtk_widget_show (w);
+
+ g_return_if_fail (BONOBO_IS_UI_COMPONENT (uic));
+ g_return_if_fail (container_path != NULL);
+
+ xml_string = g_strdup_printf ("<control name=\"location\" behavior=\"expandable\"/>");
+
+ bonobo_ui_component_set (uic, container_path, xml_string, NULL);
+
+ g_free (xml_string);
+
+ control_path = g_strconcat (container_path, "/location", NULL);
+
+ control = bonobo_control_new (w);
+ bonobo_ui_component_object_set (uic, control_path, BONOBO_OBJREF (control), NULL);
+ bonobo_object_unref (control);
+
+ g_free (control_path);
+}
+
+static void
+ephy_tbi_location_parse_properties_impl (EphyTbItem *it, const gchar *props)
+{
+ /* we have no properties */
+}
+
diff --git a/lib/toolbar/ephy-tbi-location.h b/lib/toolbar/ephy-tbi-location.h
new file mode 100644
index 000000000..9188463f6
--- /dev/null
+++ b/lib/toolbar/ephy-tbi-location.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2002 Ricardo Fernández Pascual
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EPHY_TBI_LOCATION_H
+#define EPHY_TBI_LOCATION_H
+
+#include "ephy-toolbar-item.h"
+
+G_BEGIN_DECLS
+
+/* object forward declarations */
+
+typedef struct _EphyTbiLocation EphyTbiLocation;
+typedef struct _EphyTbiLocationClass EphyTbiLocationClass;
+typedef struct _EphyTbiLocationPrivate EphyTbiLocationPrivate;
+
+/**
+ * TbiLocation object
+ */
+
+#define EPHY_TYPE_TBI_LOCATION (ephy_tbi_location_get_type())
+#define EPHY_TBI_LOCATION(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EPHY_TYPE_TBI_LOCATION,\
+ EphyTbiLocation))
+#define EPHY_TBI_LOCATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EPHY_TYPE_TBI_LOCATION,\
+ EphyTbiLocationClass))
+#define EPHY_IS_TBI_LOCATION(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EPHY_TYPE_TBI_LOCATION))
+#define EPHY_IS_TBI_LOCATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), EPHY_TYPE_TBI_LOCATION))
+#define EPHY_TBI_LOCATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EPHY_TYPE_TBI_LOCATION,\
+ EphyTbiLocationClass))
+
+struct _EphyTbiLocationClass
+{
+ EphyTbItemClass parent_class;
+};
+
+/* Remember: fields are public read-only */
+struct _EphyTbiLocation
+{
+ EphyTbItem parent_object;
+
+ EphyTbiLocationPrivate *priv;
+};
+
+/* this class is abstract */
+
+GType ephy_tbi_location_get_type (void);
+EphyTbiLocation * ephy_tbi_location_new (void);
+
+G_END_DECLS
+
+#endif
diff --git a/lib/toolbar/ephy-tbi-navigation-history.c b/lib/toolbar/ephy-tbi-navigation-history.c
new file mode 100644
index 000000000..c6edc9865
--- /dev/null
+++ b/lib/toolbar/ephy-tbi-navigation-history.c
@@ -0,0 +1,342 @@
+/*
+ * Copyright (C) 2002 Ricardo Fernández Pascual
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <libgnome/gnome-i18n.h>
+#include <bonobo/bonobo-ui-toolbar-button-item.h>
+#include <bonobo/bonobo-property-bag.h>
+#include <gtk/gtktogglebutton.h>
+#include <gtk/gtkstock.h>
+#include <string.h>
+
+#include "ephy-tbi-navigation-history.h"
+#include "ephy-gobject-misc.h"
+#include "ephy-marshal.h"
+#include "ephy-bonobo-extensions.h"
+
+#define NOT_IMPLEMENTED g_warning ("not implemented: " G_STRLOC);
+//#define DEBUG_MSG(x) g_print x
+#define DEBUG_MSG(x)
+
+/**
+ * Private data
+ */
+struct _EphyTbiNavigationHistoryPrivate
+{
+ GtkWidget *widget;
+
+ EphyTbiNavigationHistoryDirection direction;
+};
+
+enum
+{
+ TOOLBAR_ITEM_STYLE_PROP,
+ TOOLBAR_ITEM_ORIENTATION_PROP,
+ TOOLBAR_ITEM_PRIORITY_PROP
+};
+
+/**
+ * Private functions, only availble from this file
+ */
+static void ephy_tbi_navigation_history_class_init (EphyTbiNavigationHistoryClass *klass);
+static void ephy_tbi_navigation_history_init (EphyTbiNavigationHistory *tb);
+static void ephy_tbi_navigation_history_finalize_impl (GObject *o);
+static GtkWidget * ephy_tbi_navigation_history_get_widget_impl (EphyTbItem *i);
+static GdkPixbuf * ephy_tbi_navigation_history_get_icon_impl (EphyTbItem *i);
+static gchar * ephy_tbi_navigation_history_get_name_human_impl (EphyTbItem *i);
+static gchar * ephy_tbi_navigation_history_to_string_impl (EphyTbItem *i);
+static gboolean ephy_tbi_navigation_history_is_unique_impl (EphyTbItem *i);
+static EphyTbItem * ephy_tbi_navigation_history_clone_impl (EphyTbItem *i);
+static void ephy_tbi_navigation_history_parse_properties_impl (EphyTbItem *i, const gchar *props);
+static void ephy_tbi_navigation_history_add_to_bonobo_tb_impl (EphyTbItem *i,
+ BonoboUIComponent *ui,
+ const char *container_path,
+ guint index);
+
+static gpointer ephy_tb_item_class;
+
+/**
+ * TbiNavigationHistory object
+ */
+
+MAKE_GET_TYPE (ephy_tbi_navigation_history, "EphyTbiNavigationHistory", EphyTbiNavigationHistory,
+ ephy_tbi_navigation_history_class_init,
+ ephy_tbi_navigation_history_init, EPHY_TYPE_TB_ITEM);
+
+static void
+ephy_tbi_navigation_history_class_init (EphyTbiNavigationHistoryClass *klass)
+{
+ G_OBJECT_CLASS (klass)->finalize = ephy_tbi_navigation_history_finalize_impl;
+
+ EPHY_TB_ITEM_CLASS (klass)->get_widget = ephy_tbi_navigation_history_get_widget_impl;
+ EPHY_TB_ITEM_CLASS (klass)->get_icon = ephy_tbi_navigation_history_get_icon_impl;
+ EPHY_TB_ITEM_CLASS (klass)->get_name_human = ephy_tbi_navigation_history_get_name_human_impl;
+ EPHY_TB_ITEM_CLASS (klass)->to_string = ephy_tbi_navigation_history_to_string_impl;
+ EPHY_TB_ITEM_CLASS (klass)->is_unique = ephy_tbi_navigation_history_is_unique_impl;
+ EPHY_TB_ITEM_CLASS (klass)->clone = ephy_tbi_navigation_history_clone_impl;
+ EPHY_TB_ITEM_CLASS (klass)->parse_properties = ephy_tbi_navigation_history_parse_properties_impl;
+ EPHY_TB_ITEM_CLASS (klass)->add_to_bonobo_tb = ephy_tbi_navigation_history_add_to_bonobo_tb_impl;
+
+ ephy_tb_item_class = g_type_class_peek_parent (klass);
+}
+
+static void
+ephy_tbi_navigation_history_init (EphyTbiNavigationHistory *tb)
+{
+ EphyTbiNavigationHistoryPrivate *p = g_new0 (EphyTbiNavigationHistoryPrivate, 1);
+ tb->priv = p;
+
+ p->direction = EPHY_TBI_NAVIGATION_HISTORY_BACK;
+}
+
+EphyTbiNavigationHistory *
+ephy_tbi_navigation_history_new (void)
+{
+ EphyTbiNavigationHistory *ret = g_object_new (EPHY_TYPE_TBI_NAVIGATION_HISTORY, NULL);
+ return ret;
+}
+
+static void
+ephy_tbi_navigation_history_finalize_impl (GObject *o)
+{
+ EphyTbiNavigationHistory *it = EPHY_TBI_NAVIGATION_HISTORY (o);
+ EphyTbiNavigationHistoryPrivate *p = it->priv;
+
+ if (p->widget)
+ {
+ g_object_unref (p->widget);
+ }
+
+ g_free (p);
+
+ DEBUG_MSG (("EphyTbiNavigationHistory finalized\n"));
+
+ G_OBJECT_CLASS (ephy_tb_item_class)->finalize (o);
+}
+
+static GtkWidget *
+ephy_tbi_navigation_history_get_widget_impl (EphyTbItem *i)
+{
+ EphyTbiNavigationHistory *iz = EPHY_TBI_NAVIGATION_HISTORY (i);
+ EphyTbiNavigationHistoryPrivate *p = iz->priv;
+
+ DEBUG_MSG (("in ephy_tbi_navigation_history_get_widget_impl\n"));
+ if (!p->widget)
+ {
+ DEBUG_MSG (("in ephy_tbi_navigation_history_get_widget_impl, really\n"));
+
+ p->widget = gtk_toggle_button_new ();
+ gtk_button_set_relief (GTK_BUTTON (p->widget), GTK_RELIEF_NONE);
+
+ gtk_container_add (GTK_CONTAINER (p->widget),
+ gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_OUT));
+
+ g_object_ref (p->widget);
+ gtk_object_sink (GTK_OBJECT (p->widget));
+ }
+
+ return p->widget;
+}
+
+static GdkPixbuf *
+ephy_tbi_navigation_history_get_icon_impl (EphyTbItem *i)
+{
+ return NULL;
+}
+
+static gchar *
+ephy_tbi_navigation_history_get_name_human_impl (EphyTbItem *i)
+{
+ EphyTbiNavigationHistoryPrivate *p = EPHY_TBI_NAVIGATION_HISTORY (i)->priv;
+ const gchar *ret;
+
+ switch (p->direction)
+ {
+ case EPHY_TBI_NAVIGATION_HISTORY_BACK:
+ ret = _("Back History");
+ break;
+ case EPHY_TBI_NAVIGATION_HISTORY_FORWARD:
+ ret = _("Forward History");
+ break;
+ case EPHY_TBI_NAVIGATION_HISTORY_UP:
+ ret = _("Up Several Levels");
+ break;
+ default:
+ g_assert_not_reached ();
+ ret = "unknown";
+ }
+
+ return g_strdup (ret);
+}
+
+static gchar *
+ephy_tbi_navigation_history_to_string_impl (EphyTbItem *i)
+{
+ EphyTbiNavigationHistoryPrivate *p = EPHY_TBI_NAVIGATION_HISTORY (i)->priv;
+
+ /* if it had any properties, the string should include them */
+ const char *sdir;
+
+ switch (p->direction)
+ {
+ case EPHY_TBI_NAVIGATION_HISTORY_BACK:
+ sdir = "back";
+ break;
+ case EPHY_TBI_NAVIGATION_HISTORY_FORWARD:
+ sdir = "forward";
+ break;
+ case EPHY_TBI_NAVIGATION_HISTORY_UP:
+ sdir = "up";
+ break;
+ default:
+ g_assert_not_reached ();
+ sdir = "unknown";
+ }
+
+ return g_strdup_printf ("%s=navigation_history(direction=%s)", i->id, sdir);
+}
+
+static gboolean
+ephy_tbi_navigation_history_is_unique_impl (EphyTbItem *i)
+{
+ return TRUE;
+}
+
+static EphyTbItem *
+ephy_tbi_navigation_history_clone_impl (EphyTbItem *i)
+{
+ EphyTbiNavigationHistoryPrivate *p = EPHY_TBI_NAVIGATION_HISTORY (i)->priv;
+ EphyTbItem *ret = EPHY_TB_ITEM (ephy_tbi_navigation_history_new ());
+
+ ephy_tb_item_set_id (ret, i->id);
+
+ /* should copy properties too, if any */
+ ephy_tbi_navigation_history_set_direction (EPHY_TBI_NAVIGATION_HISTORY (ret), p->direction);
+
+ return ret;
+}
+
+static void
+ephy_tbi_navigation_history_property_set_cb (BonoboPropertyBag *bag,
+ const BonoboArg *arg,
+ guint arg_id,
+ CORBA_Environment *ev,
+ gpointer user_data)
+{
+ BonoboControl *control;
+ BonoboUIToolbarItem *item;
+ GtkOrientation orientation;
+ BonoboUIToolbarItemStyle style;
+
+ control = BONOBO_CONTROL (user_data);
+ item = BONOBO_UI_TOOLBAR_ITEM (bonobo_control_get_widget (control));
+
+ switch (arg_id) {
+ case TOOLBAR_ITEM_ORIENTATION_PROP:
+ orientation = BONOBO_ARG_GET_INT (arg);
+ bonobo_ui_toolbar_item_set_orientation (item, orientation);
+
+ if (GTK_WIDGET (item)->parent) {
+ gtk_widget_queue_resize (GTK_WIDGET (item)->parent);
+ }
+ break;
+ case TOOLBAR_ITEM_STYLE_PROP:
+ style = BONOBO_ARG_GET_INT (arg);
+ bonobo_ui_toolbar_item_set_style (item, style);
+ break;
+ }
+}
+
+static void
+ephy_tbi_navigation_history_add_to_bonobo_tb_impl (EphyTbItem *i, BonoboUIComponent *ui,
+ const char *container_path, guint index)
+{
+ BonoboPropertyBag *pb;
+ BonoboControl *wrapper;
+ BonoboUIToolbarItem *item;
+ GtkWidget *button;
+
+ DEBUG_MSG (("in ephy_tbi_navigation_history_add_to_bonobo_tb_impl\n"));
+
+ item = BONOBO_UI_TOOLBAR_ITEM (bonobo_ui_toolbar_item_new ());
+
+ button = ephy_tb_item_get_widget (i);
+ gtk_container_add (GTK_CONTAINER (item), button);
+ gtk_widget_show_all (GTK_WIDGET (item));
+
+ wrapper = ephy_bonobo_add_numbered_control (ui, GTK_WIDGET (item), index, container_path);
+
+ pb = bonobo_property_bag_new
+ (NULL, ephy_tbi_navigation_history_property_set_cb, wrapper);
+ bonobo_property_bag_add (pb, "style",
+ TOOLBAR_ITEM_STYLE_PROP,
+ BONOBO_ARG_INT, NULL, NULL,
+ Bonobo_PROPERTY_WRITEABLE);
+ bonobo_property_bag_add (pb, "orientation",
+ TOOLBAR_ITEM_ORIENTATION_PROP,
+ BONOBO_ARG_INT, NULL, NULL,
+ Bonobo_PROPERTY_WRITEABLE);
+ bonobo_control_set_properties (wrapper, BONOBO_OBJREF (pb), NULL);
+ bonobo_object_unref (pb);
+}
+
+static void
+ephy_tbi_navigation_history_parse_properties_impl (EphyTbItem *it, const gchar *props)
+{
+ EphyTbiNavigationHistory *a = EPHY_TBI_NAVIGATION_HISTORY (it);
+
+ /* yes, this is quite hacky, but works */
+
+ /* we have aproperty, the direction */
+ const gchar *direc_prop;
+
+ direc_prop = strstr (props, "direction=");
+ if (direc_prop)
+ {
+ direc_prop += strlen ("direction=");
+ if (!strncmp (direc_prop, "back", 4))
+ {
+ ephy_tbi_navigation_history_set_direction (a, EPHY_TBI_NAVIGATION_HISTORY_BACK);
+ }
+ else if (!strncmp (direc_prop, "forward", 4))
+ {
+ ephy_tbi_navigation_history_set_direction (a, EPHY_TBI_NAVIGATION_HISTORY_FORWARD);
+ }
+ else if (!strncmp (direc_prop, "up", 2))
+ {
+ ephy_tbi_navigation_history_set_direction (a, EPHY_TBI_NAVIGATION_HISTORY_UP);
+ }
+ }
+}
+
+void
+ephy_tbi_navigation_history_set_direction (EphyTbiNavigationHistory *a, EphyTbiNavigationHistoryDirection d)
+{
+ EphyTbiNavigationHistoryPrivate *p = a->priv;
+
+ g_return_if_fail (d == EPHY_TBI_NAVIGATION_HISTORY_UP
+ || d == EPHY_TBI_NAVIGATION_HISTORY_BACK
+ || d == EPHY_TBI_NAVIGATION_HISTORY_FORWARD);
+
+ p->direction = d;
+
+}
+
diff --git a/lib/toolbar/ephy-tbi-navigation-history.h b/lib/toolbar/ephy-tbi-navigation-history.h
new file mode 100644
index 000000000..29cb6c32a
--- /dev/null
+++ b/lib/toolbar/ephy-tbi-navigation-history.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2002 Ricardo Fernández Pascual
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EPHY_TBI_NAVIGATION_HISTORY_H
+#define EPHY_TBI_NAVIGATION_HISTORY_H
+
+#include "ephy-toolbar-item.h"
+
+G_BEGIN_DECLS
+
+/* object forward declarations */
+
+typedef struct _EphyTbiNavigationHistory EphyTbiNavigationHistory;
+typedef struct _EphyTbiNavigationHistoryClass EphyTbiNavigationHistoryClass;
+typedef struct _EphyTbiNavigationHistoryPrivate EphyTbiNavigationHistoryPrivate;
+
+/**
+ * TbiNavigationHistory object
+ */
+
+#define EPHY_TYPE_TBI_NAVIGATION_HISTORY (ephy_tbi_navigation_history_get_type())
+#define EPHY_TBI_NAVIGATION_HISTORY(object) (G_TYPE_CHECK_INSTANCE_CAST((object), \
+ EPHY_TYPE_TBI_NAVIGATION_HISTORY,\
+ EphyTbiNavigationHistory))
+#define EPHY_TBI_NAVIGATION_HISTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), \
+ EPHY_TYPE_TBI_NAVIGATION_HISTORY,\
+ EphyTbiNavigationHistoryClass))
+#define EPHY_IS_TBI_NAVIGATION_HISTORY(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), \
+ EPHY_TYPE_TBI_NAVIGATION_HISTORY))
+#define EPHY_IS_TBI_NAVIGATION_HISTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), \
+ EPHY_TYPE_TBI_NAVIGATION_HISTORY))
+#define EPHY_TBI_NAVIGATION_HISTORY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), \
+ EPHY_TYPE_TBI_NAVIGATION_HISTORY,\
+ EphyTbiNavigationHistoryClass))
+typedef enum
+{
+ EPHY_TBI_NAVIGATION_HISTORY_UP,
+ EPHY_TBI_NAVIGATION_HISTORY_BACK,
+ EPHY_TBI_NAVIGATION_HISTORY_FORWARD
+} EphyTbiNavigationHistoryDirection;
+
+
+struct _EphyTbiNavigationHistoryClass
+{
+ EphyTbItemClass parent_class;
+};
+
+/* Remember: fields are public read-only */
+struct _EphyTbiNavigationHistory
+{
+ EphyTbItem parent_object;
+
+ EphyTbiNavigationHistoryPrivate *priv;
+};
+
+/* this class is abstract */
+
+GType ephy_tbi_navigation_history_get_type (void);
+EphyTbiNavigationHistory *ephy_tbi_navigation_history_new (void);
+void ephy_tbi_navigation_history_set_direction (EphyTbiNavigationHistory *a,
+ EphyTbiNavigationHistoryDirection d);
+
+G_END_DECLS
+
+#endif
+
diff --git a/lib/toolbar/ephy-tbi-separator.c b/lib/toolbar/ephy-tbi-separator.c
new file mode 100644
index 000000000..43f69bd96
--- /dev/null
+++ b/lib/toolbar/ephy-tbi-separator.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2002 Ricardo Fernández Pascual
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <libgnome/gnome-i18n.h>
+#include <gtk/gtkstock.h>
+
+#include "ephy-tbi-separator.h"
+#include "ephy-gobject-misc.h"
+#include "ephy-marshal.h"
+#include "ephy-bonobo-extensions.h"
+
+#define NOT_IMPLEMENTED g_warning ("not implemented: " G_STRLOC);
+//#define DEBUG_MSG(x) g_print x
+#define DEBUG_MSG(x)
+
+/**
+ * Private data
+ */
+struct _EphyTbiSeparatorPrivate
+{
+ GtkWidget *widget;
+};
+
+/**
+ * Private functions, only availble from this file
+ */
+static void ephy_tbi_separator_class_init (EphyTbiSeparatorClass *klass);
+static void ephy_tbi_separator_init (EphyTbiSeparator *tb);
+static void ephy_tbi_separator_finalize_impl (GObject *o);
+static GtkWidget * ephy_tbi_separator_get_widget_impl (EphyTbItem *i);
+static GdkPixbuf * ephy_tbi_separator_get_icon_impl (EphyTbItem *i);
+static gchar * ephy_tbi_separator_get_name_human_impl (EphyTbItem *i);
+static gchar * ephy_tbi_separator_to_string_impl (EphyTbItem *i);
+static gboolean ephy_tbi_separator_is_unique_impl (EphyTbItem *i);
+static EphyTbItem * ephy_tbi_separator_clone_impl (EphyTbItem *i);
+static void ephy_tbi_separator_parse_properties_impl(EphyTbItem *i, const gchar *props);
+static void ephy_tbi_separator_add_to_bonobo_tb_impl(EphyTbItem *i,
+ BonoboUIComponent *ui,
+ const char *container_path,
+ guint index);
+
+static gpointer ephy_tb_item_class;
+
+/**
+ * TbiSeparator object
+ */
+
+MAKE_GET_TYPE (ephy_tbi_separator, "EphyTbiSeparator", EphyTbiSeparator, ephy_tbi_separator_class_init,
+ ephy_tbi_separator_init, EPHY_TYPE_TB_ITEM);
+
+static void
+ephy_tbi_separator_class_init (EphyTbiSeparatorClass *klass)
+{
+ G_OBJECT_CLASS (klass)->finalize = ephy_tbi_separator_finalize_impl;
+
+ EPHY_TB_ITEM_CLASS (klass)->get_widget = ephy_tbi_separator_get_widget_impl;
+ EPHY_TB_ITEM_CLASS (klass)->get_icon = ephy_tbi_separator_get_icon_impl;
+ EPHY_TB_ITEM_CLASS (klass)->get_name_human = ephy_tbi_separator_get_name_human_impl;
+ EPHY_TB_ITEM_CLASS (klass)->to_string = ephy_tbi_separator_to_string_impl;
+ EPHY_TB_ITEM_CLASS (klass)->is_unique = ephy_tbi_separator_is_unique_impl;
+ EPHY_TB_ITEM_CLASS (klass)->clone = ephy_tbi_separator_clone_impl;
+ EPHY_TB_ITEM_CLASS (klass)->parse_properties = ephy_tbi_separator_parse_properties_impl;
+ EPHY_TB_ITEM_CLASS (klass)->add_to_bonobo_tb = ephy_tbi_separator_add_to_bonobo_tb_impl;
+
+ ephy_tb_item_class = g_type_class_peek_parent (klass);
+}
+
+static void
+ephy_tbi_separator_init (EphyTbiSeparator *tb)
+{
+ EphyTbiSeparatorPrivate *p = g_new0 (EphyTbiSeparatorPrivate, 1);
+ tb->priv = p;
+}
+
+EphyTbiSeparator *
+ephy_tbi_separator_new (void)
+{
+ EphyTbiSeparator *ret = g_object_new (EPHY_TYPE_TBI_SEPARATOR, NULL);
+ return ret;
+}
+
+static void
+ephy_tbi_separator_finalize_impl (GObject *o)
+{
+ EphyTbiSeparator *it = EPHY_TBI_SEPARATOR (o);
+ EphyTbiSeparatorPrivate *p = it->priv;
+
+ if (p->widget)
+ {
+ g_object_unref (p->widget);
+ }
+
+ g_free (p);
+
+ DEBUG_MSG (("EphyTbiSeparator finalized\n"));
+
+ G_OBJECT_CLASS (ephy_tb_item_class)->finalize (o);
+}
+
+static GtkWidget *
+ephy_tbi_separator_get_widget_impl (EphyTbItem *i)
+{
+ return NULL;
+}
+
+static GdkPixbuf *
+ephy_tbi_separator_get_icon_impl (EphyTbItem *i)
+{
+ return NULL;
+}
+
+static gchar *
+ephy_tbi_separator_get_name_human_impl (EphyTbItem *i)
+{
+ return g_strdup (_("Separator"));
+}
+
+static gchar *
+ephy_tbi_separator_to_string_impl (EphyTbItem *i)
+{
+ /* if it had any properties, the string should include them */
+ return g_strdup_printf ("%s=separator", i->id);
+}
+
+static gboolean
+ephy_tbi_separator_is_unique_impl (EphyTbItem *i)
+{
+ return FALSE;
+}
+
+static EphyTbItem *
+ephy_tbi_separator_clone_impl (EphyTbItem *i)
+{
+ EphyTbItem *ret = EPHY_TB_ITEM (ephy_tbi_separator_new ());
+
+ ephy_tb_item_set_id (ret, i->id);
+
+ /* should copy properties too, if any */
+
+ return ret;
+}
+
+static void
+ephy_tbi_separator_add_to_bonobo_tb_impl (EphyTbItem *i, BonoboUIComponent *ui,
+ const char *container_path, guint index)
+{
+ static gint hack = 0;
+ gchar *xml;
+
+ xml = g_strdup_printf ("<separator name=\"sep%d\"/>", ++hack);
+ bonobo_ui_component_set (ui, container_path, xml, NULL);
+ g_free (xml);
+}
+
+static void
+ephy_tbi_separator_parse_properties_impl (EphyTbItem *it, const gchar *props)
+{
+ /* we have no properties */
+}
+
diff --git a/lib/toolbar/ephy-tbi-separator.h b/lib/toolbar/ephy-tbi-separator.h
new file mode 100644
index 000000000..754d85fec
--- /dev/null
+++ b/lib/toolbar/ephy-tbi-separator.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2002 Ricardo Fernández Pascual
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EPHY_TBI_SEPARATOR_H
+#define EPHY_TBI_SEPARATOR_H
+
+#include "ephy-toolbar-item.h"
+
+G_BEGIN_DECLS
+
+/* object forward declarations */
+
+typedef struct _EphyTbiSeparator EphyTbiSeparator;
+typedef struct _EphyTbiSeparatorClass EphyTbiSeparatorClass;
+typedef struct _EphyTbiSeparatorPrivate EphyTbiSeparatorPrivate;
+
+/**
+ * TbiSeparator object
+ */
+
+#define EPHY_TYPE_TBI_SEPARATOR (ephy_tbi_separator_get_type())
+#define EPHY_TBI_SEPARATOR(object) (G_TYPE_CHECK_INSTANCE_CAST((object), \
+ EPHY_TYPE_TBI_SEPARATOR,\
+ EphyTbiSeparator))
+#define EPHY_TBI_SEPARATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EPHY_TYPE_TBI_SEPARATOR,\
+ EphyTbiSeparatorClass))
+#define EPHY_IS_TBI_SEPARATOR(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), \
+ EPHY_TYPE_TBI_SEPARATOR))
+#define EPHY_IS_TBI_SEPARATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), EPHY_TYPE_TBI_SEPARATOR))
+#define EPHY_TBI_SEPARATOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EPHY_TYPE_TBI_SEPARATOR,\
+ EphyTbiSeparatorClass))
+
+struct _EphyTbiSeparatorClass
+{
+ EphyTbItemClass parent_class;
+};
+
+/* Remember: fields are public read-only */
+struct _EphyTbiSeparator
+{
+ EphyTbItem parent_object;
+
+ EphyTbiSeparatorPrivate *priv;
+};
+
+/* this class is abstract */
+
+GType ephy_tbi_separator_get_type (void);
+EphyTbiSeparator * ephy_tbi_separator_new (void);
+
+G_END_DECLS
+
+#endif
diff --git a/lib/toolbar/ephy-tbi-spinner.c b/lib/toolbar/ephy-tbi-spinner.c
new file mode 100644
index 000000000..6f37764ec
--- /dev/null
+++ b/lib/toolbar/ephy-tbi-spinner.c
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2002 Ricardo Fernández Pascual
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <libgnome/gnome-i18n.h>
+#include <gtk/gtkhbox.h>
+
+#include "ephy-tbi-spinner.h"
+#include "ephy-gobject-misc.h"
+#include "ephy-marshal.h"
+#include "ephy-bonobo-extensions.h"
+
+#define NOT_IMPLEMENTED g_warning ("not implemented: " G_STRLOC);
+//#define DEBUG_MSG(x) g_print x
+#define DEBUG_MSG(x)
+
+/**
+ * Private data
+ */
+struct _EphyTbiSpinnerPrivate
+{
+ GtkWidget *widget;
+};
+
+/**
+ * Private functions, only availble from this file
+ */
+static void ephy_tbi_spinner_class_init (EphyTbiSpinnerClass *klass);
+static void ephy_tbi_spinner_init (EphyTbiSpinner *tb);
+static void ephy_tbi_spinner_finalize_impl (GObject *o);
+static GtkWidget * ephy_tbi_spinner_get_widget_impl (EphyTbItem *i);
+static GdkPixbuf * ephy_tbi_spinner_get_icon_impl (EphyTbItem *i);
+static gchar * ephy_tbi_spinner_get_name_human_impl (EphyTbItem *i);
+static gchar * ephy_tbi_spinner_to_string_impl (EphyTbItem *i);
+static gboolean ephy_tbi_spinner_is_unique_impl (EphyTbItem *i);
+static EphyTbItem * ephy_tbi_spinner_clone_impl (EphyTbItem *i);
+static void ephy_tbi_spinner_parse_properties_impl (EphyTbItem *i, const gchar *props);
+static void ephy_tbi_spinner_add_to_bonobo_tb_impl (EphyTbItem *i,
+ BonoboUIComponent *ui,
+ const char *container_path,
+ guint index);
+
+static gpointer ephy_tb_item_class;
+
+/**
+ * TbiSpinner object
+ */
+
+MAKE_GET_TYPE (ephy_tbi_spinner, "EphyTbiSpinner", EphyTbiSpinner, ephy_tbi_spinner_class_init,
+ ephy_tbi_spinner_init, EPHY_TYPE_TB_ITEM);
+
+static void
+ephy_tbi_spinner_class_init (EphyTbiSpinnerClass *klass)
+{
+ G_OBJECT_CLASS (klass)->finalize = ephy_tbi_spinner_finalize_impl;
+
+ EPHY_TB_ITEM_CLASS (klass)->get_widget = ephy_tbi_spinner_get_widget_impl;
+ EPHY_TB_ITEM_CLASS (klass)->get_icon = ephy_tbi_spinner_get_icon_impl;
+ EPHY_TB_ITEM_CLASS (klass)->get_name_human = ephy_tbi_spinner_get_name_human_impl;
+ EPHY_TB_ITEM_CLASS (klass)->to_string = ephy_tbi_spinner_to_string_impl;
+ EPHY_TB_ITEM_CLASS (klass)->is_unique = ephy_tbi_spinner_is_unique_impl;
+ EPHY_TB_ITEM_CLASS (klass)->clone = ephy_tbi_spinner_clone_impl;
+ EPHY_TB_ITEM_CLASS (klass)->parse_properties = ephy_tbi_spinner_parse_properties_impl;
+ EPHY_TB_ITEM_CLASS (klass)->add_to_bonobo_tb = ephy_tbi_spinner_add_to_bonobo_tb_impl;
+
+ ephy_tb_item_class = g_type_class_peek_parent (klass);
+}
+
+static void
+ephy_tbi_spinner_init (EphyTbiSpinner *tb)
+{
+ EphyTbiSpinnerPrivate *p = g_new0 (EphyTbiSpinnerPrivate, 1);
+ tb->priv = p;
+}
+
+EphyTbiSpinner *
+ephy_tbi_spinner_new (void)
+{
+ EphyTbiSpinner *ret = g_object_new (EPHY_TYPE_TBI_SPINNER, NULL);
+ return ret;
+}
+
+static void
+ephy_tbi_spinner_finalize_impl (GObject *o)
+{
+ EphyTbiSpinner *it = EPHY_TBI_SPINNER (o);
+ EphyTbiSpinnerPrivate *p = it->priv;
+
+ if (p->widget)
+ {
+ g_object_unref (p->widget);
+ }
+
+ g_free (p);
+
+ DEBUG_MSG (("EphyTbiSpinner finalized\n"));
+
+ G_OBJECT_CLASS (ephy_tb_item_class)->finalize (o);
+}
+
+static GtkWidget *
+ephy_tbi_spinner_get_widget_impl (EphyTbItem *i)
+{
+ EphyTbiSpinner *iz = EPHY_TBI_SPINNER (i);
+ EphyTbiSpinnerPrivate *p = iz->priv;
+
+ if (!p->widget)
+ {
+ /* here, we create only a box */
+ p->widget = gtk_hbox_new (FALSE, 0);
+ g_object_ref (p->widget);
+ gtk_object_sink (GTK_OBJECT (p->widget));
+ }
+
+ return p->widget;
+}
+
+static GdkPixbuf *
+ephy_tbi_spinner_get_icon_impl (EphyTbItem *i)
+{
+ /* need an icon for this */
+ return NULL;
+}
+
+static gchar *
+ephy_tbi_spinner_get_name_human_impl (EphyTbItem *i)
+{
+ return g_strdup (_("Spinner"));
+}
+
+static gchar *
+ephy_tbi_spinner_to_string_impl (EphyTbItem *i)
+{
+ /* if it had any properties, the string should include them */
+ return g_strdup_printf ("%s=spinner", i->id);
+}
+
+static gboolean
+ephy_tbi_spinner_is_unique_impl (EphyTbItem *i)
+{
+ return TRUE;
+}
+
+static EphyTbItem *
+ephy_tbi_spinner_clone_impl (EphyTbItem *i)
+{
+ EphyTbItem *ret = EPHY_TB_ITEM (ephy_tbi_spinner_new ());
+
+ ephy_tb_item_set_id (ret, i->id);
+
+ /* should copy properties too, if any */
+
+ return ret;
+}
+
+static void
+ephy_tbi_spinner_add_to_bonobo_tb_impl (EphyTbItem *i, BonoboUIComponent *ui,
+ const char *container_path, guint index)
+{
+ GtkWidget *w = ephy_tb_item_get_widget (i);
+ gtk_widget_show (w);
+ ephy_bonobo_add_numbered_control (ui, w, index, container_path);
+}
+
+static void
+ephy_tbi_spinner_parse_properties_impl (EphyTbItem *it, const gchar *props)
+{
+ /* we have no properties */
+}
+
diff --git a/lib/toolbar/ephy-tbi-spinner.h b/lib/toolbar/ephy-tbi-spinner.h
new file mode 100644
index 000000000..1bb04f277
--- /dev/null
+++ b/lib/toolbar/ephy-tbi-spinner.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2002 Ricardo Fernández Pascual
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EPHY_TBI_SPINNER_H
+#define EPHY_TBI_SPINNER_H
+
+#include "ephy-toolbar-item.h"
+
+G_BEGIN_DECLS
+
+/* object forward declarations */
+
+typedef struct _EphyTbiSpinner EphyTbiSpinner;
+typedef struct _EphyTbiSpinnerClass EphyTbiSpinnerClass;
+typedef struct _EphyTbiSpinnerPrivate EphyTbiSpinnerPrivate;
+
+/**
+ * TbiSpinner object
+ */
+
+#define EPHY_TYPE_TBI_SPINNER (ephy_tbi_spinner_get_type())
+#define EPHY_TBI_SPINNER(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EPHY_TYPE_TBI_SPINNER,\
+ EphyTbiSpinner))
+#define EPHY_TBI_SPINNER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EPHY_TYPE_TBI_SPINNER,\
+ EphyTbiSpinnerClass))
+#define EPHY_IS_TBI_SPINNER(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EPHY_TYPE_TBI_SPINNER))
+#define EPHY_IS_TBI_SPINNER_CLASS(klass)(G_TYPE_CHECK_CLASS_TYPE((klass), EPHY_TYPE_TBI_SPINNER))
+#define EPHY_TBI_SPINNER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EPHY_TYPE_TBI_SPINNER,\
+ EphyTbiSpinnerClass))
+
+struct _EphyTbiSpinnerClass
+{
+ EphyTbItemClass parent_class;
+};
+
+/* Remember: fields are public read-only */
+struct _EphyTbiSpinner
+{
+ EphyTbItem parent_object;
+
+ EphyTbiSpinnerPrivate *priv;
+};
+
+/* this class is abstract */
+
+GType ephy_tbi_spinner_get_type (void);
+EphyTbiSpinner * ephy_tbi_spinner_new (void);
+
+G_END_DECLS
+
+#endif
diff --git a/lib/toolbar/ephy-tbi-std-toolitem.c b/lib/toolbar/ephy-tbi-std-toolitem.c
new file mode 100644
index 000000000..deb468ecb
--- /dev/null
+++ b/lib/toolbar/ephy-tbi-std-toolitem.c
@@ -0,0 +1,467 @@
+/*
+ * Copyright (C) 2002 Ricardo Fernández Pascual
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <libgnome/gnome-i18n.h>
+#include <bonobo/bonobo-ui-toolbar-button-item.h>
+#include <bonobo/bonobo-property-bag.h>
+#include <gtk/gtkstock.h>
+#include <string.h>
+
+#include "ephy-tbi-std-toolitem.h"
+#include "ephy-gobject-misc.h"
+#include "ephy-marshal.h"
+#include "ephy-bonobo-extensions.h"
+
+#define NOT_IMPLEMENTED g_warning ("not implemented: " G_STRLOC);
+//#define DEBUG_MSG(x) g_print x
+#define DEBUG_MSG(x)
+
+/**
+ * Private data
+ */
+struct _EphyTbiStdToolitemPrivate
+{
+ GtkWidget *widget;
+
+ EphyTbiStdToolitemItem item;
+};
+
+
+/**
+ * Private functions, only availble from this file
+ */
+static void ephy_tbi_std_toolitem_class_init (EphyTbiStdToolitemClass *klass);
+static void ephy_tbi_std_toolitem_init (EphyTbiStdToolitem *tb);
+static void ephy_tbi_std_toolitem_finalize_impl (GObject *o);
+static GtkWidget * ephy_tbi_std_toolitem_get_widget_impl (EphyTbItem *i);
+static GdkPixbuf * ephy_tbi_std_toolitem_get_icon_impl (EphyTbItem *i);
+static gchar * ephy_tbi_std_toolitem_get_name_human_impl (EphyTbItem *i);
+static gchar * ephy_tbi_std_toolitem_to_string_impl (EphyTbItem *i);
+static gboolean ephy_tbi_std_toolitem_is_unique_impl (EphyTbItem *i);
+static EphyTbItem * ephy_tbi_std_toolitem_clone_impl (EphyTbItem *i);
+static void ephy_tbi_std_toolitem_parse_properties_impl (EphyTbItem *i, const gchar *props);
+static void ephy_tbi_std_toolitem_add_to_bonobo_tb_impl (EphyTbItem *i,
+ BonoboUIComponent *ui,
+ const char *container_path,
+ guint index);
+
+static gpointer ephy_tb_item_class;
+
+/**
+ * TbiStdToolitem object
+ */
+
+MAKE_GET_TYPE (ephy_tbi_std_toolitem, "EphyTbiStdToolitem", EphyTbiStdToolitem,
+ ephy_tbi_std_toolitem_class_init,
+ ephy_tbi_std_toolitem_init, EPHY_TYPE_TB_ITEM);
+
+static void
+ephy_tbi_std_toolitem_class_init (EphyTbiStdToolitemClass *klass)
+{
+ G_OBJECT_CLASS (klass)->finalize = ephy_tbi_std_toolitem_finalize_impl;
+
+ EPHY_TB_ITEM_CLASS (klass)->get_widget = ephy_tbi_std_toolitem_get_widget_impl;
+ EPHY_TB_ITEM_CLASS (klass)->get_icon = ephy_tbi_std_toolitem_get_icon_impl;
+ EPHY_TB_ITEM_CLASS (klass)->get_name_human = ephy_tbi_std_toolitem_get_name_human_impl;
+ EPHY_TB_ITEM_CLASS (klass)->to_string = ephy_tbi_std_toolitem_to_string_impl;
+ EPHY_TB_ITEM_CLASS (klass)->is_unique = ephy_tbi_std_toolitem_is_unique_impl;
+ EPHY_TB_ITEM_CLASS (klass)->clone = ephy_tbi_std_toolitem_clone_impl;
+ EPHY_TB_ITEM_CLASS (klass)->parse_properties = ephy_tbi_std_toolitem_parse_properties_impl;
+ EPHY_TB_ITEM_CLASS (klass)->add_to_bonobo_tb = ephy_tbi_std_toolitem_add_to_bonobo_tb_impl;
+
+ ephy_tb_item_class = g_type_class_peek_parent (klass);
+}
+
+static void
+ephy_tbi_std_toolitem_init (EphyTbiStdToolitem *tb)
+{
+ EphyTbiStdToolitemPrivate *p = g_new0 (EphyTbiStdToolitemPrivate, 1);
+ tb->priv = p;
+
+ p->item = EPHY_TBI_STD_TOOLITEM_BACK;
+}
+
+EphyTbiStdToolitem *
+ephy_tbi_std_toolitem_new (void)
+{
+ EphyTbiStdToolitem *ret = g_object_new (EPHY_TYPE_TBI_STD_TOOLITEM, NULL);
+ return ret;
+}
+
+static void
+ephy_tbi_std_toolitem_finalize_impl (GObject *o)
+{
+ EphyTbiStdToolitem *it = EPHY_TBI_STD_TOOLITEM (o);
+ EphyTbiStdToolitemPrivate *p = it->priv;
+
+ if (p->widget)
+ {
+ g_object_unref (p->widget);
+ }
+
+ g_free (p);
+
+ DEBUG_MSG (("EphyTbiStdToolitem finalized\n"));
+
+ G_OBJECT_CLASS (ephy_tb_item_class)->finalize (o);
+}
+
+static GtkWidget *
+ephy_tbi_std_toolitem_get_widget_impl (EphyTbItem *i)
+{
+ /* no widget avaible ... */
+ return NULL;
+}
+
+static GdkPixbuf *
+ephy_tbi_std_toolitem_get_icon_impl (EphyTbItem *i)
+{
+ EphyTbiStdToolitemPrivate *p = EPHY_TBI_STD_TOOLITEM (i)->priv;
+
+ static GdkPixbuf *pb_up = NULL;
+ static GdkPixbuf *pb_back = NULL;
+ static GdkPixbuf *pb_forward = NULL;
+ static GdkPixbuf *pb_stop = NULL;
+ static GdkPixbuf *pb_reload = NULL;
+ static GdkPixbuf *pb_home = NULL;
+ static GdkPixbuf *pb_go = NULL;
+ static GdkPixbuf *pb_new = NULL;
+
+ if (!pb_up)
+ {
+ /* what's the easier way? */
+ GtkWidget *b = gtk_spin_button_new_with_range (0, 1, 0.5);
+ pb_up = gtk_widget_render_icon (b,
+ GTK_STOCK_GO_UP,
+ GTK_ICON_SIZE_SMALL_TOOLBAR,
+ NULL);
+ pb_back = gtk_widget_render_icon (b,
+ GTK_STOCK_GO_BACK,
+ GTK_ICON_SIZE_SMALL_TOOLBAR,
+ NULL);
+ pb_forward = gtk_widget_render_icon (b,
+ GTK_STOCK_GO_FORWARD,
+ GTK_ICON_SIZE_SMALL_TOOLBAR,
+ NULL);
+ pb_stop = gtk_widget_render_icon (b,
+ GTK_STOCK_STOP,
+ GTK_ICON_SIZE_SMALL_TOOLBAR,
+ NULL);
+ pb_reload = gtk_widget_render_icon (b,
+ GTK_STOCK_REFRESH,
+ GTK_ICON_SIZE_SMALL_TOOLBAR,
+ NULL);
+ pb_home = gtk_widget_render_icon (b,
+ GTK_STOCK_HOME,
+ GTK_ICON_SIZE_SMALL_TOOLBAR,
+ NULL);
+ pb_go = gtk_widget_render_icon (b,
+ GTK_STOCK_JUMP_TO,
+ GTK_ICON_SIZE_SMALL_TOOLBAR,
+ NULL);
+ pb_new = gtk_widget_render_icon (b,
+ GTK_STOCK_NEW,
+ GTK_ICON_SIZE_SMALL_TOOLBAR,
+ NULL);
+ gtk_widget_destroy (b);
+ }
+
+ switch (p->item)
+ {
+ case EPHY_TBI_STD_TOOLITEM_BACK:
+ return g_object_ref (pb_back);
+ break;
+ case EPHY_TBI_STD_TOOLITEM_FORWARD:
+ return g_object_ref (pb_forward);
+ break;
+ case EPHY_TBI_STD_TOOLITEM_UP:
+ return g_object_ref (pb_up);
+ break;
+ case EPHY_TBI_STD_TOOLITEM_STOP:
+ return g_object_ref (pb_stop);
+ break;
+ case EPHY_TBI_STD_TOOLITEM_RELOAD:
+ return g_object_ref (pb_reload);
+ break;
+ case EPHY_TBI_STD_TOOLITEM_HOME:
+ return g_object_ref (pb_home);
+ break;
+ case EPHY_TBI_STD_TOOLITEM_GO:
+ return g_object_ref (pb_go);
+ break;
+ case EPHY_TBI_STD_TOOLITEM_NEW:
+ return g_object_ref (pb_new);
+ break;
+ default:
+ g_assert_not_reached ();
+ return NULL;
+ }
+}
+
+static gchar *
+ephy_tbi_std_toolitem_get_name_human_impl (EphyTbItem *i)
+{
+ EphyTbiStdToolitemPrivate *p = EPHY_TBI_STD_TOOLITEM (i)->priv;
+ const gchar *ret;
+
+ switch (p->item)
+ {
+ case EPHY_TBI_STD_TOOLITEM_BACK:
+ ret = _("Back");
+ break;
+ case EPHY_TBI_STD_TOOLITEM_FORWARD:
+ ret = _("Forward");
+ break;
+ case EPHY_TBI_STD_TOOLITEM_UP:
+ ret = _("Up");
+ break;
+ case EPHY_TBI_STD_TOOLITEM_STOP:
+ ret = _("Stop");
+ break;
+ case EPHY_TBI_STD_TOOLITEM_RELOAD:
+ ret = _("Reload");
+ break;
+ case EPHY_TBI_STD_TOOLITEM_HOME:
+ ret = _("Home");
+ break;
+ case EPHY_TBI_STD_TOOLITEM_GO:
+ ret = _("Go");
+ break;
+ case EPHY_TBI_STD_TOOLITEM_NEW:
+ ret = _("New");
+ break;
+ default:
+ g_assert_not_reached ();
+ ret = "unknown";
+ }
+
+ return g_strdup (ret);
+}
+
+static gchar *
+ephy_tbi_std_toolitem_to_string_impl (EphyTbItem *i)
+{
+ EphyTbiStdToolitemPrivate *p = EPHY_TBI_STD_TOOLITEM (i)->priv;
+
+ /* if it had any properties, the string should include them */
+ const char *sitem;
+
+ switch (p->item)
+ {
+ case EPHY_TBI_STD_TOOLITEM_BACK:
+ sitem = "back";
+ break;
+ case EPHY_TBI_STD_TOOLITEM_FORWARD:
+ sitem = "forward";
+ break;
+ case EPHY_TBI_STD_TOOLITEM_UP:
+ sitem = "up";
+ break;
+ case EPHY_TBI_STD_TOOLITEM_STOP:
+ sitem = "stop";
+ break;
+ case EPHY_TBI_STD_TOOLITEM_RELOAD:
+ sitem = "reload";
+ break;
+ case EPHY_TBI_STD_TOOLITEM_HOME:
+ sitem = "home";
+ break;
+ case EPHY_TBI_STD_TOOLITEM_GO:
+ sitem = "go";
+ break;
+ case EPHY_TBI_STD_TOOLITEM_NEW:
+ sitem = "new";
+ break;
+ default:
+ g_assert_not_reached ();
+ sitem = "unknown";
+ }
+
+ return g_strdup_printf ("%s=std_toolitem(item=%s)", i->id, sitem);
+}
+
+static gboolean
+ephy_tbi_std_toolitem_is_unique_impl (EphyTbItem *i)
+{
+ return TRUE;
+}
+
+static EphyTbItem *
+ephy_tbi_std_toolitem_clone_impl (EphyTbItem *i)
+{
+ EphyTbiStdToolitemPrivate *p = EPHY_TBI_STD_TOOLITEM (i)->priv;
+
+ EphyTbItem *ret = EPHY_TB_ITEM (ephy_tbi_std_toolitem_new ());
+
+ ephy_tb_item_set_id (ret, i->id);
+
+ /* should copy properties too, if any */
+ ephy_tbi_std_toolitem_set_item (EPHY_TBI_STD_TOOLITEM (ret), p->item);
+
+ return ret;
+}
+
+
+static void
+ephy_tbi_std_toolitem_add_to_bonobo_tb_impl (EphyTbItem *i, BonoboUIComponent *ui,
+ const char *container_path, guint index)
+{
+ EphyTbiStdToolitemPrivate *p = EPHY_TBI_STD_TOOLITEM (i)->priv;
+ gchar *xml_item;
+
+ switch (p->item)
+ {
+ case EPHY_TBI_STD_TOOLITEM_BACK:
+ xml_item = g_strdup_printf
+ ("<toolitem name=\"Back\" "
+ "label=\"%s\" "
+ "pixtype=\"stock\" pixname=\"gtk-go-back\" "
+ "priority=\"1\" "
+ "verb=\"GoBack\"/>", _("Back"));;
+ break;
+ case EPHY_TBI_STD_TOOLITEM_FORWARD:
+ xml_item = g_strdup_printf
+ ("<toolitem name=\"Forward\" "
+ "label=\"%s\" "
+ "pixtype=\"stock\" pixname=\"gtk-go-forward\" "
+ "verb=\"GoForward\"/>", _("Forward"));
+ break;
+ case EPHY_TBI_STD_TOOLITEM_UP:
+ xml_item = g_strdup_printf
+ ("<toolitem name=\"Up\" "
+ "label=\"%s\" "
+ "pixtype=\"stock\" pixname=\"gtk-go-up\" "
+ "verb=\"GoUp\"/>", _("Up"));;
+ break;
+ case EPHY_TBI_STD_TOOLITEM_STOP:
+ xml_item = g_strdup_printf
+ ("<toolitem name=\"Stop\" "
+ "label=\"%s\" "
+ "pixtype=\"stock\" pixname=\"gtk-stop\" "
+ "verb=\"GoStop\"/>", _("Stop"));
+ break;
+ case EPHY_TBI_STD_TOOLITEM_RELOAD:
+ xml_item = g_strdup_printf
+ ("<toolitem name=\"Reload\" "
+ "label=\"%s\" "
+ "pixtype=\"stock\" pixname=\"gtk-refresh\" "
+ "verb=\"GoReload\"/>", _("Reload"));
+ break;
+ case EPHY_TBI_STD_TOOLITEM_HOME:
+ xml_item = g_strdup_printf
+ ("<toolitem name=\"Home\" "
+ "label=\"%s\" "
+ "pixtype=\"stock\" pixname=\"gtk-home\" "
+ "priority=\"1\" "
+ "verb=\"GoHome\"/>", _("Home"));;
+ break;
+ case EPHY_TBI_STD_TOOLITEM_GO:
+ xml_item = g_strdup_printf
+ ("<toolitem name=\"Go\" "
+ "label=\"%s\" "
+ "pixtype=\"stock\" pixname=\"gtk-jump-to\" "
+ "verb=\"GoGo\"/>", _("Go"));;
+ break;
+ case EPHY_TBI_STD_TOOLITEM_NEW:
+ xml_item = g_strdup_printf
+ ("<toolitem name=\"New\" "
+ "label=\"%s\" "
+ "pixtype=\"stock\" pixname=\"gtk-new\" "
+ "verb=\"FileNew\"/>", _("New"));;
+ break;
+
+ default:
+ g_assert_not_reached ();
+ xml_item = g_strdup ("");
+ }
+
+ bonobo_ui_component_set (ui, container_path, xml_item, NULL);
+ g_free (xml_item);
+}
+
+static void
+ephy_tbi_std_toolitem_parse_properties_impl (EphyTbItem *it, const gchar *props)
+{
+ EphyTbiStdToolitem *a = EPHY_TBI_STD_TOOLITEM (it);
+
+ /* yes, this is quite hacky, but works */
+
+ /* we have one property */
+ const gchar *item_prop;
+
+ item_prop = strstr (props, "item=");
+ if (item_prop)
+ {
+ item_prop += strlen ("item=");
+ if (!strncmp (item_prop, "back", 4))
+ {
+ ephy_tbi_std_toolitem_set_item (a, EPHY_TBI_STD_TOOLITEM_BACK);
+ }
+ else if (!strncmp (item_prop, "forward", 4))
+ {
+ ephy_tbi_std_toolitem_set_item (a, EPHY_TBI_STD_TOOLITEM_FORWARD);
+ }
+ else if (!strncmp (item_prop, "up", 2))
+ {
+ ephy_tbi_std_toolitem_set_item (a, EPHY_TBI_STD_TOOLITEM_UP);
+ }
+ else if (!strncmp (item_prop, "stop", 4))
+ {
+ ephy_tbi_std_toolitem_set_item (a, EPHY_TBI_STD_TOOLITEM_STOP);
+ }
+ else if (!strncmp (item_prop, "home", 4))
+ {
+ ephy_tbi_std_toolitem_set_item (a, EPHY_TBI_STD_TOOLITEM_HOME);
+ }
+ else if (!strncmp (item_prop, "go", 2))
+ {
+ ephy_tbi_std_toolitem_set_item (a, EPHY_TBI_STD_TOOLITEM_GO);
+ }
+ else if (!strncmp (item_prop, "reload", 6))
+ {
+ ephy_tbi_std_toolitem_set_item (a, EPHY_TBI_STD_TOOLITEM_RELOAD);
+ }
+ else if (!strncmp (item_prop, "new", 3))
+ {
+ ephy_tbi_std_toolitem_set_item (a, EPHY_TBI_STD_TOOLITEM_NEW);
+ }
+
+ }
+}
+
+void
+ephy_tbi_std_toolitem_set_item (EphyTbiStdToolitem *a, EphyTbiStdToolitemItem i)
+{
+ EphyTbiStdToolitemPrivate *p = a->priv;
+
+ g_return_if_fail (i == EPHY_TBI_STD_TOOLITEM_UP
+ || i == EPHY_TBI_STD_TOOLITEM_BACK
+ || i == EPHY_TBI_STD_TOOLITEM_FORWARD
+ || i == EPHY_TBI_STD_TOOLITEM_STOP
+ || i == EPHY_TBI_STD_TOOLITEM_RELOAD
+ || i == EPHY_TBI_STD_TOOLITEM_GO
+ || i == EPHY_TBI_STD_TOOLITEM_HOME
+ || i == EPHY_TBI_STD_TOOLITEM_NEW);
+
+ p->item = i;
+}
+
diff --git a/lib/toolbar/ephy-tbi-std-toolitem.h b/lib/toolbar/ephy-tbi-std-toolitem.h
new file mode 100644
index 000000000..67073041f
--- /dev/null
+++ b/lib/toolbar/ephy-tbi-std-toolitem.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2002 Ricardo Fernández Pascual
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EPHY_TBI_STD_TOOLITEM_H
+#define EPHY_TBI_STD_TOOLITEM_H
+
+#include "ephy-toolbar-item.h"
+
+G_BEGIN_DECLS
+
+/* object forward declarations */
+
+typedef struct _EphyTbiStdToolitem EphyTbiStdToolitem;
+typedef struct _EphyTbiStdToolitemClass EphyTbiStdToolitemClass;
+typedef struct _EphyTbiStdToolitemPrivate EphyTbiStdToolitemPrivate;
+
+/**
+ * TbiStdToolitem object
+ */
+
+#define EPHY_TYPE_TBI_STD_TOOLITEM (ephy_tbi_std_toolitem_get_type())
+#define EPHY_TBI_STD_TOOLITEM(object) (G_TYPE_CHECK_INSTANCE_CAST((object), \
+ EPHY_TYPE_TBI_STD_TOOLITEM,\
+ EphyTbiStdToolitem))
+#define EPHY_TBI_STD_TOOLITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), \
+ EPHY_TYPE_TBI_STD_TOOLITEM,\
+ EphyTbiStdToolitemClass))
+#define EPHY_IS_TBI_STD_TOOLITEM(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), \
+ EPHY_TYPE_TBI_STD_TOOLITEM))
+#define EPHY_IS_TBI_STD_TOOLITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), \
+ EPHY_TYPE_TBI_STD_TOOLITEM))
+#define EPHY_TBI_STD_TOOLITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), \
+ EPHY_TYPE_TBI_STD_TOOLITEM,\
+ EphyTbiStdToolitemClass))
+typedef enum
+{
+ EPHY_TBI_STD_TOOLITEM_BACK,
+ EPHY_TBI_STD_TOOLITEM_FORWARD,
+ EPHY_TBI_STD_TOOLITEM_UP,
+ EPHY_TBI_STD_TOOLITEM_STOP,
+ EPHY_TBI_STD_TOOLITEM_RELOAD,
+ EPHY_TBI_STD_TOOLITEM_HOME,
+ EPHY_TBI_STD_TOOLITEM_GO,
+ EPHY_TBI_STD_TOOLITEM_NEW
+} EphyTbiStdToolitemItem;
+
+
+struct _EphyTbiStdToolitemClass
+{
+ EphyTbItemClass parent_class;
+};
+
+/* Remember: fields are public read-only */
+struct _EphyTbiStdToolitem
+{
+ EphyTbItem parent_object;
+
+ EphyTbiStdToolitemPrivate *priv;
+};
+
+/* this class is abstract */
+
+GType ephy_tbi_std_toolitem_get_type (void);
+EphyTbiStdToolitem * ephy_tbi_std_toolitem_new (void);
+void ephy_tbi_std_toolitem_set_item (EphyTbiStdToolitem *sit,
+ EphyTbiStdToolitemItem it);
+
+G_END_DECLS
+
+#endif
+
diff --git a/lib/toolbar/ephy-tbi-zoom.c b/lib/toolbar/ephy-tbi-zoom.c
new file mode 100644
index 000000000..578799b24
--- /dev/null
+++ b/lib/toolbar/ephy-tbi-zoom.c
@@ -0,0 +1,304 @@
+/*
+ * Copyright (C) 2002 Ricardo Fernández Pascual
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <libgnome/gnome-i18n.h>
+#include <gtk/gtkspinbutton.h>
+#include <gtk/gtklabel.h>
+#include <gtk/gtkstock.h>
+#include <gtk/gtkhbox.h>
+#include <gtk/gtkvbox.h>
+#include <string.h>
+
+#include "ephy-tbi-zoom.h"
+#include "ephy-prefs.h"
+#include "eel-gconf-extensions.h"
+#include "ephy-gobject-misc.h"
+#include "ephy-marshal.h"
+#include "ephy-bonobo-extensions.h"
+
+#define NOT_IMPLEMENTED g_warning ("not implemented: " G_STRLOC);
+//#define DEBUG_MSG(x) g_print x
+#define DEBUG_MSG(x)
+
+/**
+ * Private data
+ */
+struct _EphyTbiZoomPrivate
+{
+ GtkWidget *widget;
+ GtkWidget *label;
+ GtkWidget *hbox;
+ GtkWidget *vbox;
+ guint notification;
+};
+
+enum
+{
+ TOOLBAR_ITEM_STYLE_PROP,
+ TOOLBAR_ITEM_ORIENTATION_PROP,
+ TOOLBAR_ITEM_WANT_LABEL_PROP
+};
+
+/**
+ * Private functions, only availble from this file
+ */
+static void ephy_tbi_zoom_class_init (EphyTbiZoomClass *klass);
+static void ephy_tbi_zoom_init (EphyTbiZoom *tb);
+static void ephy_tbi_zoom_finalize_impl (GObject *o);
+static GtkWidget * ephy_tbi_zoom_get_widget_impl (EphyTbItem *i);
+static GdkPixbuf * ephy_tbi_zoom_get_icon_impl (EphyTbItem *i);
+static gchar * ephy_tbi_zoom_get_name_human_impl (EphyTbItem *i);
+static gchar * ephy_tbi_zoom_to_string_impl (EphyTbItem *i);
+static gboolean ephy_tbi_zoom_is_unique_impl (EphyTbItem *i);
+static EphyTbItem * ephy_tbi_zoom_clone_impl (EphyTbItem *i);
+static void ephy_tbi_zoom_parse_properties_impl (EphyTbItem *i, const gchar *props);
+static void ephy_tbi_zoom_add_to_bonobo_tb_impl (EphyTbItem *i,
+ BonoboUIComponent *ui,
+ const char *container_path,
+ guint index);
+static void ephy_tbi_zoom_setup_label (EphyTbiZoom *it);
+static void ephy_tbi_zoom_notification_cb (GConfClient* client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ gpointer user_data);
+
+
+static gpointer ephy_tb_item_class;
+
+/**
+ * TbiZoom object
+ */
+
+MAKE_GET_TYPE (ephy_tbi_zoom, "EphyTbiZoom", EphyTbiZoom, ephy_tbi_zoom_class_init,
+ ephy_tbi_zoom_init, EPHY_TYPE_TB_ITEM);
+
+static void
+ephy_tbi_zoom_class_init (EphyTbiZoomClass *klass)
+{
+ G_OBJECT_CLASS (klass)->finalize = ephy_tbi_zoom_finalize_impl;
+
+ EPHY_TB_ITEM_CLASS (klass)->get_widget = ephy_tbi_zoom_get_widget_impl;
+ EPHY_TB_ITEM_CLASS (klass)->get_icon = ephy_tbi_zoom_get_icon_impl;
+ EPHY_TB_ITEM_CLASS (klass)->get_name_human = ephy_tbi_zoom_get_name_human_impl;
+ EPHY_TB_ITEM_CLASS (klass)->to_string = ephy_tbi_zoom_to_string_impl;
+ EPHY_TB_ITEM_CLASS (klass)->is_unique = ephy_tbi_zoom_is_unique_impl;
+ EPHY_TB_ITEM_CLASS (klass)->clone = ephy_tbi_zoom_clone_impl;
+ EPHY_TB_ITEM_CLASS (klass)->parse_properties = ephy_tbi_zoom_parse_properties_impl;
+ EPHY_TB_ITEM_CLASS (klass)->add_to_bonobo_tb = ephy_tbi_zoom_add_to_bonobo_tb_impl;
+
+ ephy_tb_item_class = g_type_class_peek_parent (klass);
+}
+
+static void
+ephy_tbi_zoom_init (EphyTbiZoom *tbi)
+{
+ EphyTbiZoomPrivate *p = g_new0 (EphyTbiZoomPrivate, 1);
+ tbi->priv = p;
+
+ p->notification = eel_gconf_notification_add (CONF_DESKTOP_TOOLBAR_STYLE,
+ ephy_tbi_zoom_notification_cb,
+ tbi);
+}
+
+EphyTbiZoom *
+ephy_tbi_zoom_new (void)
+{
+ EphyTbiZoom *ret = g_object_new (EPHY_TYPE_TBI_ZOOM, NULL);
+ return ret;
+}
+
+static void
+ephy_tbi_zoom_finalize_impl (GObject *o)
+{
+ EphyTbiZoom *it = EPHY_TBI_ZOOM (o);
+ EphyTbiZoomPrivate *p = it->priv;
+
+ if (p->widget)
+ {
+ g_object_unref (p->widget);
+ }
+
+ if (p->label)
+ {
+ g_object_unref (p->label);
+ }
+
+ if (p->vbox)
+ {
+ g_object_unref (p->vbox);
+ }
+
+ if (p->hbox)
+ {
+ g_object_unref (p->hbox);
+ }
+
+ if (p->notification)
+ {
+ eel_gconf_notification_remove (p->notification);
+ }
+
+ g_free (p);
+
+ DEBUG_MSG (("EphyTbiZoom finalized\n"));
+
+ G_OBJECT_CLASS (ephy_tb_item_class)->finalize (o);
+}
+
+static GtkWidget *
+ephy_tbi_zoom_get_widget_impl (EphyTbItem *i)
+{
+ EphyTbiZoom *iz = EPHY_TBI_ZOOM (i);
+ EphyTbiZoomPrivate *p = iz->priv;
+
+ if (!p->widget)
+ {
+ p->widget = gtk_spin_button_new_with_range (1, 999, 10);
+ gtk_spin_button_set_value (GTK_SPIN_BUTTON (p->widget), 100);
+ g_object_ref (p->widget);
+ gtk_object_sink (GTK_OBJECT (p->widget));
+ p->label = gtk_label_new (_("Zoom"));
+ g_object_ref (p->label);
+ gtk_object_sink (GTK_OBJECT (p->label));
+ p->vbox = gtk_vbox_new (FALSE, 0);
+ g_object_ref (p->vbox);
+ gtk_object_sink (GTK_OBJECT (p->vbox));
+ p->hbox = gtk_hbox_new (FALSE, 0);
+ g_object_ref (p->hbox);
+ gtk_object_sink (GTK_OBJECT (p->hbox));
+
+ gtk_box_pack_start_defaults (GTK_BOX (p->hbox), p->vbox);
+ gtk_box_pack_start_defaults (GTK_BOX (p->vbox), p->widget);
+ gtk_widget_show (p->vbox);
+ gtk_widget_show (p->hbox);
+ }
+
+ return p->widget;
+}
+
+static GdkPixbuf *
+ephy_tbi_zoom_get_icon_impl (EphyTbItem *i)
+{
+ static GdkPixbuf *pb = NULL;
+ if (!pb)
+ {
+ /* what's the easier way? */
+ GtkWidget *b = gtk_spin_button_new_with_range (0, 1, 0.5);
+ pb = gtk_widget_render_icon (b,
+ GTK_STOCK_ZOOM_IN,
+ GTK_ICON_SIZE_SMALL_TOOLBAR,
+ NULL);
+ gtk_widget_destroy (b);
+ }
+ return g_object_ref (pb);
+}
+
+static gchar *
+ephy_tbi_zoom_get_name_human_impl (EphyTbItem *i)
+{
+ return g_strdup (_("Zoom"));
+}
+
+static gchar *
+ephy_tbi_zoom_to_string_impl (EphyTbItem *i)
+{
+ /* if it had any properties, the string should include them */
+ return g_strdup_printf ("%s=zoom", i->id);
+}
+
+static gboolean
+ephy_tbi_zoom_is_unique_impl (EphyTbItem *i)
+{
+ return TRUE;
+}
+
+static EphyTbItem *
+ephy_tbi_zoom_clone_impl (EphyTbItem *i)
+{
+ EphyTbItem *ret = EPHY_TB_ITEM (ephy_tbi_zoom_new ());
+
+ ephy_tb_item_set_id (ret, i->id);
+
+ /* should copy properties too, if any */
+ /* the zoom value is not copied, not sure if it should... */
+
+ return ret;
+}
+
+static void
+ephy_tbi_zoom_add_to_bonobo_tb_impl (EphyTbItem *i, BonoboUIComponent *ui,
+ const char *container_path, guint index)
+{
+ GtkWidget *w = ephy_tb_item_get_widget (i);
+ EphyTbiZoomPrivate *p = EPHY_TBI_ZOOM (i)->priv;
+ gtk_widget_show (w);
+ ephy_bonobo_add_numbered_control (ui, p->hbox, index, container_path);
+ ephy_tbi_zoom_setup_label (EPHY_TBI_ZOOM (i));
+}
+
+static void
+ephy_tbi_zoom_parse_properties_impl (EphyTbItem *it, const gchar *props)
+{
+ /* we have no properties */
+}
+
+static void
+ephy_tbi_zoom_setup_label (EphyTbiZoom *it)
+{
+ EphyTbiZoomPrivate *p = it->priv;
+ gchar *style = eel_gconf_get_string (CONF_DESKTOP_TOOLBAR_STYLE);
+ ephy_tb_item_get_widget (EPHY_TB_ITEM (it));
+
+ g_object_ref (p->label);
+ if (p->label->parent)
+ {
+ gtk_container_remove (GTK_CONTAINER (p->label->parent), p->label);
+ }
+
+ if (!strcmp (style, "both_horiz") || !strcmp (style, "text"))
+ {
+ gtk_widget_show (p->label);
+ gtk_box_pack_start_defaults (GTK_BOX (p->hbox), p->label);
+ }
+ else if (!strcmp (style, "both"))
+ {
+ gtk_widget_show (p->label);
+ gtk_box_pack_start_defaults (GTK_BOX (p->vbox), p->label);
+ }
+ else
+ {
+ gtk_widget_hide (p->label);
+ }
+
+ g_free (style);
+ g_object_unref (p->label);
+}
+
+static void
+ephy_tbi_zoom_notification_cb (GConfClient* client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ gpointer user_data)
+{
+ ephy_tbi_zoom_setup_label (user_data);
+}
+
diff --git a/lib/toolbar/ephy-tbi-zoom.h b/lib/toolbar/ephy-tbi-zoom.h
new file mode 100644
index 000000000..03f0ed61e
--- /dev/null
+++ b/lib/toolbar/ephy-tbi-zoom.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2002 Ricardo Fernández Pascual
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EPHY_TBI_ZOOM_H
+#define EPHY_TBI_ZOOM_H
+
+#include "ephy-toolbar-item.h"
+
+G_BEGIN_DECLS
+
+/* object forward declarations */
+
+typedef struct _EphyTbiZoom EphyTbiZoom;
+typedef struct _EphyTbiZoomClass EphyTbiZoomClass;
+typedef struct _EphyTbiZoomPrivate EphyTbiZoomPrivate;
+
+/**
+ * TbiZoom object
+ */
+
+#define EPHY_TYPE_TBI_ZOOM (ephy_tbi_zoom_get_type())
+#define EPHY_TBI_ZOOM(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EPHY_TYPE_TBI_ZOOM,\
+ EphyTbiZoom))
+#define EPHY_TBI_ZOOM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EPHY_TYPE_TBI_ZOOM,\
+ EphyTbiZoomClass))
+#define EPHY_IS_TBI_ZOOM(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EPHY_TYPE_TBI_ZOOM))
+#define EPHY_IS_TBI_ZOOM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), EPHY_TYPE_TBI_ZOOM))
+#define EPHY_TBI_ZOOM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EPHY_TYPE_TBI_ZOOM,\
+ EphyTbiZoomClass))
+
+struct _EphyTbiZoomClass
+{
+ EphyTbItemClass parent_class;
+};
+
+/* Remember: fields are public read-only */
+struct _EphyTbiZoom
+{
+ EphyTbItem parent_object;
+
+ EphyTbiZoomPrivate *priv;
+};
+
+/* this class is abstract */
+
+GType ephy_tbi_zoom_get_type (void);
+EphyTbiZoom * ephy_tbi_zoom_new (void);
+
+G_END_DECLS
+
+#endif
diff --git a/lib/toolbar/ephy-toolbar-bonobo-view.c b/lib/toolbar/ephy-toolbar-bonobo-view.c
new file mode 100644
index 000000000..a22356e1e
--- /dev/null
+++ b/lib/toolbar/ephy-toolbar-bonobo-view.c
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2002 Ricardo Fernández Pascual
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <libgnome/gnome-i18n.h>
+
+#include "ephy-gobject-misc.h"
+#include "ephy-marshal.h"
+#include "ephy-toolbar-bonobo-view.h"
+#include "ephy-bonobo-extensions.h"
+
+#define NOT_IMPLEMENTED g_warning ("not implemented: " G_STRLOC);
+//#define DEBUG_MSG(x) g_print x
+#define DEBUG_MSG(x)
+
+/**
+ * Private data
+ */
+struct _EphyTbBonoboViewPrivate
+{
+ EphyToolbar *tb;
+ BonoboUIComponent *ui;
+ gchar *path;
+};
+
+/**
+ * Private functions, only availble from this file
+ */
+static void ephy_tb_bonobo_view_class_init (EphyTbBonoboViewClass *klass);
+static void ephy_tb_bonobo_view_init (EphyTbBonoboView *tb);
+static void ephy_tb_bonobo_view_finalize_impl (GObject *o);
+static void ephy_tb_bonobo_view_rebuild (EphyTbBonoboView *tbv);
+static void ephy_tb_bonobo_view_tb_changed (EphyToolbar *tb, EphyTbBonoboView *tbv);
+
+static gpointer g_object_class;
+
+/**
+ * TbBonoboView object
+ */
+
+MAKE_GET_TYPE (ephy_tb_bonobo_view, "EphyTbBonoboView", EphyTbBonoboView, ephy_tb_bonobo_view_class_init,
+ ephy_tb_bonobo_view_init, G_TYPE_OBJECT);
+
+static void
+ephy_tb_bonobo_view_class_init (EphyTbBonoboViewClass *klass)
+{
+ G_OBJECT_CLASS (klass)->finalize = ephy_tb_bonobo_view_finalize_impl;
+
+ g_object_class = g_type_class_peek_parent (klass);
+}
+
+static void
+ephy_tb_bonobo_view_init (EphyTbBonoboView *tb)
+{
+ EphyTbBonoboViewPrivate *p = g_new0 (EphyTbBonoboViewPrivate, 1);
+ tb->priv = p;
+}
+
+static void
+ephy_tb_bonobo_view_finalize_impl (GObject *o)
+{
+ EphyTbBonoboView *tbv = EPHY_TB_BONOBO_VIEW (o);
+ EphyTbBonoboViewPrivate *p = tbv->priv;
+
+ if (p->tb)
+ {
+ g_signal_handlers_disconnect_matched (p->tb, G_SIGNAL_MATCH_DATA, 0, 0,
+ NULL, NULL, tbv);
+ g_object_unref (p->tb);
+ }
+ if (p->ui)
+ {
+ g_object_unref (p->ui);
+ }
+ if (p->path)
+ {
+ g_free (p->path);
+ }
+
+ g_free (p);
+
+ DEBUG_MSG (("EphyTbBonoboView finalized\n"));
+
+ G_OBJECT_CLASS (g_object_class)->finalize (o);
+}
+
+EphyTbBonoboView *
+ephy_tb_bonobo_view_new (void)
+{
+ EphyTbBonoboView *ret = g_object_new (EPHY_TYPE_TB_BONOBO_VIEW, NULL);
+ return ret;
+}
+
+void
+ephy_tb_bonobo_view_set_toolbar (EphyTbBonoboView *tbv, EphyToolbar *tb)
+{
+ EphyTbBonoboViewPrivate *p = tbv->priv;
+
+ if (p->tb)
+ {
+ g_signal_handlers_disconnect_matched (p->tb, G_SIGNAL_MATCH_DATA, 0, 0,
+ NULL, NULL, tbv);
+ g_object_unref (p->tb);
+ }
+
+ p->tb = g_object_ref (tb);
+ g_signal_connect (p->tb, "changed", G_CALLBACK (ephy_tb_bonobo_view_tb_changed), tbv);
+
+ if (p->ui)
+ {
+ ephy_tb_bonobo_view_rebuild (tbv);
+ }
+}
+
+static void
+ephy_tb_bonobo_view_tb_changed (EphyToolbar *tb, EphyTbBonoboView *tbv)
+{
+ EphyTbBonoboViewPrivate *p = tbv->priv;
+ if (p->ui)
+ {
+ ephy_tb_bonobo_view_rebuild (tbv);
+ }
+}
+
+void
+ephy_tb_bonobo_view_set_path (EphyTbBonoboView *tbv,
+ BonoboUIComponent *ui,
+ const gchar *path)
+{
+ EphyTbBonoboViewPrivate *p = tbv->priv;
+
+ if (p->ui)
+ {
+ g_object_unref (p->ui);
+ }
+
+ if (p->path)
+ {
+ g_free (p->path);
+ }
+
+ p->ui = g_object_ref (ui);
+ p->path = g_strdup (path);
+
+ if (p->tb)
+ {
+ ephy_tb_bonobo_view_rebuild (tbv);
+ }
+}
+
+static void
+ephy_tb_bonobo_view_rebuild (EphyTbBonoboView *tbv)
+{
+ EphyTbBonoboViewPrivate *p = tbv->priv;
+ GSList *items;
+ GSList *li;
+ uint index = 0;
+
+ g_return_if_fail (EPHY_IS_TOOLBAR (p->tb));
+ g_return_if_fail (BONOBO_IS_UI_COMPONENT (p->ui));
+ g_return_if_fail (p->path);
+
+ DEBUG_MSG (("Rebuilding EphyTbBonoboView\n"));
+
+ ephy_bonobo_clear_path (p->ui, p->path);
+
+ items = (GSList *) ephy_toolbar_get_item_list (p->tb);
+ for (li = items; li; li = li->next)
+ {
+ ephy_tb_item_add_to_bonobo_tb (li->data, p->ui, p->path, index++);
+ }
+
+ DEBUG_MSG (("Rebuilt EphyTbBonoboView\n"));
+}
+
diff --git a/lib/toolbar/ephy-toolbar-bonobo-view.h b/lib/toolbar/ephy-toolbar-bonobo-view.h
new file mode 100644
index 000000000..a914fc201
--- /dev/null
+++ b/lib/toolbar/ephy-toolbar-bonobo-view.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2002 Ricardo Fernández Pascual
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EPHY_TOOLBAR_BONOBO_VIEW_H
+#define EPHY_TOOLBAR_BONOBO_VIEW_H
+
+#include <glib-object.h>
+
+#include <bonobo/bonobo-ui-component.h>
+
+#include "ephy-toolbar.h"
+
+G_BEGIN_DECLS
+
+/* object forward declarations */
+
+typedef struct _EphyTbBonoboView EphyTbBonoboView;
+typedef struct _EphyTbBonoboViewClass EphyTbBonoboViewClass;
+typedef struct _EphyTbBonoboViewPrivate EphyTbBonoboViewPrivate;
+
+/**
+ * TbBonoboView object
+ */
+
+#define EPHY_TYPE_TB_BONOBO_VIEW (ephy_tb_bonobo_view_get_type())
+#define EPHY_TB_BONOBO_VIEW(object) (G_TYPE_CHECK_INSTANCE_CAST((object), \
+ EPHY_TYPE_TB_BONOBO_VIEW,\
+ EphyTbBonoboView))
+#define EPHY_TB_BONOBO_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EPHY_TYPE_TB_BONOBO_VIEW,\
+ EphyTbBonoboViewClass))
+#define EPHY_IS_TB_BONOBO_VIEW(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), \
+ EPHY_TYPE_TB_BONOBO_VIEW))
+#define EPHY_IS_TB_BONOBO_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), EPHY_TYPE_TB_BONOBO_VIEW))
+#define EPHY_TB_BONOBO_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EPHY_TYPE_TB_BONOBO_VIEW,\
+ EphyTbBonoboViewClass))
+
+struct _EphyTbBonoboViewClass
+{
+ GObjectClass parent_class;
+};
+
+/* Remember: fields are public read-only */
+struct _EphyTbBonoboView
+{
+ GObject parent_object;
+
+ EphyTbBonoboViewPrivate *priv;
+};
+
+/* this class is abstract */
+
+GType ephy_tb_bonobo_view_get_type (void);
+EphyTbBonoboView * ephy_tb_bonobo_view_new (void);
+void ephy_tb_bonobo_view_set_toolbar (EphyTbBonoboView *tbv, EphyToolbar *tb);
+void ephy_tb_bonobo_view_set_path (EphyTbBonoboView *tbv,
+ BonoboUIComponent *ui,
+ const gchar *path);
+
+#endif
+
diff --git a/lib/toolbar/ephy-toolbar-editor.c b/lib/toolbar/ephy-toolbar-editor.c
new file mode 100644
index 000000000..e44767bad
--- /dev/null
+++ b/lib/toolbar/ephy-toolbar-editor.c
@@ -0,0 +1,634 @@
+/*
+ * Copyright (C) 2002 Ricardo Fernández Pascual
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <libgnome/gnome-i18n.h>
+
+#include "ephy-gobject-misc.h"
+#include "ephy-marshal.h"
+#include "ephy-toolbar-editor.h"
+#include "ephy-toolbar-tree-model.h"
+#include "ephy-glade.h"
+
+#define NOT_IMPLEMENTED g_warning ("not implemented: " G_STRLOC);
+//#define DEBUG_MSG(x) g_print x
+#define DEBUG_MSG(x)
+
+/**
+ * Private data
+ */
+struct _EphyTbEditorPrivate
+{
+ EphyToolbar *tb;
+ EphyToolbar *available;
+
+ gchar *tb_undo_string;
+ gchar *available_undo_string;
+
+ gboolean in_toolbar_changed;
+
+ GtkWidget *window;
+ GtkWidget *available_view;
+ GtkWidget *current_view;
+ GtkWidget *close_button;
+ GtkWidget *undo_button;
+ GtkWidget *revert_button;
+ GtkWidget *up_button;
+ GtkWidget *down_button;
+ GtkWidget *left_button;
+ GtkWidget *right_button;
+};
+
+/**
+ * Private functions, only available from this file
+ */
+static void ephy_tb_editor_class_init (EphyTbEditorClass *klass);
+static void ephy_tb_editor_init (EphyTbEditor *tbe);
+static void ephy_tb_editor_finalize_impl (GObject *o);
+static void ephy_tb_editor_init_widgets (EphyTbEditor *tbe);
+static void ephy_tb_editor_set_treeview_toolbar (EphyTbEditor *tbe,
+ GtkTreeView *tv, EphyToolbar *tb);
+static void ephy_tb_editor_setup_treeview (EphyTbEditor *tbe, GtkTreeView *tv);
+static EphyTbItem * ephy_tb_editor_get_selected (EphyTbEditor *tbe, GtkTreeView *tv);
+static gint ephy_tb_editor_get_selected_index (EphyTbEditor *tbe, GtkTreeView *tv);
+static void ephy_tb_editor_select_index (EphyTbEditor *tbe, GtkTreeView *tv,
+ gint index);
+static void ephy_tb_editor_remove_used_items (EphyTbEditor *tbe);
+
+static void ephy_tb_editor_undo_clicked_cb (GtkWidget *b, EphyTbEditor *tbe);
+static void ephy_tb_editor_close_clicked_cb (GtkWidget *b, EphyTbEditor *tbe);
+static void ephy_tb_editor_up_clicked_cb (GtkWidget *b, EphyTbEditor *tbe);
+static void ephy_tb_editor_down_clicked_cb (GtkWidget *b, EphyTbEditor *tbe);
+static void ephy_tb_editor_left_clicked_cb (GtkWidget *b, EphyTbEditor *tbe);
+static void ephy_tb_editor_right_clicked_cb (GtkWidget *b, EphyTbEditor *tbe);
+static void ephy_tb_editor_toolbar_changed_cb (EphyToolbar *tb, EphyTbEditor *tbe);
+static gboolean ephy_tb_editor_treeview_button_press_event_cb (GtkWidget *widget,
+ GdkEventButton *event,
+ EphyTbEditor *tbe);
+
+
+static gpointer g_object_class;
+
+/* treeview dnd */
+enum
+{
+ TARGET_GTK_TREE_MODEL_ROW
+};
+static GtkTargetEntry tree_view_row_targets[] = {
+ { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_APP, TARGET_GTK_TREE_MODEL_ROW }
+};
+
+/**
+ * TbEditor object
+ */
+
+MAKE_GET_TYPE (ephy_tb_editor, "EphyTbEditor", EphyTbEditor, ephy_tb_editor_class_init,
+ ephy_tb_editor_init, G_TYPE_OBJECT);
+
+static void
+ephy_tb_editor_class_init (EphyTbEditorClass *klass)
+{
+ G_OBJECT_CLASS (klass)->finalize = ephy_tb_editor_finalize_impl;
+
+ g_object_class = g_type_class_peek_parent (klass);
+}
+
+static void
+ephy_tb_editor_init (EphyTbEditor *tb)
+{
+ EphyTbEditorPrivate *p = g_new0 (EphyTbEditorPrivate, 1);
+ tb->priv = p;
+
+ ephy_tb_editor_init_widgets (tb);
+}
+
+static void
+update_arrows_sensitivity (EphyTbEditor *tbe)
+{
+ GtkTreeSelection *selection;
+ gboolean current_sel;
+ gboolean avail_sel;
+ gboolean first = FALSE;
+ gboolean last = FALSE;
+ GtkTreeModel *tm;
+ GtkTreeIter iter;
+ GtkTreePath *path;
+
+ selection = gtk_tree_view_get_selection
+ (GTK_TREE_VIEW (tbe->priv->current_view));
+ current_sel = gtk_tree_selection_get_selected (selection, &tm, &iter);
+ if (current_sel)
+ {
+ path = gtk_tree_model_get_path (tm, &iter);
+ first = !gtk_tree_path_prev (path);
+ last = !gtk_tree_model_iter_next (tm, &iter);
+ }
+
+ selection = gtk_tree_view_get_selection
+ (GTK_TREE_VIEW (tbe->priv->available_view));
+ avail_sel = gtk_tree_selection_get_selected (selection, &tm, &iter);
+
+ gtk_widget_set_sensitive (tbe->priv->right_button,
+ avail_sel);
+ gtk_widget_set_sensitive (tbe->priv->left_button,
+ current_sel);
+ gtk_widget_set_sensitive (tbe->priv->up_button,
+ current_sel && !first);
+ gtk_widget_set_sensitive (tbe->priv->down_button,
+ current_sel && !last);
+}
+
+static void
+ephy_tb_editor_treeview_selection_changed_cb (GtkTreeSelection *selection,
+ EphyTbEditor *tbe)
+{
+ update_arrows_sensitivity (tbe);
+}
+
+static void
+ephy_tb_editor_init_widgets (EphyTbEditor *tbe)
+{
+ EphyTbEditorPrivate *p = tbe->priv;
+
+ GladeXML *gxml = ephy_glade_widget_new ("toolbar-editor.glade", "toolbar-editor-dialog",
+ NULL, tbe);
+ p->window = glade_xml_get_widget (gxml, "toolbar-editor-dialog");
+ p->available_view = glade_xml_get_widget (gxml, "toolbar-editor-available-view");
+ p->current_view = glade_xml_get_widget (gxml, "toolbar-editor-current-view");
+ p->close_button = glade_xml_get_widget (gxml, "toolbar-editor-close-button");
+ p->undo_button = glade_xml_get_widget (gxml, "toolbar-editor-undo-button");
+ p->revert_button = glade_xml_get_widget (gxml, "toolbar-editor-revert-button");
+ p->up_button = glade_xml_get_widget (gxml, "toolbar-editor-up-button");
+ p->down_button = glade_xml_get_widget (gxml, "toolbar-editor-down-button");
+ p->left_button = glade_xml_get_widget (gxml, "toolbar-editor-left-button");
+ p->right_button = glade_xml_get_widget (gxml, "toolbar-editor-right-button");
+ g_object_unref (gxml);
+
+ g_signal_connect_swapped (p->window, "delete_event", G_CALLBACK (g_object_unref), tbe);
+ g_signal_connect (p->undo_button, "clicked", G_CALLBACK (ephy_tb_editor_undo_clicked_cb), tbe);
+ g_signal_connect (p->close_button, "clicked", G_CALLBACK (ephy_tb_editor_close_clicked_cb), tbe);
+ g_signal_connect (p->up_button, "clicked", G_CALLBACK (ephy_tb_editor_up_clicked_cb), tbe);
+ g_signal_connect (p->down_button, "clicked", G_CALLBACK (ephy_tb_editor_down_clicked_cb), tbe);
+ g_signal_connect (p->left_button, "clicked", G_CALLBACK (ephy_tb_editor_left_clicked_cb), tbe);
+ g_signal_connect (p->right_button, "clicked", G_CALLBACK (ephy_tb_editor_right_clicked_cb), tbe);
+
+ ephy_tb_editor_setup_treeview (tbe, GTK_TREE_VIEW (p->current_view));
+ ephy_tb_editor_setup_treeview (tbe, GTK_TREE_VIEW (p->available_view));
+}
+
+static void
+ephy_tb_editor_undo_clicked_cb (GtkWidget *b, EphyTbEditor *tbe)
+{
+ EphyTbEditorPrivate *p = tbe->priv;
+ if (p->available_undo_string && p->available)
+ {
+ ephy_toolbar_parse (p->available, p->available_undo_string);
+ }
+
+ if (p->tb_undo_string && p->tb)
+ {
+ ephy_toolbar_parse (p->tb, p->tb_undo_string);
+ }
+}
+
+static void
+ephy_tb_editor_close_clicked_cb (GtkWidget *b, EphyTbEditor *tbe)
+{
+ gtk_widget_hide (tbe->priv->window);
+ g_object_unref (tbe);
+}
+
+static void
+ephy_tb_editor_up_clicked_cb (GtkWidget *b, EphyTbEditor *tbe)
+{
+ EphyTbEditorPrivate *p = tbe->priv;
+ EphyTbItem *item = ephy_tb_editor_get_selected (tbe, GTK_TREE_VIEW (p->current_view));
+ gint index = ephy_tb_editor_get_selected_index (tbe, GTK_TREE_VIEW (p->current_view));
+ if (item && index > 0)
+ {
+ g_object_ref (item);
+ ephy_toolbar_remove_item (p->tb, item);
+ ephy_toolbar_add_item (p->tb, item, index - 1);
+ ephy_tb_editor_select_index (tbe, GTK_TREE_VIEW (p->current_view), index - 1);
+ g_object_unref (item);
+ }
+}
+
+static void
+ephy_tb_editor_down_clicked_cb (GtkWidget *b, EphyTbEditor *tbe)
+{
+ EphyTbEditorPrivate *p = tbe->priv;
+ EphyTbItem *item = ephy_tb_editor_get_selected (tbe, GTK_TREE_VIEW (p->current_view));
+ gint index = ephy_tb_editor_get_selected_index (tbe, GTK_TREE_VIEW (p->current_view));
+ if (item)
+ {
+ g_object_ref (item);
+ ephy_toolbar_remove_item (p->tb, item);
+ ephy_toolbar_add_item (p->tb, item, index + 1);
+ ephy_tb_editor_select_index (tbe, GTK_TREE_VIEW (p->current_view), index + 1);
+ g_object_unref (item);
+ }
+}
+
+static void
+ephy_tb_editor_left_clicked_cb (GtkWidget *b, EphyTbEditor *tbe)
+{
+ EphyTbEditorPrivate *p = tbe->priv;
+ EphyTbItem *item = ephy_tb_editor_get_selected (tbe, GTK_TREE_VIEW (p->current_view));
+ /* probably is better not allowing reordering the available_view */
+ gint index = ephy_tb_editor_get_selected_index (tbe, GTK_TREE_VIEW (p->available_view));
+ if (item)
+ {
+ g_object_ref (item);
+ ephy_toolbar_remove_item (p->tb, item);
+ if (ephy_tb_item_is_unique (item))
+ {
+ ephy_toolbar_add_item (p->available, item, index);
+ }
+ g_object_unref (item);
+ }
+}
+
+static void
+ephy_tb_editor_right_clicked_cb (GtkWidget *b, EphyTbEditor *tbe)
+{
+ EphyTbEditorPrivate *p = tbe->priv;
+ EphyTbItem *item = ephy_tb_editor_get_selected (tbe, GTK_TREE_VIEW (p->available_view));
+ gint index = ephy_tb_editor_get_selected_index (tbe, GTK_TREE_VIEW (p->current_view));
+ if (item)
+ {
+ if (ephy_tb_item_is_unique (item))
+ {
+ g_object_ref (item);
+ ephy_toolbar_remove_item (p->available, item);
+ }
+ else
+ {
+ item = ephy_tb_item_clone (item);
+ }
+ ephy_toolbar_add_item (p->tb, item, index);
+ ephy_tb_editor_select_index (tbe, GTK_TREE_VIEW (p->current_view), index);
+ g_object_unref (item);
+ }
+}
+
+static EphyTbItem *
+ephy_tb_editor_get_selected (EphyTbEditor *tbe, GtkTreeView *tv)
+{
+ GtkTreeSelection *sel = gtk_tree_view_get_selection (tv);
+ GtkTreeModel *tm;
+ GtkTreeIter iter;
+ if (gtk_tree_selection_get_selected (sel, &tm, &iter))
+ {
+ EphyTbItem *ret;
+ g_return_val_if_fail (EPHY_IS_TB_TREE_MODEL (tm), NULL);
+ ret = ephy_tb_tree_model_item_from_iter (EPHY_TB_TREE_MODEL (tm), &iter);
+ return ret;
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+static gint
+ephy_tb_editor_get_selected_index (EphyTbEditor *tbe, GtkTreeView *tv)
+{
+ GtkTreeSelection *sel = gtk_tree_view_get_selection (tv);
+ GtkTreeModel *tm;
+ GtkTreeIter iter;
+ if (gtk_tree_selection_get_selected (sel, &tm, &iter))
+ {
+ GtkTreePath *p = gtk_tree_model_get_path (tm, &iter);
+ if (p)
+ {
+ gint ret = gtk_tree_path_get_depth (p) > 0 ? gtk_tree_path_get_indices (p)[0] : -1;
+ gtk_tree_path_free (p);
+ return ret;
+ }
+ else
+ {
+ return -1;
+ }
+ }
+ else
+ {
+ return -1;
+ }
+}
+
+static void
+ephy_tb_editor_select_index (EphyTbEditor *tbe, GtkTreeView *tv, gint index)
+{
+ GtkTreeSelection *sel = gtk_tree_view_get_selection (tv);
+ GtkTreePath *p = gtk_tree_path_new ();
+ GtkTreeModel *tm = gtk_tree_view_get_model (tv);
+ gint max = gtk_tree_model_iter_n_children (tm, NULL);
+
+ if (index < 0 || index >= max)
+ {
+ index = max - 1;
+ }
+
+ gtk_tree_path_append_index (p, index);
+ gtk_tree_selection_select_path (sel, p);
+ gtk_tree_path_free (p);
+}
+
+static void
+ephy_tb_editor_finalize_impl (GObject *o)
+{
+ EphyTbEditor *tbe = EPHY_TB_EDITOR (o);
+ EphyTbEditorPrivate *p = tbe->priv;
+
+ if (p->tb)
+ {
+ g_signal_handlers_disconnect_matched (p->tb, G_SIGNAL_MATCH_DATA, 0, 0,
+ NULL, NULL, tbe);
+
+ g_object_unref (p->tb);
+ }
+ if (p->available)
+ {
+ g_signal_handlers_disconnect_matched (p->available, G_SIGNAL_MATCH_DATA, 0, 0,
+ NULL, NULL, tbe);
+ g_object_unref (p->available);
+ }
+
+ if (p->window)
+ {
+ gtk_widget_destroy (p->window);
+ }
+
+ g_free (p->tb_undo_string);
+ g_free (p->available_undo_string);
+
+ g_free (p);
+
+ DEBUG_MSG (("EphyTbEditor finalized\n"));
+
+ G_OBJECT_CLASS (g_object_class)->finalize (o);
+}
+
+EphyTbEditor *
+ephy_tb_editor_new (void)
+{
+ EphyTbEditor *ret = g_object_new (EPHY_TYPE_TB_EDITOR, NULL);
+ return ret;
+}
+
+void
+ephy_tb_editor_set_toolbar (EphyTbEditor *tbe, EphyToolbar *tb)
+{
+ EphyTbEditorPrivate *p = tbe->priv;
+
+ if (p->tb)
+ {
+ g_signal_handlers_disconnect_matched (p->tb, G_SIGNAL_MATCH_DATA, 0, 0,
+ NULL, NULL, tbe);
+ g_object_unref (p->tb);
+ }
+ p->tb = g_object_ref (tb);
+
+ g_free (p->tb_undo_string);
+ p->tb_undo_string = ephy_toolbar_to_string (p->tb);
+
+ if (p->available)
+ {
+ ephy_tb_editor_remove_used_items (tbe);
+ }
+
+ g_signal_connect (p->tb, "changed", G_CALLBACK (ephy_tb_editor_toolbar_changed_cb), tbe);
+
+ ephy_tb_editor_set_treeview_toolbar (tbe, GTK_TREE_VIEW (p->current_view), p->tb);
+
+ gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW (p->current_view),
+ GDK_BUTTON1_MASK,
+ tree_view_row_targets,
+ G_N_ELEMENTS (tree_view_row_targets),
+ GDK_ACTION_MOVE);
+ gtk_tree_view_enable_model_drag_dest (GTK_TREE_VIEW (p->current_view),
+ tree_view_row_targets,
+ G_N_ELEMENTS (tree_view_row_targets),
+ GDK_ACTION_COPY);
+}
+
+void
+ephy_tb_editor_set_available (EphyTbEditor *tbe, EphyToolbar *tb)
+{
+ EphyTbEditorPrivate *p = tbe->priv;
+
+ if (p->available)
+ {
+ g_signal_handlers_disconnect_matched (p->available, G_SIGNAL_MATCH_DATA, 0, 0,
+ NULL, NULL, tbe);
+ g_object_unref (p->available);
+ }
+ p->available = g_object_ref (tb);
+
+ g_free (p->available_undo_string);
+ p->available_undo_string = ephy_toolbar_to_string (p->available);
+
+ ephy_toolbar_set_fixed_order (p->available, TRUE);
+
+ if (p->tb)
+ {
+ ephy_tb_editor_remove_used_items (tbe);
+ }
+
+ ephy_tb_editor_set_treeview_toolbar (tbe, GTK_TREE_VIEW (p->available_view), p->available);
+
+ gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW (p->available_view),
+ GDK_BUTTON1_MASK,
+ tree_view_row_targets,
+ G_N_ELEMENTS (tree_view_row_targets),
+ GDK_ACTION_COPY);
+ gtk_tree_view_enable_model_drag_dest (GTK_TREE_VIEW (p->available_view),
+ tree_view_row_targets,
+ G_N_ELEMENTS (tree_view_row_targets),
+ GDK_ACTION_MOVE);
+}
+
+void
+ephy_tb_editor_set_parent (EphyTbEditor *tbe, GtkWidget *parent)
+{
+ gtk_window_set_transient_for (GTK_WINDOW (tbe->priv->window),
+ GTK_WINDOW (parent));
+}
+
+void
+ephy_tb_editor_show (EphyTbEditor *tbe)
+{
+ gtk_window_present (GTK_WINDOW (tbe->priv->window));
+}
+
+static void
+ephy_tb_editor_set_treeview_toolbar (EphyTbEditor *tbe, GtkTreeView *tv, EphyToolbar *tb)
+{
+ EphyTbTreeModel *tm = ephy_tb_tree_model_new ();
+ ephy_tb_tree_model_set_toolbar (tm, tb);
+ gtk_tree_view_set_model (tv, GTK_TREE_MODEL (tm));
+ g_object_unref (tm);
+}
+
+static void
+ephy_tb_editor_setup_treeview (EphyTbEditor *tbe, GtkTreeView *tv)
+{
+ GtkCellRenderer *renderer;
+ GtkTreeViewColumn *column;
+ GtkTreeSelection *selection;
+
+ selection = gtk_tree_view_get_selection (tv);
+ column = gtk_tree_view_column_new ();
+ renderer = gtk_cell_renderer_pixbuf_new ();
+
+ gtk_tree_view_column_pack_start (column, renderer, FALSE);
+ gtk_tree_view_column_set_attributes (column, renderer,
+ "pixbuf", EPHY_TB_TREE_MODEL_COL_ICON,
+ NULL);
+
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_tree_view_column_pack_start (column, renderer, TRUE);
+ gtk_tree_view_column_set_attributes (column, renderer,
+ "text", EPHY_TB_TREE_MODEL_COL_NAME,
+ NULL);
+ gtk_tree_view_column_set_title (column, "Name");
+ gtk_tree_view_column_set_resizable (column, TRUE);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (tv), column);
+
+ g_signal_connect (tv, "button-press-event",
+ G_CALLBACK (ephy_tb_editor_treeview_button_press_event_cb), tbe);
+ g_signal_connect (selection, "changed",
+ G_CALLBACK (ephy_tb_editor_treeview_selection_changed_cb), tbe);
+}
+
+EphyToolbar *
+ephy_tb_editor_get_toolbar (EphyTbEditor *tbe)
+{
+ EphyTbEditorPrivate *p;
+
+ g_return_val_if_fail (EPHY_IS_TB_EDITOR (tbe), NULL);
+
+ p = tbe->priv;
+
+ return p->tb;
+}
+
+EphyToolbar *
+ephy_tb_editor_get_available (EphyTbEditor *tbe)
+{
+ EphyTbEditorPrivate *p;
+
+ g_return_val_if_fail (EPHY_IS_TB_EDITOR (tbe), NULL);
+
+ p = tbe->priv;
+
+ return p->available;
+}
+
+
+static void
+ephy_tb_editor_remove_used_items (EphyTbEditor *tbe)
+{
+ EphyTbEditorPrivate *p = tbe->priv;
+ const GSList *current_items;
+ const GSList *li;
+
+ g_return_if_fail (EPHY_IS_TOOLBAR (p->tb));
+ g_return_if_fail (EPHY_IS_TOOLBAR (p->available));
+
+ current_items = ephy_toolbar_get_item_list (p->tb);
+ for (li = current_items; li; li = li->next)
+ {
+ EphyTbItem *i = li->data;
+ if (ephy_tb_item_is_unique (i))
+ {
+ EphyTbItem *j = ephy_toolbar_get_item_by_id (p->available, i->id);
+ if (j)
+ {
+ ephy_toolbar_remove_item (p->available, j);
+ }
+ }
+ }
+}
+
+static void
+ephy_tb_editor_toolbar_changed_cb (EphyToolbar *tb, EphyTbEditor *tbe)
+{
+ EphyTbEditorPrivate *p = tbe->priv;
+
+ if (p->in_toolbar_changed)
+ {
+ return;
+ }
+
+ if (p->tb && p->available)
+ {
+ p->in_toolbar_changed = TRUE;
+ ephy_tb_editor_remove_used_items (tbe);
+ p->in_toolbar_changed = FALSE;
+ }
+}
+
+static gboolean
+ephy_tb_editor_treeview_button_press_event_cb (GtkWidget *widget,
+ GdkEventButton *event,
+ EphyTbEditor *tbe)
+{
+ EphyTbEditorPrivate *p = tbe->priv;
+
+ if (event->window != gtk_tree_view_get_bin_window (GTK_TREE_VIEW (widget)))
+ {
+ return FALSE;
+ }
+
+ if (event->type == GDK_2BUTTON_PRESS)
+ {
+ if (widget == p->current_view)
+ {
+ ephy_tb_editor_left_clicked_cb (NULL, tbe);
+ }
+ else if (widget == p->available_view)
+ {
+ ephy_tb_editor_right_clicked_cb (NULL, tbe);
+ }
+ else
+ {
+ g_assert_not_reached ();
+ }
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+GtkButton *
+ephy_tb_editor_get_revert_button (EphyTbEditor *tbe)
+{
+ EphyTbEditorPrivate *p;
+ g_return_val_if_fail (EPHY_IS_TB_EDITOR (tbe), NULL);
+ p = tbe->priv;
+ g_return_val_if_fail (GTK_IS_BUTTON (p->revert_button), NULL);
+
+ return GTK_BUTTON (p->revert_button);
+
+}
+
diff --git a/lib/toolbar/ephy-toolbar-editor.h b/lib/toolbar/ephy-toolbar-editor.h
new file mode 100644
index 000000000..97ee10e7a
--- /dev/null
+++ b/lib/toolbar/ephy-toolbar-editor.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2002 Ricardo Fernández Pascual
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EPHY_TOOLBAR_EDITOR_H
+#define EPHY_TOOLBAR_EDITOR_H
+
+#include <glib-object.h>
+#include <gtk/gtkbutton.h>
+
+#include "ephy-toolbar.h"
+
+G_BEGIN_DECLS
+
+/* object forward declarations */
+
+typedef struct _EphyTbEditor EphyTbEditor;
+typedef struct _EphyTbEditorClass EphyTbEditorClass;
+typedef struct _EphyTbEditorPrivate EphyTbEditorPrivate;
+
+/**
+ * TbEditor object
+ */
+
+#define EPHY_TYPE_TB_EDITOR (ephy_tb_editor_get_type())
+#define EPHY_TB_EDITOR(object) (G_TYPE_CHECK_INSTANCE_CAST((object), \
+ EPHY_TYPE_TB_EDITOR,\
+ EphyTbEditor))
+#define EPHY_TB_EDITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EPHY_TYPE_TB_EDITOR,\
+ EphyTbEditorClass))
+#define EPHY_IS_TB_EDITOR(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), \
+ EPHY_TYPE_TB_EDITOR))
+#define EPHY_IS_TB_EDITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), EPHY_TYPE_TB_EDITOR))
+#define EPHY_TB_EDITOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EPHY_TYPE_TB_EDITOR,\
+ EphyTbEditorClass))
+
+struct _EphyTbEditorClass
+{
+ GObjectClass parent_class;
+};
+
+/* Remember: fields are public read-only */
+struct _EphyTbEditor
+{
+ GObject parent_object;
+
+ EphyTbEditorPrivate *priv;
+};
+
+/* this class is abstract */
+
+GType ephy_tb_editor_get_type (void);
+EphyTbEditor * ephy_tb_editor_new (void);
+void ephy_tb_editor_set_toolbar (EphyTbEditor *tbe, EphyToolbar *tb);
+EphyToolbar * ephy_tb_editor_get_toolbar (EphyTbEditor *tbe);
+void ephy_tb_editor_set_available (EphyTbEditor *tbe, EphyToolbar *tb);
+EphyToolbar * ephy_tb_editor_get_available (EphyTbEditor *tbe);
+void ephy_tb_editor_set_parent (EphyTbEditor *tbe, GtkWidget *parent);
+void ephy_tb_editor_show (EphyTbEditor *tbe);
+/* the revert button is hidden initially */
+GtkButton * ephy_tb_editor_get_revert_button (EphyTbEditor *tbe);
+
+G_END_DECLS
+
+#endif
+
diff --git a/lib/toolbar/ephy-toolbar-item-factory.c b/lib/toolbar/ephy-toolbar-item-factory.c
new file mode 100644
index 000000000..1637100ae
--- /dev/null
+++ b/lib/toolbar/ephy-toolbar-item-factory.c
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2002 Ricardo Fernández Pascual
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "ephy-toolbar-item-factory.h"
+#include <string.h>
+
+#include "ephy-tbi-zoom.h"
+#include "ephy-tbi-separator.h"
+#include "ephy-tbi-favicon.h"
+#include "ephy-tbi-spinner.h"
+#include "ephy-tbi-location.h"
+#include "ephy-tbi-navigation-history.h"
+#include "ephy-tbi-std-toolitem.h"
+
+#define NOT_IMPLEMENTED g_warning ("not implemented: " G_STRLOC);
+//#define DEBUG_MSG(x) g_print x
+#define DEBUG_MSG(x)
+
+typedef EphyTbItem *(EphyTbItemConstructor) (void);
+
+typedef struct
+{
+ const char *type_name;
+ EphyTbItemConstructor *constructor;
+} EphyTbItemTypeInfo;
+
+static EphyTbItemTypeInfo ephy_tb_item_known_types[] =
+{
+ { "std_toolitem", (EphyTbItemConstructor *) ephy_tbi_std_toolitem_new },
+ { "navigation_history", (EphyTbItemConstructor *) ephy_tbi_navigation_history_new },
+ { "zoom", (EphyTbItemConstructor *) ephy_tbi_zoom_new },
+ { "location", (EphyTbItemConstructor *) ephy_tbi_location_new },
+ { "spinner", (EphyTbItemConstructor *) ephy_tbi_spinner_new },
+ { "favicon", (EphyTbItemConstructor *) ephy_tbi_favicon_new },
+ { "separator", (EphyTbItemConstructor *) ephy_tbi_separator_new },
+ { NULL, NULL }
+};
+
+EphyTbItem *
+ephy_toolbar_item_create_from_string (const gchar *str)
+{
+ EphyTbItem *ret = NULL;
+ gchar *type;
+ gchar *props;
+ gchar *id;
+ const gchar *rest;
+ const gchar *lpar;
+ const gchar *rpar;
+ const gchar *eq;
+ int i;
+
+ rest = str;
+
+ eq = strchr (rest, '=');
+ if (eq)
+ {
+ id = g_strndup (rest, eq - rest);
+ rest = eq + 1;
+ }
+ else
+ {
+ id = NULL;
+ }
+
+ lpar = strchr (rest, '(');
+ if (lpar)
+ {
+ type = g_strndup (rest, lpar - rest);
+ rest = lpar + 1;
+
+ rpar = strchr (rest, ')');
+ if (rpar)
+ {
+ props = g_strndup (rest, rpar - rest);
+ rest = rpar + 1;
+ }
+ else
+ {
+ props = g_strdup (rest);
+ }
+ }
+ else
+ {
+ type = g_strdup (rest);
+ props = NULL;
+ }
+
+ DEBUG_MSG (("ephytoolbar_item_create_from_string id=%s type=%s props=%s\n", id, type, props));
+
+ for (i = 0; ephy_tb_item_known_types[i].type_name; ++i)
+ {
+ if (!strcmp (type, ephy_tb_item_known_types[i].type_name))
+ {
+ ret = ephy_tb_item_known_types[i].constructor ();
+ if (id)
+ {
+ ephy_tb_item_set_id (ret, id);
+ }
+ if (props)
+ {
+ ephy_tb_item_parse_properties (ret, props);
+ }
+ }
+ }
+
+ if (!ret)
+ {
+ g_warning ("Error creating toolbar item of type %s", type);
+ }
+
+ if (id)
+ {
+ g_free (id);
+ }
+ if (type)
+ {
+ g_free (type);
+ }
+ if (props)
+ {
+ g_free (props);
+ }
+
+ return ret;
+}
+
+GSList *
+ephy_toolbar_list_item_types (void)
+{
+ int i;
+ GSList *ret = NULL;
+ for (i = 0; ephy_tb_item_known_types[i].type_name; ++i)
+ {
+ ret = g_slist_prepend (ret,
+ (gchar *) ephy_tb_item_known_types[i].type_name);
+ }
+ return ret;
+}
+
diff --git a/lib/toolbar/ephy-toolbar-item-factory.h b/lib/toolbar/ephy-toolbar-item-factory.h
new file mode 100644
index 000000000..e86179399
--- /dev/null
+++ b/lib/toolbar/ephy-toolbar-item-factory.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2002 Ricardo Fernández Pascual
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EPHY_TOOLBAR_ITEM_FACTORY_H
+#define EPHY_TOOLBAR_ITEM_FACTORY_H
+
+#include "ephy-toolbar-item.h"
+
+G_BEGIN_DECLS
+
+EphyTbItem * ephy_toolbar_item_create_from_string (const gchar *str);
+GSList * ephy_toolbar_list_item_types (void);
+
+G_END_DECLS
+
+#endif
diff --git a/lib/toolbar/ephy-toolbar-item.c b/lib/toolbar/ephy-toolbar-item.c
new file mode 100644
index 000000000..f9c452f02
--- /dev/null
+++ b/lib/toolbar/ephy-toolbar-item.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2002 Ricardo Fernández Pascual
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <libgnome/gnome-i18n.h>
+
+#include "ephy-gobject-misc.h"
+#include "ephy-marshal.h"
+#include "ephy-toolbar-item.h"
+
+#define NOT_IMPLEMENTED g_warning ("not implemented: " G_STRLOC);
+//#define DEBUG_MSG(x) g_print x
+#define DEBUG_MSG(x)
+
+/**
+ * Private data
+ */
+struct _EphyTbItemPrivate
+{
+};
+
+/**
+ * Private functions, only availble from this file
+ */
+static void ephy_tb_item_class_init (EphyTbItemClass *klass);
+static void ephy_tb_item_init (EphyTbItem *tb);
+static void ephy_tb_item_finalize_impl (GObject *o);
+
+static gpointer g_object_class;
+
+/**
+ * TbItem object
+ */
+
+MAKE_GET_TYPE (ephy_tb_item, "EphyTbItem", EphyTbItem, ephy_tb_item_class_init,
+ ephy_tb_item_init, G_TYPE_OBJECT);
+
+static void
+ephy_tb_item_class_init (EphyTbItemClass *klass)
+{
+ G_OBJECT_CLASS (klass)->finalize = ephy_tb_item_finalize_impl;
+
+ g_object_class = g_type_class_peek_parent (klass);
+}
+
+static void
+ephy_tb_item_init (EphyTbItem *it)
+{
+ EphyTbItemPrivate *p = g_new0 (EphyTbItemPrivate, 1);
+ it->priv = p;
+ it->id = g_strdup ("");
+}
+
+static void
+ephy_tb_item_finalize_impl (GObject *o)
+{
+ EphyTbItem *it = EPHY_TB_ITEM (o);
+ EphyTbItemPrivate *p = it->priv;
+
+ g_free (it->id);
+ g_free (p);
+
+ DEBUG_MSG (("EphyTbItem finalized\n"));
+
+ G_OBJECT_CLASS (g_object_class)->finalize (o);
+}
+
+GtkWidget *
+ephy_tb_item_get_widget (EphyTbItem *i)
+{
+ return EPHY_TB_ITEM_GET_CLASS (i)->get_widget (i);
+}
+
+GdkPixbuf *
+ephy_tb_item_get_icon (EphyTbItem *i)
+{
+ return EPHY_TB_ITEM_GET_CLASS (i)->get_icon (i);
+}
+
+gchar *
+ephy_tb_item_get_name_human (EphyTbItem *i)
+{
+ return EPHY_TB_ITEM_GET_CLASS (i)->get_name_human (i);
+}
+
+gchar *
+ephy_tb_item_to_string (EphyTbItem *i)
+{
+ return EPHY_TB_ITEM_GET_CLASS (i)->to_string (i);
+}
+
+gboolean
+ephy_tb_item_is_unique (EphyTbItem *i)
+{
+ return EPHY_TB_ITEM_GET_CLASS (i)->is_unique (i);
+}
+
+EphyTbItem *
+ephy_tb_item_clone (EphyTbItem *i)
+{
+ return EPHY_TB_ITEM_GET_CLASS (i)->clone (i);
+}
+
+void
+ephy_tb_item_add_to_bonobo_tb (EphyTbItem *i, BonoboUIComponent *ui,
+ const char *container_path, guint index)
+{
+ EPHY_TB_ITEM_GET_CLASS (i)->add_to_bonobo_tb (i, ui, container_path, index);
+}
+
+void
+ephy_tb_item_set_id (EphyTbItem *i, const gchar *id)
+{
+ g_return_if_fail (EPHY_IS_TB_ITEM (i));
+
+ g_free (i->id);
+ i->id = g_strdup (id);
+}
+
+void
+ephy_tb_item_parse_properties (EphyTbItem *i, const gchar *props)
+{
+ EPHY_TB_ITEM_GET_CLASS (i)->parse_properties (i, props);
+}
diff --git a/lib/toolbar/ephy-toolbar-item.h b/lib/toolbar/ephy-toolbar-item.h
new file mode 100644
index 000000000..29e46697f
--- /dev/null
+++ b/lib/toolbar/ephy-toolbar-item.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2002 Ricardo Fernández Pascual
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EPHY_TOOLBAR_ITEM_H
+#define EPHY_TOOLBAR_ITEM_H
+
+#include <glib-object.h>
+
+#include <bonobo/bonobo-ui-component.h>
+#include <gtk/gtkwidget.h>
+
+G_BEGIN_DECLS
+
+/* object forward declarations */
+
+typedef struct _EphyTbItem EphyTbItem;
+typedef struct _EphyTbItemClass EphyTbItemClass;
+typedef struct _EphyTbItemPrivate EphyTbItemPrivate;
+
+/**
+ * TbItem object
+ */
+
+#define EPHY_TYPE_TB_ITEM (ephy_tb_item_get_type())
+#define EPHY_TB_ITEM(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EPHY_TYPE_TB_ITEM,\
+ EphyTbItem))
+#define EPHY_TB_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EPHY_TYPE_TB_ITEM,\
+ EphyTbItemClass))
+#define EPHY_IS_TB_ITEM(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EPHY_TYPE_TB_ITEM))
+#define EPHY_IS_TB_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), EPHY_TYPE_TB_ITEM))
+#define EPHY_TB_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EPHY_TYPE_TB_ITEM,\
+ EphyTbItemClass))
+
+struct _EphyTbItemClass
+{
+ GObjectClass parent_class;
+
+ /* virtual */
+ GtkWidget * (*get_widget) (EphyTbItem *it);
+ GdkPixbuf * (*get_icon) (EphyTbItem *it);
+ gchar * (*get_name_human) (EphyTbItem *it);
+ gchar * (*to_string) (EphyTbItem *it);
+ gboolean (*is_unique) (EphyTbItem *it);
+ void (*add_to_bonobo_tb) (EphyTbItem *it, BonoboUIComponent *ui,
+ const char *container_path, guint index);
+ EphyTbItem * (*clone) (EphyTbItem *it);
+ void (*parse_properties) (EphyTbItem *it, const gchar *props);
+};
+
+/* Remember: fields are public read-only */
+struct _EphyTbItem
+{
+ GObject parent_object;
+
+ gchar *id;
+
+ EphyTbItemPrivate *priv;
+};
+
+/* this class is abstract */
+
+GType ephy_tb_item_get_type (void);
+GtkWidget * ephy_tb_item_get_widget (EphyTbItem *i);
+GdkPixbuf * ephy_tb_item_get_icon (EphyTbItem *i);
+gchar * ephy_tb_item_get_name_human (EphyTbItem *i);
+gchar * ephy_tb_item_to_string (EphyTbItem *i);
+gboolean ephy_tb_item_is_unique (EphyTbItem *i);
+void ephy_tb_item_add_to_bonobo_tb (EphyTbItem *i, BonoboUIComponent *ui,
+ const char *container_path, guint index);
+EphyTbItem * ephy_tb_item_clone (EphyTbItem *i);
+void ephy_tb_item_set_id (EphyTbItem *i, const gchar *id);
+void ephy_tb_item_parse_properties (EphyTbItem *i, const gchar *props);
+
+G_END_DECLS
+
+#endif
diff --git a/lib/toolbar/ephy-toolbar-tree-model.c b/lib/toolbar/ephy-toolbar-tree-model.c
new file mode 100644
index 000000000..91acba952
--- /dev/null
+++ b/lib/toolbar/ephy-toolbar-tree-model.c
@@ -0,0 +1,784 @@
+/*
+ * Copyright (C) 2002 Ricardo Fernándezs Pascual <ric@users.sourceforge.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gtk/gtktreednd.h>
+#include <glib-object.h>
+#include <string.h>
+
+#include "ephy-toolbar-tree-model.h"
+
+#define NOT_IMPLEMENTED g_warning ("not implemented: " G_STRLOC);
+//#define DEBUG_MSG(x) g_print x
+#define DEBUG_MSG(x)
+
+#define VALID_ITER(iter, tb_tree_model) (iter!= NULL && iter->user_data != NULL \
+ && tb_tree_model->stamp == iter->stamp)
+
+/**
+ * Private data
+ */
+struct _EphyTbTreeModelPrivate
+{
+ EphyToolbar *tb;
+ GSList *curr_items;
+};
+
+/**
+ * Private functions
+ */
+static void ephy_tb_tree_model_init (EphyTbTreeModel *tb_tree_model);
+static void ephy_tb_tree_model_class_init (EphyTbTreeModelClass *tb_tree_model_class);
+static void ephy_tb_tree_model_tb_tree_model_init (GtkTreeModelIface *iface);
+static void ephy_tb_tree_model_drag_source_init (GtkTreeDragSourceIface *iface);
+static void ephy_tb_tree_model_drag_dest_init (GtkTreeDragDestIface *iface);
+static void ephy_tb_tree_model_finalize_impl (GObject *object);
+static guint ephy_tb_tree_model_get_flags_impl (GtkTreeModel *tb_tree_model);
+static gint ephy_tb_tree_model_get_n_columns_impl (GtkTreeModel *tb_tree_model);
+static GType ephy_tb_tree_model_get_column_type_impl (GtkTreeModel *tb_tree_model,
+ gint index);
+static gboolean ephy_tb_tree_model_get_iter_impl (GtkTreeModel *tb_tree_model,
+ GtkTreeIter *iter,
+ GtkTreePath *path);
+static GtkTreePath * ephy_tb_tree_model_get_path_impl (GtkTreeModel *tb_tree_model,
+ GtkTreeIter *iter);
+static void ephy_tb_tree_model_get_value_impl (GtkTreeModel *tb_tree_model,
+ GtkTreeIter *iter,
+ gint column,
+ GValue *value);
+static gboolean ephy_tb_tree_model_iter_next_impl (GtkTreeModel *tb_tree_model,
+ GtkTreeIter *iter);
+static gboolean ephy_tb_tree_model_iter_children_impl (GtkTreeModel *tb_tree_model,
+ GtkTreeIter *iter,
+ GtkTreeIter *parent);
+static gboolean ephy_tb_tree_model_iter_has_child_impl (GtkTreeModel *tb_tree_model,
+ GtkTreeIter *iter);
+static gint ephy_tb_tree_model_iter_n_children_impl (GtkTreeModel *tb_tree_model,
+ GtkTreeIter *iter);
+static gboolean ephy_tb_tree_model_iter_nth_child_impl (GtkTreeModel *tb_tree_model,
+ GtkTreeIter *iter,
+ GtkTreeIter *parent,
+ gint n);
+static gboolean ephy_tb_tree_model_iter_parent_impl (GtkTreeModel *tb_tree_model,
+ GtkTreeIter *iter,
+ GtkTreeIter *child);
+
+/* DND interfaces */
+static gboolean ephy_tb_tree_model_drag_data_delete_impl(GtkTreeDragSource *drag_source,
+ GtkTreePath *path);
+static gboolean ephy_tb_tree_model_drag_data_get_impl (GtkTreeDragSource *drag_source,
+ GtkTreePath *path,
+ GtkSelectionData *selection_data);
+static gboolean ephy_tb_tree_model_drag_data_received_impl (GtkTreeDragDest *drag_dest,
+ GtkTreePath *dest,
+ GtkSelectionData *selection_data);
+static gboolean ephy_tb_tree_model_row_drop_possible_impl (GtkTreeDragDest *drag_dest,
+ GtkTreePath *dest_path,
+ GtkSelectionData *selection_data);
+
+/* helper functions */
+static void ephy_tb_tree_model_toolbar_changed_cb (EphyToolbar *tb, EphyTbTreeModel *tm);
+static void ephy_tb_tree_model_update (EphyTbTreeModel *tm);
+
+
+static GObjectClass *parent_class = NULL;
+
+GtkType
+ephy_tb_tree_model_get_type (void)
+{
+ static GType tb_tree_model_type = 0;
+
+ if (!tb_tree_model_type)
+ {
+ static const GTypeInfo tb_tree_model_info =
+ {
+ sizeof (EphyTbTreeModelClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) ephy_tb_tree_model_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (EphyTbTreeModel),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) ephy_tb_tree_model_init
+ };
+
+ static const GInterfaceInfo tb_gtk_tree_model_info =
+ {
+ (GInterfaceInitFunc) ephy_tb_tree_model_tb_tree_model_init,
+ NULL,
+ NULL
+ };
+
+ static const GInterfaceInfo drag_source_info =
+ {
+ (GInterfaceInitFunc) ephy_tb_tree_model_drag_source_init,
+ NULL,
+ NULL
+ };
+
+ static const GInterfaceInfo drag_dest_info =
+ {
+ (GInterfaceInitFunc) ephy_tb_tree_model_drag_dest_init,
+ NULL,
+ NULL
+ };
+
+ tb_tree_model_type = g_type_register_static (G_TYPE_OBJECT, "EphyTbTreeModel",
+ &tb_tree_model_info, 0);
+
+ g_type_add_interface_static (tb_tree_model_type,
+ GTK_TYPE_TREE_MODEL,
+ &tb_gtk_tree_model_info);
+ g_type_add_interface_static (tb_tree_model_type,
+ GTK_TYPE_TREE_DRAG_SOURCE,
+ &drag_source_info);
+ g_type_add_interface_static (tb_tree_model_type,
+ GTK_TYPE_TREE_DRAG_DEST,
+ &drag_dest_info);
+ }
+
+ return tb_tree_model_type;
+}
+
+static void
+ephy_tb_tree_model_class_init (EphyTbTreeModelClass *class)
+{
+ GObjectClass *object_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ object_class = (GObjectClass *) class;
+
+ object_class->finalize = ephy_tb_tree_model_finalize_impl;
+}
+
+static void
+ephy_tb_tree_model_tb_tree_model_init (GtkTreeModelIface *iface)
+{
+ iface->get_flags = ephy_tb_tree_model_get_flags_impl;
+ iface->get_n_columns = ephy_tb_tree_model_get_n_columns_impl;
+ iface->get_column_type = ephy_tb_tree_model_get_column_type_impl;
+ iface->get_iter = ephy_tb_tree_model_get_iter_impl;
+ iface->get_path = ephy_tb_tree_model_get_path_impl;
+ iface->get_value = ephy_tb_tree_model_get_value_impl;
+ iface->iter_next = ephy_tb_tree_model_iter_next_impl;
+ iface->iter_children = ephy_tb_tree_model_iter_children_impl;
+ iface->iter_has_child = ephy_tb_tree_model_iter_has_child_impl;
+ iface->iter_n_children = ephy_tb_tree_model_iter_n_children_impl;
+ iface->iter_nth_child = ephy_tb_tree_model_iter_nth_child_impl;
+ iface->iter_parent = ephy_tb_tree_model_iter_parent_impl;
+}
+
+static void
+ephy_tb_tree_model_drag_source_init (GtkTreeDragSourceIface *iface)
+{
+ iface->drag_data_delete = ephy_tb_tree_model_drag_data_delete_impl;
+ iface->drag_data_get = ephy_tb_tree_model_drag_data_get_impl;
+}
+
+static void
+ephy_tb_tree_model_drag_dest_init (GtkTreeDragDestIface *iface)
+{
+ iface->drag_data_received = ephy_tb_tree_model_drag_data_received_impl;
+ iface->row_drop_possible = ephy_tb_tree_model_row_drop_possible_impl;
+}
+
+static void
+ephy_tb_tree_model_init (EphyTbTreeModel *tb_tree_model)
+{
+ EphyTbTreeModelPrivate *p = g_new0 (EphyTbTreeModelPrivate, 1);
+ tb_tree_model->priv = p;
+
+ do
+ {
+ tb_tree_model->stamp = g_random_int ();
+ }
+ while (tb_tree_model->stamp == 0);
+}
+
+EphyTbTreeModel *
+ephy_tb_tree_model_new (void)
+{
+ EphyTbTreeModel *ret = EPHY_TB_TREE_MODEL (g_object_new (EPHY_TYPE_TB_TREE_MODEL, NULL));
+ return ret;
+}
+
+
+void
+ephy_tb_tree_model_set_toolbar (EphyTbTreeModel *tm, EphyToolbar *tb)
+{
+ EphyTbTreeModelPrivate *p;
+
+ g_return_if_fail (EPHY_IS_TB_TREE_MODEL (tm));
+ g_return_if_fail (EPHY_IS_TOOLBAR (tb));
+
+ p = tm->priv;
+
+ if (p->tb)
+ {
+ g_signal_handlers_disconnect_matched (p->tb, G_SIGNAL_MATCH_DATA, 0, 0,
+ NULL, NULL, tm);
+ g_object_unref (p->tb);
+ }
+
+ p->tb = g_object_ref (tb);
+ g_signal_connect (p->tb, "changed", G_CALLBACK (ephy_tb_tree_model_toolbar_changed_cb), tm);
+
+ ephy_tb_tree_model_update (tm);
+}
+
+static void
+ephy_tb_tree_model_finalize_impl (GObject *object)
+{
+ EphyTbTreeModel *tm = EPHY_TB_TREE_MODEL (object);
+ EphyTbTreeModelPrivate *p = tm->priv;
+
+ DEBUG_MSG (("Finalizing a EphyTbTreeModel\n"));
+
+ if (p->tb)
+ {
+ g_signal_handlers_disconnect_matched (p->tb, G_SIGNAL_MATCH_DATA, 0, 0,
+ NULL, NULL, tm);
+ g_object_unref (p->tb);
+ }
+
+ g_slist_foreach (p->curr_items, (GFunc) g_object_unref, NULL);
+ g_slist_free (p->curr_items);
+ g_free (p);
+
+ (* parent_class->finalize) (object);
+}
+
+/* fulfill the GtkTreeModel requirements */
+
+static guint
+ephy_tb_tree_model_get_flags_impl (GtkTreeModel *tb_tree_model)
+{
+ return 0;
+}
+
+static gint
+ephy_tb_tree_model_get_n_columns_impl (GtkTreeModel *tb_tree_model)
+{
+ return EPHY_TB_TREE_MODEL_NUM_COLUMS;
+}
+
+static GType
+ephy_tb_tree_model_get_column_type_impl (GtkTreeModel *tb_tree_model,
+ gint index)
+{
+ g_return_val_if_fail (EPHY_IS_TB_TREE_MODEL (tb_tree_model), G_TYPE_INVALID);
+ g_return_val_if_fail ((index < EPHY_TB_TREE_MODEL_NUM_COLUMS) && (index >= 0), G_TYPE_INVALID);
+
+ switch (index)
+ {
+ case EPHY_TB_TREE_MODEL_COL_ICON:
+ return GDK_TYPE_PIXBUF;
+ break;
+ case EPHY_TB_TREE_MODEL_COL_NAME:
+ return G_TYPE_STRING;
+ break;
+ default:
+ g_assert_not_reached ();
+ return G_TYPE_INVALID;
+ break;
+ }
+}
+
+static gboolean
+ephy_tb_tree_model_get_iter_impl (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreePath *path)
+{
+ EphyTbTreeModel *tb_tree_model = (EphyTbTreeModel *) tree_model;
+ EphyTbTreeModelPrivate *p;
+ GSList *li;
+ gint i;
+
+ g_return_val_if_fail (EPHY_IS_TB_TREE_MODEL (tb_tree_model), FALSE);
+ g_return_val_if_fail (gtk_tree_path_get_depth (path) > 0, FALSE);
+
+ p = tb_tree_model->priv;
+ i = gtk_tree_path_get_indices (path)[0];
+ li = g_slist_nth (p->curr_items, i);
+
+ if (!li)
+ {
+ return FALSE;
+ }
+
+ iter->stamp = tb_tree_model->stamp;
+ iter->user_data = li;
+
+ return TRUE;
+}
+
+static GtkTreePath *
+ephy_tb_tree_model_get_path_impl (GtkTreeModel *tree_model,
+ GtkTreeIter *iter)
+{
+ EphyTbTreeModel *tb_tree_model = (EphyTbTreeModel *) tree_model;
+ EphyTbTreeModelPrivate *p;
+ gint i;
+
+ g_return_val_if_fail (EPHY_IS_TB_TREE_MODEL (tb_tree_model), NULL);
+ g_return_val_if_fail (iter != NULL, NULL);
+ g_return_val_if_fail (iter->user_data != NULL, NULL);
+ g_return_val_if_fail (iter->stamp == tb_tree_model->stamp, NULL);
+
+ p = tb_tree_model->priv;
+
+ i = g_slist_position (p->curr_items, iter->user_data);
+ if (i < 0)
+ {
+ return NULL;
+ }
+ else
+ {
+ GtkTreePath *retval;
+ retval = gtk_tree_path_new ();
+ gtk_tree_path_append_index (retval, i);
+ return retval;
+ }
+}
+
+
+static void
+ephy_tb_tree_model_get_value_impl (GtkTreeModel *tb_tree_model,
+ GtkTreeIter *iter,
+ gint column,
+ GValue *value)
+{
+ EphyTbItem *it;
+ GdkPixbuf *pb;
+ gchar *s;
+
+ g_return_if_fail (EPHY_IS_TB_TREE_MODEL (tb_tree_model));
+ g_return_if_fail (iter != NULL);
+ g_return_if_fail (iter->stamp == EPHY_TB_TREE_MODEL (tb_tree_model)->stamp);
+ g_return_if_fail (EPHY_IS_TB_ITEM (((GSList *) iter->user_data)->data));
+ g_return_if_fail (column < EPHY_TB_TREE_MODEL_NUM_COLUMS);
+
+ it = ((GSList *) iter->user_data)->data;
+
+ switch (column) {
+ case EPHY_TB_TREE_MODEL_COL_ICON:
+ g_value_init (value, GDK_TYPE_PIXBUF);
+ pb = ephy_tb_item_get_icon (it);
+ g_value_set_object (value, pb);
+ break;
+ case EPHY_TB_TREE_MODEL_COL_NAME:
+ g_value_init (value, G_TYPE_STRING);
+ s = ephy_tb_item_get_name_human (it);
+ g_value_set_string_take_ownership (value, s);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+}
+
+static gboolean
+ephy_tb_tree_model_iter_next_impl (GtkTreeModel *tree_model,
+ GtkTreeIter *iter)
+{
+ g_return_val_if_fail (EPHY_IS_TB_TREE_MODEL (tree_model), FALSE);
+ g_return_val_if_fail (EPHY_TB_TREE_MODEL (tree_model)->stamp == iter->stamp, FALSE);
+
+ iter->user_data = ((GSList *) (iter->user_data))->next;
+ return (iter->user_data != NULL);
+}
+
+static gboolean
+ephy_tb_tree_model_iter_children_impl (GtkTreeModel *tb_tree_model,
+ GtkTreeIter *iter,
+ GtkTreeIter *parent)
+{
+ if (parent)
+ {
+ /* this is a list, nodes have no children */
+ return FALSE;
+ }
+ else
+ {
+ /* but if parent == NULL we return the list itself as children of the
+ * "root"
+ */
+ EphyTbTreeModel *tm = EPHY_TB_TREE_MODEL (tb_tree_model);
+ EphyTbTreeModelPrivate *p = tm->priv;
+
+ iter->stamp = tm->stamp;
+ iter->user_data = p->curr_items;
+ return (p->curr_items != NULL);
+ }
+}
+
+static gboolean
+ephy_tb_tree_model_iter_has_child_impl (GtkTreeModel *tb_tree_model,
+ GtkTreeIter *iter)
+{
+ return FALSE;
+}
+
+static gint
+ephy_tb_tree_model_iter_n_children_impl (GtkTreeModel *tb_tree_model,
+ GtkTreeIter *iter)
+{
+ EphyTbTreeModel *tm = (EphyTbTreeModel *) tb_tree_model;
+ EphyTbTreeModelPrivate *p;
+ g_return_val_if_fail (EPHY_IS_TB_TREE_MODEL (tm), -1);
+
+ p = tm->priv;
+
+ if (iter == NULL)
+ {
+ return g_slist_length (p->curr_items);
+ }
+
+ g_return_val_if_fail (tm->stamp == iter->stamp, -1);
+ return 0;
+}
+
+static gboolean
+ephy_tb_tree_model_iter_nth_child_impl (GtkTreeModel *tb_tree_model,
+ GtkTreeIter *iter,
+ GtkTreeIter *parent,
+ gint n)
+{
+ EphyTbTreeModel *tm = (EphyTbTreeModel *) tb_tree_model;
+ EphyTbTreeModelPrivate *p;
+ g_return_val_if_fail (EPHY_IS_TB_TREE_MODEL (tm), FALSE);
+
+ p = tm->priv;
+
+ if (parent)
+ {
+ return FALSE;
+ }
+ else
+ {
+ GSList *li = g_slist_nth (p->curr_items, n);
+
+ if (li)
+ {
+ iter->stamp = tm->stamp;
+ iter->user_data = li;
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+ }
+}
+
+static gboolean
+ephy_tb_tree_model_iter_parent_impl (GtkTreeModel *tb_tree_model,
+ GtkTreeIter *iter,
+ GtkTreeIter *child)
+{
+ return FALSE;
+}
+
+
+
+/* DND */
+
+
+static gboolean
+ephy_tb_tree_model_drag_data_delete_impl (GtkTreeDragSource *drag_source,
+ GtkTreePath *path)
+{
+ GtkTreeIter iter;
+ EphyTbTreeModel *tm;
+
+ g_return_val_if_fail (EPHY_IS_TB_TREE_MODEL (drag_source), FALSE);
+
+ tm = EPHY_TB_TREE_MODEL (drag_source);
+
+ DEBUG_MSG (("in ephy_tb_tree_model_drag_data_delete_impl\n"));
+
+ if (ephy_tb_tree_model_get_iter_impl (GTK_TREE_MODEL (tm), &iter, path))
+ {
+ EphyTbTreeModelPrivate *p = tm->priv;
+ EphyTbItem *it = ephy_tb_tree_model_item_from_iter (tm, &iter);
+ EphyTbItem *delete_hack;
+ if ((delete_hack = g_object_get_data (G_OBJECT (tm),
+ "gul-toolbar-tree-model-dnd-delete-hack")) != NULL)
+ {
+ g_return_val_if_fail (EPHY_IS_TB_ITEM (delete_hack), FALSE);
+ g_object_ref (delete_hack);
+
+ g_object_set_data (G_OBJECT (tm),
+ "gul-toolbar-tree-model-dnd-delete-hack", NULL);
+
+ if (!strcmp (delete_hack->id, it->id))
+ {
+ g_object_unref (delete_hack);
+ return FALSE;
+ }
+ g_object_unref (delete_hack);
+ }
+
+ ephy_toolbar_remove_item (p->tb, it);
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+static gboolean
+ephy_tb_tree_model_drag_data_get_impl (GtkTreeDragSource *drag_source,
+ GtkTreePath *path,
+ GtkSelectionData *selection_data)
+{
+ g_return_val_if_fail (EPHY_IS_TB_TREE_MODEL (drag_source), FALSE);
+
+ /* Note that we don't need to handle the GTK_TB_TREE_MODEL_ROW
+ * target, because the default handler does it for us, but
+ * we do anyway for the convenience of someone maybe overriding the
+ * default handler.
+ */
+
+ if (gtk_tree_set_row_drag_data (selection_data,
+ GTK_TREE_MODEL (drag_source),
+ path))
+ {
+ return TRUE;
+ }
+ else
+ {
+ /* to string ? */
+ }
+
+ return FALSE;
+}
+
+
+static gboolean
+ephy_tb_tree_model_drag_data_received_impl (GtkTreeDragDest *drag_dest,
+ GtkTreePath *dest,
+ GtkSelectionData *selection_data)
+{
+ EphyTbTreeModel *tbm;
+ GtkTreeModel *src_model = NULL;
+ GtkTreePath *src_path = NULL;
+
+ g_return_val_if_fail (EPHY_IS_TB_TREE_MODEL (drag_dest), FALSE);
+ g_return_val_if_fail (gtk_tree_path_get_depth (dest) == 1, FALSE);
+
+ tbm = EPHY_TB_TREE_MODEL (drag_dest);
+
+ DEBUG_MSG (("in ephy_tb_tree_model_drag_data_received_impl\n"));
+
+ if (gtk_tree_get_row_drag_data (selection_data,
+ &src_model,
+ &src_path)
+ && EPHY_IS_TB_TREE_MODEL (src_model))
+ {
+ /* copy the item */
+
+ GtkTreeIter src_iter;
+ EphyTbItem *it;
+ int idx = gtk_tree_path_get_indices (dest)[0];
+
+ if (!gtk_tree_model_get_iter (src_model,
+ &src_iter,
+ src_path))
+ {
+ gtk_tree_path_free (src_path);
+ return FALSE;
+ }
+ gtk_tree_path_free (src_path);
+
+ if (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (drag_dest),
+ "gtk-tree-model-drop-append")))
+ {
+ ++idx;
+ }
+
+ it = ephy_tb_item_clone (EPHY_TB_ITEM (((GSList *)src_iter.user_data)->data));
+ ephy_toolbar_add_item (tbm->priv->tb, it, idx);
+
+ /* hack */
+ if (src_model == GTK_TREE_MODEL (drag_dest)
+ && ephy_toolbar_get_check_unique (EPHY_TB_TREE_MODEL (src_model)->priv->tb)
+ && ephy_tb_item_is_unique (it))
+ {
+ g_object_set_data_full (G_OBJECT (src_model),
+ "gul-toolbar-tree-model-dnd-delete-hack", it,
+ g_object_unref);
+ }
+ else
+ {
+ g_object_unref (it);
+ }
+
+ g_object_set_data (G_OBJECT (drag_dest), "gtk-tree-model-drop-append", NULL);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+ephy_tb_tree_model_row_drop_possible_impl (GtkTreeDragDest *drag_dest,
+ GtkTreePath *dest_path,
+ GtkSelectionData *selection_data)
+{
+ GtkTreeModel *src_model = NULL;
+ GtkTreePath *src_path = NULL;
+ gboolean retval = FALSE;
+ EphyTbTreeModel *tm;
+ EphyTbTreeModelPrivate *p;
+
+ g_return_val_if_fail (EPHY_IS_TB_TREE_MODEL (drag_dest), FALSE);
+ tm = EPHY_TB_TREE_MODEL (drag_dest);
+ p = tm->priv;
+
+ if (gtk_tree_path_get_depth (dest_path) != 1)
+ {
+ return FALSE;
+ }
+ if (!gtk_tree_get_row_drag_data (selection_data,
+ &src_model,
+ &src_path))
+ {
+ return FALSE;
+ }
+
+ /* can drop before any existing node, or before one past any existing. */
+
+ retval = (gtk_tree_path_get_indices (dest_path)[0] <= (gint) g_slist_length (p->curr_items));
+
+ gtk_tree_path_free (src_path);
+
+ return retval;
+}
+
+
+EphyTbItem *
+ephy_tb_tree_model_item_from_iter (EphyTbTreeModel *tm, GtkTreeIter *iter)
+{
+ return iter ? EPHY_TB_ITEM (((GSList *) iter->user_data)->data) : NULL;
+}
+
+static void
+ephy_tb_tree_model_toolbar_changed_cb (EphyToolbar *tb, EphyTbTreeModel *tm)
+{
+ ephy_tb_tree_model_update (tm);
+}
+
+static void
+ephy_tb_tree_model_update (EphyTbTreeModel *tm)
+{
+ EphyTbTreeModelPrivate *p;
+ GSList *new_items;
+ GSList *old_items;
+ GSList *li;
+ GSList *lj;
+ int i;
+
+ g_return_if_fail (EPHY_IS_TB_TREE_MODEL (tm));
+ p = tm->priv;
+ g_return_if_fail (EPHY_IS_TOOLBAR (p->tb));
+
+ old_items = p->curr_items;
+ new_items = g_slist_copy ((GSList *) ephy_toolbar_get_item_list (p->tb));
+ g_slist_foreach (new_items, (GFunc) g_object_ref, NULL);
+ p->curr_items = new_items;
+
+ li = new_items;
+ lj = old_items;
+ i = 0;
+
+ while (li && lj)
+ {
+ if (li->data == lj->data)
+ {
+ li = li->next;
+ lj = lj->next;
+ ++i;
+ }
+ else if (lj->next && lj->next->data == li->data)
+ {
+ GtkTreePath *p = gtk_tree_path_new ();
+ gtk_tree_path_append_index (p, i);
+ gtk_tree_model_row_deleted (GTK_TREE_MODEL (tm), p);
+ gtk_tree_path_free (p);
+ lj = lj->next;
+ }
+ else if (li->next && li->next->data == lj->data)
+ {
+ GtkTreePath *p = gtk_tree_path_new ();
+ GtkTreeIter iter;
+ iter.stamp = tm->stamp;
+ iter.user_data = li;
+ gtk_tree_path_append_index (p, i);
+ gtk_tree_model_row_inserted (GTK_TREE_MODEL (tm), p, &iter);
+ gtk_tree_path_free (p);
+ li = li->next;
+ ++i;
+ }
+ else
+ {
+ GtkTreePath *p = gtk_tree_path_new ();
+ GtkTreeIter iter;
+ iter.stamp = tm->stamp;
+ iter.user_data = li;
+ gtk_tree_path_append_index (p, i);
+ gtk_tree_model_row_deleted (GTK_TREE_MODEL (tm), p);
+ gtk_tree_model_row_inserted (GTK_TREE_MODEL (tm), p, &iter);
+ gtk_tree_path_free (p);
+ lj = lj->next;
+ li = li->next;
+ ++i;
+ }
+ }
+
+ while (li)
+ {
+ GtkTreePath *p = gtk_tree_path_new ();
+ GtkTreeIter iter;
+ iter.stamp = tm->stamp;
+ iter.user_data = li;
+ gtk_tree_path_append_index (p, i);
+ gtk_tree_model_row_inserted (GTK_TREE_MODEL (tm), p, &iter);
+ gtk_tree_path_free (p);
+ li = li->next;
+ ++i;
+ }
+
+ while (lj)
+ {
+ GtkTreePath *p = gtk_tree_path_new ();
+ gtk_tree_path_append_index (p, i);
+ gtk_tree_model_row_deleted (GTK_TREE_MODEL (tm), p);
+ gtk_tree_path_free (p);
+ lj = lj->next;
+ }
+
+ g_slist_foreach (old_items, (GFunc) g_object_unref, NULL);
+ g_slist_free (old_items);
+}
+
diff --git a/lib/toolbar/ephy-toolbar-tree-model.h b/lib/toolbar/ephy-toolbar-tree-model.h
new file mode 100644
index 000000000..893e6ba9a
--- /dev/null
+++ b/lib/toolbar/ephy-toolbar-tree-model.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2002 Ricardo Fernándezs Pascual <ric@users.sourceforge.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EPHY_TOOLBAR_TREE_MODEL_H
+#define EPHY_TOOLBAR_TREE_MODEL_H
+
+#include <gtk/gtktreemodel.h>
+#include "ephy-toolbar.h"
+
+G_BEGIN_DECLS
+
+/* object forward declarations */
+
+typedef struct _EphyTbTreeModel EphyTbTreeModel;
+typedef struct _EphyTbTreeModelClass EphyTbTreeModelClass;
+typedef struct _EphyTbTreeModelPrivate EphyTbTreeModelPrivate;
+
+typedef enum {
+ EPHY_TB_TREE_MODEL_COL_ICON,
+ EPHY_TB_TREE_MODEL_COL_NAME,
+ EPHY_TB_TREE_MODEL_NUM_COLUMS
+} EphyTbTreeModelColumn;
+
+/**
+ * Tb tree model object
+ */
+
+#define EPHY_TYPE_TB_TREE_MODEL (ephy_tb_tree_model_get_type())
+#define EPHY_TB_TREE_MODEL(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EPHY_TYPE_TB_TREE_MODEL,\
+ EphyTbTreeModel))
+#define EPHY_TB_TREE_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EPHY_TYPE_TB_TREE_MODEL,\
+ EphyTbTreeModelClass))
+#define EPHY_IS_TB_TREE_MODEL(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EPHY_TYPE_TB_TREE_MODEL))
+#define EPHY_IS_TB_TREE_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), EPHY_TYPE_TB_TREE_MODEL))
+#define EPHY_TB_TREE_MODEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EPHY_TYPE_TB_TREE_MODEL,\
+ EphyTbTreeModelClass))
+
+struct _EphyTbTreeModel
+{
+ GObject parent;
+
+ EphyTbTreeModelPrivate *priv;
+ gint stamp;
+};
+
+struct _EphyTbTreeModelClass
+{
+ GObjectClass parent_class;
+};
+
+
+GtkType ephy_tb_tree_model_get_type (void);
+EphyTbTreeModel * ephy_tb_tree_model_new (void);
+void ephy_tb_tree_model_set_toolbar (EphyTbTreeModel *tm, EphyToolbar *tb);
+EphyTbItem * ephy_tb_tree_model_item_from_iter (EphyTbTreeModel *tm, GtkTreeIter *iter);
+
+G_END_DECLS
+
+#endif
diff --git a/lib/toolbar/ephy-toolbar.c b/lib/toolbar/ephy-toolbar.c
new file mode 100644
index 000000000..53598cc6c
--- /dev/null
+++ b/lib/toolbar/ephy-toolbar.c
@@ -0,0 +1,420 @@
+/*
+ * Copyright (C) 2002 Ricardo Fernández Pascual
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <libgnome/gnome-i18n.h>
+#include <string.h>
+#include "ephy-gobject-misc.h"
+#include "ephy-marshal.h"
+#include "ephy-toolbar.h"
+#include "ephy-toolbar-item-factory.h"
+#include "eel-gconf-extensions.h"
+
+#define NOT_IMPLEMENTED g_warning ("not implemented: " G_STRLOC);
+//#define DEBUG_MSG(x) g_print x
+#define DEBUG_MSG(x)
+
+/**
+ * Private data
+ */
+struct _EphyToolbarPrivate
+{
+ GSList *items;
+ guint gconf_notification_id;
+
+ gboolean check_unique;
+ gboolean fixed_order;
+ GSList *order; /* list of ids */
+};
+
+/**
+ * Private functions, only availble from this file
+ */
+static void ephy_toolbar_class_init (EphyToolbarClass *klass);
+static void ephy_toolbar_init (EphyToolbar *tb);
+static void ephy_toolbar_finalize_impl (GObject *o);
+static void ephy_toolbar_listen_to_gconf_cb (GConfClient* client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ gpointer user_data);
+static void ephy_toolbar_update_order (EphyToolbar *tb);
+
+
+static gpointer g_object_class;
+
+/* signals enums and ids */
+enum EphyToolbarSignalsEnum {
+ EPHY_TOOLBAR_CHANGED,
+ EPHY_TOOLBAR_LAST_SIGNAL
+};
+static gint EphyToolbarSignals[EPHY_TOOLBAR_LAST_SIGNAL];
+
+/**
+ * Toolbar object
+ */
+
+MAKE_GET_TYPE (ephy_toolbar, "EphyToolbar", EphyToolbar, ephy_toolbar_class_init,
+ ephy_toolbar_init, G_TYPE_OBJECT);
+
+static void
+ephy_toolbar_class_init (EphyToolbarClass *klass)
+{
+ G_OBJECT_CLASS (klass)->finalize = ephy_toolbar_finalize_impl;
+
+ EphyToolbarSignals[EPHY_TOOLBAR_CHANGED] = g_signal_new (
+ "changed", G_OBJECT_CLASS_TYPE (klass),
+ G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST | G_SIGNAL_RUN_CLEANUP,
+ G_STRUCT_OFFSET (EphyToolbarClass, changed),
+ NULL, NULL,
+ ephy_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ g_object_class = g_type_class_peek_parent (klass);
+}
+
+static void
+ephy_toolbar_init (EphyToolbar *tb)
+{
+ EphyToolbarPrivate *p = g_new0 (EphyToolbarPrivate, 1);
+ tb->priv = p;
+
+ p->check_unique = TRUE;
+}
+
+static void
+ephy_toolbar_finalize_impl (GObject *o)
+{
+ EphyToolbar *tb = EPHY_TOOLBAR (o);
+ EphyToolbarPrivate *p = tb->priv;
+
+ g_slist_foreach (p->items, (GFunc) g_object_unref, NULL);
+ g_slist_free (p->items);
+
+ if (p->gconf_notification_id)
+ {
+ eel_gconf_notification_remove (p->gconf_notification_id);
+ }
+
+ g_slist_foreach (p->order, (GFunc) g_free, NULL);
+ g_slist_free (p->order);
+
+ g_free (p);
+
+ DEBUG_MSG (("EphyToolbar finalized\n"));
+
+ G_OBJECT_CLASS (g_object_class)->finalize (o);
+}
+
+
+EphyToolbar *
+ephy_toolbar_new (void)
+{
+ EphyToolbar *ret = g_object_new (EPHY_TYPE_TOOLBAR, NULL);
+ return ret;
+}
+
+gboolean
+ephy_toolbar_parse (EphyToolbar *tb, const gchar *cfg)
+{
+ EphyToolbarPrivate *p = tb->priv;
+ GSList *list = NULL;
+ gchar **items;
+ int i;
+
+ g_return_val_if_fail (EPHY_IS_TOOLBAR (tb), FALSE);
+ g_return_val_if_fail (cfg != NULL, FALSE);
+
+ items = g_strsplit (cfg, ";", 9999);
+ if (!items) return FALSE;
+
+ for (i = 0; items[i]; ++i)
+ {
+ if (items[i][0])
+ {
+ EphyTbItem *it = ephy_toolbar_item_create_from_string (items[i]);
+
+ if (!it)
+ {
+ /* FIXME: this leaks everything... */
+ return FALSE;
+ }
+
+ list = g_slist_prepend (list, it);
+ }
+ }
+
+ g_strfreev (items);
+
+ g_slist_foreach (p->items, (GFunc) g_object_unref, NULL);
+ g_slist_free (p->items);
+ p->items = g_slist_reverse (list);
+
+ if (p->fixed_order)
+ {
+ ephy_toolbar_update_order (tb);
+ }
+
+ g_signal_emit (tb, EphyToolbarSignals[EPHY_TOOLBAR_CHANGED], 0);
+
+ return TRUE;
+}
+
+gchar *
+ephy_toolbar_to_string (EphyToolbar *tb)
+{
+ EphyToolbarPrivate *p = tb->priv;
+ gchar *ret;
+ GString *str = g_string_new ("");
+ GSList *li;
+
+ for (li = p->items; li; li = li->next)
+ {
+ EphyTbItem *it = li->data;
+ gchar *s = ephy_tb_item_to_string (it);
+ g_string_append (str, s);
+ if (li->next)
+ {
+ g_string_append (str, ";");
+ }
+ g_free (s);
+ }
+
+ ret = str->str;
+ g_string_free (str, FALSE);
+ return ret;
+}
+
+static void
+ephy_toolbar_listen_to_gconf_cb (GConfClient* client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ gpointer user_data)
+{
+ EphyToolbar *tb = user_data;
+ GConfValue *value;
+ const char *str;
+
+ g_return_if_fail (EPHY_IS_TOOLBAR (tb));
+
+ value = gconf_entry_get_value (entry);
+ str = gconf_value_get_string (value);
+
+ DEBUG_MSG (("in ephy_toolbar_listen_to_gconf_cb\n"));
+
+ ephy_toolbar_parse (tb, str);
+}
+
+/**
+ * Listen to changes in the toolbar configuration. Returns TRUE if the
+ * current configuration is valid.
+ */
+gboolean
+ephy_toolbar_listen_to_gconf (EphyToolbar *tb, const gchar *gconf_key)
+{
+ EphyToolbarPrivate *p = tb->priv;
+ gchar *s;
+ gboolean ret = FALSE;
+
+ if (p->gconf_notification_id)
+ {
+ eel_gconf_notification_remove (p->gconf_notification_id);
+ }
+
+ s = eel_gconf_get_string (gconf_key);
+ if (s)
+ {
+ ret = ephy_toolbar_parse (tb, s);
+ g_free (s);
+ }
+
+ p->gconf_notification_id = eel_gconf_notification_add (gconf_key,
+ ephy_toolbar_listen_to_gconf_cb,
+ tb);
+
+ DEBUG_MSG (("listening to %s, %d (FIXME: does not seem to work)\n",
+ gconf_key, p->gconf_notification_id));
+
+ return ret;
+}
+
+EphyTbItem *
+ephy_toolbar_get_item_by_id (EphyToolbar *tb, const gchar *id)
+{
+ EphyToolbarPrivate *p = tb->priv;
+ GSList *li;
+
+ for (li = p->items; li; li = li->next)
+ {
+ EphyTbItem *i = li->data;
+ if (i->id && !strcmp (i->id, id))
+ {
+ return i;
+ }
+ }
+ return NULL;
+}
+
+const GSList *
+ephy_toolbar_get_item_list (EphyToolbar *tb)
+{
+ EphyToolbarPrivate *p = tb->priv;
+ return p->items;
+}
+
+void
+ephy_toolbar_add_item (EphyToolbar *tb, EphyTbItem *it, gint index)
+{
+ EphyToolbarPrivate *p = tb->priv;
+ EphyTbItem *old_it;
+
+ g_return_if_fail (g_slist_find (p->items, it) == NULL);
+
+ if (p->check_unique && ephy_tb_item_is_unique (it)
+ && (old_it = ephy_toolbar_get_item_by_id (tb, it->id)) != NULL)
+ {
+ GSList *old_it_link;
+ if (p->fixed_order)
+ {
+ return;
+ }
+ old_it_link = g_slist_find (p->items, old_it);
+ p->items = g_slist_insert (p->items, old_it, index);
+ p->items = g_slist_delete_link (p->items, old_it_link);
+
+ }
+ else
+ {
+ if (p->fixed_order)
+ {
+ GSList *li;
+ if (ephy_toolbar_get_item_by_id (tb, it->id) != NULL)
+ {
+ return;
+ }
+ index = 0;
+ for (li = p->order; li && strcmp (li->data, it->id); li = li->next)
+ {
+ if (ephy_toolbar_get_item_by_id (tb, li->data) != NULL)
+ {
+ ++index;
+ }
+ }
+ }
+
+ p->items = g_slist_insert (p->items, it, index);
+ g_object_ref (it);
+ }
+ g_signal_emit (tb, EphyToolbarSignals[EPHY_TOOLBAR_CHANGED], 0);
+}
+
+void
+ephy_toolbar_remove_item (EphyToolbar *tb, EphyTbItem *it)
+{
+ EphyToolbarPrivate *p = tb->priv;
+
+ g_return_if_fail (g_slist_find (p->items, it) != NULL);
+
+ p->items = g_slist_remove (p->items, it);
+
+ g_signal_emit (tb, EphyToolbarSignals[EPHY_TOOLBAR_CHANGED], 0);
+
+ g_object_unref (it);
+}
+
+void
+ephy_toolbar_set_fixed_order (EphyToolbar *tb, gboolean value)
+{
+ EphyToolbarPrivate *p = tb->priv;
+ p->fixed_order = value;
+
+ if (value)
+ {
+ ephy_toolbar_update_order (tb);
+ }
+}
+
+void
+ephy_toolbar_set_check_unique (EphyToolbar *tb, gboolean value)
+{
+ EphyToolbarPrivate *p = tb->priv;
+ p->check_unique = value;
+
+ /* maybe it should remove duplicated items now, if any */
+}
+
+gboolean
+ephy_toolbar_get_check_unique (EphyToolbar *tb)
+{
+ EphyToolbarPrivate *p = tb->priv;
+ return p->check_unique;
+}
+
+static void
+ephy_toolbar_update_order (EphyToolbar *tb)
+{
+ EphyToolbarPrivate *p = tb->priv;
+ GSList *li;
+ GSList *lj;
+ GSList *new_order = NULL;
+
+ lj = p->order;
+ for (li = p->items; li; li = li->next)
+ {
+ EphyTbItem *i = li->data;
+ const gchar *id = i->id;
+
+ if (g_slist_find_custom (lj, id, (GCompareFunc) strcmp))
+ {
+ for ( ; lj && strcmp (lj->data, id); lj = lj->next)
+ {
+ if (ephy_toolbar_get_item_by_id (tb, lj->data) == NULL)
+ {
+ new_order = g_slist_prepend (new_order, g_strdup (lj->data));
+ }
+ }
+ }
+
+ new_order = g_slist_prepend (new_order, g_strdup (id));
+
+ }
+
+ for ( ; lj; lj = lj->next)
+ {
+ if (ephy_toolbar_get_item_by_id (tb, lj->data) == NULL)
+ {
+ new_order = g_slist_prepend (new_order, g_strdup (lj->data));
+ }
+ }
+
+ g_slist_foreach (p->order, (GFunc) g_free, NULL);
+ g_slist_free (p->order);
+
+ p->order = g_slist_reverse (new_order);
+
+#ifdef DEBUG_ORDER
+ DEBUG_MSG (("New order:\n"));
+ for (lj = p->order; lj; lj = lj->next)
+ {
+ DEBUG_MSG (("%s\n", (char *) lj->data));
+ }
+#endif
+}
+
diff --git a/lib/toolbar/ephy-toolbar.h b/lib/toolbar/ephy-toolbar.h
new file mode 100644
index 000000000..3c70a4783
--- /dev/null
+++ b/lib/toolbar/ephy-toolbar.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2002 Ricardo Fernández Pascual
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EPHY_TOOLBAR_H
+#define EPHY_TOOLBAR_H
+
+#include <glib-object.h>
+
+#include "ephy-toolbar-item.h"
+
+G_BEGIN_DECLS
+
+/* object forward declarations */
+
+typedef struct _EphyToolbar EphyToolbar;
+typedef struct _EphyToolbarClass EphyToolbarClass;
+typedef struct _EphyToolbarPrivate EphyToolbarPrivate;
+
+/**
+ * Toolbar object
+ */
+
+#define EPHY_TYPE_TOOLBAR (ephy_toolbar_get_type())
+#define EPHY_TOOLBAR(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EPHY_TYPE_TOOLBAR,\
+ EphyToolbar))
+#define EPHY_TOOLBAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EPHY_TYPE_TOOLBAR,\
+ EphyToolbarClass))
+#define EPHY_IS_TOOLBAR(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EPHY_TYPE_TOOLBAR))
+#define EPHY_IS_TOOLBAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), EPHY_TYPE_TOOLBAR))
+#define EPHY_TOOLBAR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EPHY_TYPE_TOOLBAR,\
+ EphyToolbarClass))
+
+struct _EphyToolbarClass
+{
+ GObjectClass parent_class;
+
+ /* signals */
+ void (*changed) (EphyToolbar *tb);
+
+};
+
+/* Remember: fields are public read-only */
+struct _EphyToolbar
+{
+ GObject parent_object;
+
+ EphyToolbarPrivate *priv;
+};
+
+GType ephy_toolbar_get_type (void);
+EphyToolbar * ephy_toolbar_new (void);
+gboolean ephy_toolbar_parse (EphyToolbar *tb, const gchar *cfg);
+gchar * ephy_toolbar_to_string (EphyToolbar *tb);
+gboolean ephy_toolbar_listen_to_gconf (EphyToolbar *tb, const gchar *gconf_key);
+EphyTbItem * ephy_toolbar_get_item_by_id (EphyToolbar *tb, const gchar *id);
+const GSList * ephy_toolbar_get_item_list (EphyToolbar *tb);
+void ephy_toolbar_add_item (EphyToolbar *tb, EphyTbItem *it, gint index);
+void ephy_toolbar_remove_item (EphyToolbar *tb, EphyTbItem *it);
+void ephy_toolbar_set_fixed_order (EphyToolbar *tb, gboolean value);
+void ephy_toolbar_set_check_unique (EphyToolbar *tb, gboolean value);
+gboolean ephy_toolbar_get_check_unique (EphyToolbar *tb);
+
+G_END_DECLS
+
+#endif
diff --git a/lib/widgets/.cvsignore b/lib/widgets/.cvsignore
new file mode 100644
index 000000000..20e4cb0c8
--- /dev/null
+++ b/lib/widgets/.cvsignore
@@ -0,0 +1,6 @@
+Makefile
+Makefile.in
+*.lo
+.deps
+.libs
+*.la
diff --git a/lib/widgets/Makefile.am b/lib/widgets/Makefile.am
new file mode 100644
index 000000000..a8b7a69b8
--- /dev/null
+++ b/lib/widgets/Makefile.am
@@ -0,0 +1,30 @@
+INCLUDES = \
+ -I$(top_srcdir)/lib \
+ $(WARN_CFLAGS) \
+ $(EPIPHANY_DEPENDENCY_CFLAGS) \
+ -DSHARE_DIR=\"$(pkgdatadir)\" \
+ -DG_DISABLE_DEPRECATED \
+ -DGDK_DISABLE_DEPRECATED \
+ -DGTK_DISABLE_DEPRECATED \
+ -DGDK_PIXBUF_DISABLE_DEPRECATED \
+ -DGNOME_DISABLE_DEPRECATED
+
+noinst_LTLIBRARIES = libephywidgets.la
+
+libephywidgets_la_SOURCES = \
+ ephy-ellipsizing-label.c \
+ ephy-ellipsizing-label.h \
+ ephy-notebook.c \
+ ephy-notebook.h \
+ ephy-location-entry.c \
+ ephy-location-entry.h \
+ ephy-autocompletion-window.c \
+ ephy-autocompletion-window.h \
+ ephy-spinner.c \
+ ephy-spinner.h \
+ eggtreemultidnd.c \
+ eggtreemultidnd.h \
+ ephy-tree-model-sort.c \
+ ephy-tree-model-sort.h \
+ eggtreemodelfilter.c \
+ eggtreemodelfilter.h
diff --git a/lib/widgets/eggtreemodelfilter.c b/lib/widgets/eggtreemodelfilter.c
new file mode 100644
index 000000000..b3b31a46d
--- /dev/null
+++ b/lib/widgets/eggtreemodelfilter.c
@@ -0,0 +1,2560 @@
+/* eggtreemodelfilter.c
+ * Copyright (C) 2000,2001 Red Hat, Inc., Jonathan Blandford <jrb@redhat.com>
+ * Copyright (C) 2001,2002 Kristian Rietveld <kris@gtk.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "eggtreemodelfilter.h"
+#include <gtk/gtksignal.h>
+#include <string.h>
+
+/****** NOTE NOTE NOTE WARNING WARNING ******
+ *
+ * This is *unstable* code. Don't use it in any project. This warning
+ * will be removed when this treemodel works.
+ */
+
+/*#define VERBOSE 1*/
+
+/* removed this when you add support for i18n */
+#define _
+
+/* ITER FORMAT:
+ *
+ * iter->stamp = filter->stamp
+ * iter->user_data = FilterLevel
+ * iter->user_data2 = FilterElt
+ */
+
+/* all paths, iters, etc prefixed with c_ are paths, iters, etc relative to the
+ * child model.
+ */
+
+typedef struct _FilterElt FilterElt;
+typedef struct _FilterLevel FilterLevel;
+
+struct _FilterElt
+{
+ GtkTreeIter iter;
+ FilterLevel *children;
+ gint offset;
+ gint ref_count;
+ gint zero_ref_count;
+ gboolean visible;
+};
+
+struct _FilterLevel
+{
+ GArray *array;
+ gint ref_count;
+
+ FilterElt *parent_elt;
+ FilterLevel *parent_level;
+};
+
+/* properties */
+enum
+{
+ PROP_0,
+ PROP_CHILD_MODEL,
+ PROP_VIRTUAL_ROOT
+};
+
+#define EGG_TREE_MODEL_FILTER_CACHE_CHILD_ITERS(filter) \
+ (((EggTreeModelFilter *)filter)->child_flags & GTK_TREE_MODEL_ITERS_PERSIST)
+
+#define FILTER_ELT(filter_elt) ((FilterElt *)filter_elt)
+#define FILTER_LEVEL(filter_level) ((FilterLevel *)filter_level)
+
+/* general code (object/interface init, properties, etc) */
+static void egg_tree_model_filter_init (EggTreeModelFilter *filter);
+static void egg_tree_model_filter_class_init (EggTreeModelFilterClass *filter_class);
+static void egg_tree_model_filter_tree_model_init (GtkTreeModelIface *iface);
+static void egg_tree_model_filter_finalize (GObject *object);
+static void egg_tree_model_filter_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void egg_tree_model_filter_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+/* signal handlers */
+static void egg_tree_model_filter_row_changed (GtkTreeModel *c_model,
+ GtkTreePath *c_path,
+ GtkTreeIter *c_iter,
+ gpointer data);
+static void egg_tree_model_filter_row_inserted (GtkTreeModel *c_model,
+ GtkTreePath *c_path,
+ GtkTreeIter *c_iter,
+ gpointer data);
+static void egg_tree_model_filter_row_has_child_toggled (GtkTreeModel *c_model,
+ GtkTreePath *c_path,
+ GtkTreeIter *c_iter,
+ gpointer data);
+static void egg_tree_model_filter_row_deleted (GtkTreeModel *c_model,
+ GtkTreePath *c_path,
+ gpointer data);
+static void egg_tree_model_filter_rows_reordered (GtkTreeModel *c_model,
+ GtkTreePath *c_path,
+ GtkTreeIter *c_iter,
+ gint *new_order,
+ gpointer data);
+
+/* GtkTreeModel interface */
+static guint egg_tree_model_filter_get_flags (GtkTreeModel *model);
+static gint egg_tree_model_filter_get_n_columns (GtkTreeModel *model);
+static GType egg_tree_model_filter_get_column_type (GtkTreeModel *model,
+ gint index);
+static gboolean egg_tree_model_filter_get_iter (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ GtkTreePath *path);
+static GtkTreePath *egg_tree_model_filter_get_path (GtkTreeModel *model,
+ GtkTreeIter *iter);
+static void egg_tree_model_filter_get_value (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gint column,
+ GValue *value);
+static gboolean egg_tree_model_filter_iter_next (GtkTreeModel *model,
+ GtkTreeIter *iter);
+static gboolean egg_tree_model_filter_iter_children (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ GtkTreeIter *parent);
+static gboolean egg_tree_model_filter_iter_has_child (GtkTreeModel *model,
+ GtkTreeIter *iter);
+static gint egg_tree_model_filter_iter_n_children (GtkTreeModel *model,
+ GtkTreeIter *iter);
+static gboolean egg_tree_model_filter_iter_nth_child (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ GtkTreeIter *parent,
+ gint n);
+static gboolean egg_tree_model_filter_iter_parent (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ GtkTreeIter *child);
+static void egg_tree_model_filter_ref_node (GtkTreeModel *model,
+ GtkTreeIter *iter);
+static void egg_tree_model_filter_unref_node (GtkTreeModel *model,
+ GtkTreeIter *iter);
+
+
+
+/* private functions */
+static void egg_tree_model_filter_build_level (EggTreeModelFilter *filter,
+ FilterLevel *parent_level,
+ FilterElt *parent_elt);
+static void egg_tree_model_filter_free_level (EggTreeModelFilter *filter,
+ FilterLevel *filter_level);
+
+static GtkTreePath *egg_tree_model_filter_elt_get_path (FilterLevel *level,
+ FilterElt *elt,
+ GtkTreePath *root);
+
+static GtkTreePath *egg_tree_model_filter_add_root (GtkTreePath *src,
+ GtkTreePath *root);
+static GtkTreePath *egg_tree_model_filter_remove_root (GtkTreePath *src,
+ GtkTreePath *root);
+
+static void egg_tree_model_filter_increment_stamp (EggTreeModelFilter *filter);
+
+static gboolean egg_tree_model_filter_visible (EggTreeModelFilter *filter,
+ GtkTreeIter *child_iter);
+static void egg_tree_model_filter_clear_cache_helper (EggTreeModelFilter *filter,
+ FilterLevel *level);
+
+static void egg_tree_model_filter_real_unref_node (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gboolean propagate_unref);
+
+static void egg_tree_model_filter_set_model (EggTreeModelFilter *filter,
+ GtkTreeModel *child_model);
+static void egg_tree_model_filter_set_root (EggTreeModelFilter *filter,
+ GtkTreePath *root);
+
+static GtkTreePath *egg_real_tree_model_filter_convert_child_path_to_path (EggTreeModelFilter *filter,
+ GtkTreePath *child_path,
+ gboolean build_levels,
+ gboolean fetch_childs);
+
+static gboolean egg_tree_model_filter_fetch_child (EggTreeModelFilter *filter,
+ FilterLevel *level,
+ gint offset);
+static void egg_tree_model_filter_remove_node (EggTreeModelFilter *filter,
+ GtkTreeIter *iter,
+ gboolean emit_signal);
+static void egg_tree_model_filter_update_childs (EggTreeModelFilter *filter,
+ FilterLevel *level,
+ FilterElt *elt);
+
+
+static GObjectClass *parent_class = NULL;
+
+GType
+egg_tree_model_filter_get_type (void)
+{
+ static GType tree_model_filter_type = 0;
+
+ if (!tree_model_filter_type)
+ {
+ static const GTypeInfo tree_model_filter_info =
+ {
+ sizeof (EggTreeModelFilterClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) egg_tree_model_filter_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (EggTreeModelFilter),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) egg_tree_model_filter_init
+ };
+
+ static const GInterfaceInfo tree_model_info =
+ {
+ (GInterfaceInitFunc) egg_tree_model_filter_tree_model_init,
+ NULL,
+ NULL
+ };
+
+ tree_model_filter_type = g_type_register_static (G_TYPE_OBJECT,
+ "EggTreeModelFilter",
+ &tree_model_filter_info, 0);
+
+ g_type_add_interface_static (tree_model_filter_type,
+ GTK_TYPE_TREE_MODEL,
+ &tree_model_info);
+ }
+
+ return tree_model_filter_type;
+}
+
+static void
+egg_tree_model_filter_init (EggTreeModelFilter *filter)
+{
+ filter->visible_column = -1;
+ filter->zero_ref_count = 0;
+ filter->visible_method_set = FALSE;
+ filter->modify_func_set = FALSE;
+}
+
+static void
+egg_tree_model_filter_class_init (EggTreeModelFilterClass *filter_class)
+{
+ GObjectClass *object_class;
+
+ object_class = (GObjectClass *) filter_class;
+ parent_class = g_type_class_peek_parent (filter_class);
+
+ object_class->set_property = egg_tree_model_filter_set_property;
+ object_class->get_property = egg_tree_model_filter_get_property;
+
+ object_class->finalize = egg_tree_model_filter_finalize;
+
+ /* Properties -- FIXME: write a better description ... */
+ g_object_class_install_property (object_class,
+ PROP_CHILD_MODEL,
+ g_param_spec_object ("child_model",
+ "The child model",
+ "The model for the TreeModelFilter to filter",
+ GTK_TYPE_TREE_MODEL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+ g_object_class_install_property (object_class,
+ PROP_VIRTUAL_ROOT,
+ g_param_spec_boxed ("virtual_root",
+ "The virtual root",
+ "The virtual root (relative to the child model) for this filtermodel",
+ GTK_TYPE_TREE_PATH,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+egg_tree_model_filter_tree_model_init (GtkTreeModelIface *iface)
+{
+ iface->get_flags = egg_tree_model_filter_get_flags;
+ iface->get_n_columns = egg_tree_model_filter_get_n_columns;
+ iface->get_column_type = egg_tree_model_filter_get_column_type;
+ iface->get_iter = egg_tree_model_filter_get_iter;
+ iface->get_path = egg_tree_model_filter_get_path;
+ iface->get_value = egg_tree_model_filter_get_value;
+ iface->iter_next = egg_tree_model_filter_iter_next;
+ iface->iter_children = egg_tree_model_filter_iter_children;
+ iface->iter_has_child = egg_tree_model_filter_iter_has_child;
+ iface->iter_n_children = egg_tree_model_filter_iter_n_children;
+ iface->iter_nth_child = egg_tree_model_filter_iter_nth_child;
+ iface->iter_parent = egg_tree_model_filter_iter_parent;
+ iface->ref_node = egg_tree_model_filter_ref_node;
+ iface->unref_node = egg_tree_model_filter_unref_node;
+}
+
+
+static void
+egg_tree_model_filter_finalize (GObject *object)
+{
+ EggTreeModelFilter *filter = (EggTreeModelFilter *) object;
+
+ egg_tree_model_filter_set_model (filter, NULL);
+
+ if (filter->virtual_root)
+ gtk_tree_path_free (filter->virtual_root);
+
+ if (filter->root)
+ egg_tree_model_filter_free_level (filter, filter->root);
+
+ if (filter->modify_types)
+ g_free (filter->modify_types);
+
+ /* must chain up */
+ parent_class->finalize (object);
+}
+
+static void
+egg_tree_model_filter_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EggTreeModelFilter *filter = EGG_TREE_MODEL_FILTER (object);
+
+ switch (prop_id)
+ {
+ case PROP_CHILD_MODEL:
+ egg_tree_model_filter_set_model (filter, g_value_get_object (value));
+ break;
+ case PROP_VIRTUAL_ROOT:
+ egg_tree_model_filter_set_root (filter, g_value_get_boxed (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+egg_tree_model_filter_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ EggTreeModelFilter *filter = EGG_TREE_MODEL_FILTER (object);
+
+ switch (prop_id)
+ {
+ case PROP_CHILD_MODEL:
+ g_value_set_object (value, filter->child_model);
+ break;
+ case PROP_VIRTUAL_ROOT:
+ g_value_set_boxed (value, filter->virtual_root);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+/* helpers */
+
+static void
+egg_tree_model_filter_build_level (EggTreeModelFilter *filter,
+ FilterLevel *parent_level,
+ FilterElt *parent_elt)
+{
+ GtkTreeIter iter;
+ GtkTreeIter root;
+ FilterLevel *new_level;
+ gint length = 0;
+ gint i;
+
+ g_assert (filter->child_model != NULL);
+
+ if (!parent_level)
+ {
+ if (filter->virtual_root)
+ {
+ if (gtk_tree_model_get_iter (filter->child_model, &root, filter->virtual_root) == FALSE)
+ return;
+ length = gtk_tree_model_iter_n_children (filter->child_model, &root);
+
+#ifdef VERBOSE
+ g_print ("-- vroot %d children\n", length);
+#endif
+
+ if (gtk_tree_model_iter_children (filter->child_model, &iter, &root) == FALSE)
+ return;
+ }
+ else
+ {
+ if (!gtk_tree_model_get_iter_first (filter->child_model, &iter))
+ return;
+ length = gtk_tree_model_iter_n_children (filter->child_model, NULL);
+ }
+ }
+ else
+ {
+ GtkTreeIter parent_iter;
+ GtkTreeIter child_parent_iter;
+
+ parent_iter.stamp = filter->stamp;
+ parent_iter.user_data = parent_level;
+ parent_iter.user_data2 = parent_elt;
+
+ egg_tree_model_filter_convert_iter_to_child_iter (filter,
+ &child_parent_iter,
+ &parent_iter);
+ if (gtk_tree_model_iter_children (filter->child_model, &iter, &child_parent_iter) == FALSE)
+ return;
+
+ /* stamp may have changed */
+ egg_tree_model_filter_convert_iter_to_child_iter (filter,
+ &child_parent_iter,
+ &parent_iter);
+ length = gtk_tree_model_iter_n_children (filter->child_model, &child_parent_iter);
+ }
+
+ g_return_if_fail (length > 0);
+
+#ifdef VERBOSE
+ g_print ("-- building new level with %d childs\n", length);
+#endif
+
+ new_level = g_new (FilterLevel, 1);
+ new_level->array = g_array_sized_new (FALSE, FALSE,
+ sizeof (FilterElt),
+ length);
+ new_level->ref_count = 0;
+ new_level->parent_elt = parent_elt;
+ new_level->parent_level = parent_level;
+
+ if (parent_elt)
+ parent_elt->children = new_level;
+ else
+ filter->root = new_level;
+
+ /* increase the count of zero ref_counts */
+ while (parent_level)
+ {
+ parent_elt->zero_ref_count++;
+
+ parent_elt = parent_level->parent_elt;
+ parent_level = parent_level->parent_level;
+ }
+ filter->zero_ref_count++;
+
+#ifdef VERBOSE
+ g_print ("_build_level: zero ref count on filter is now %d\n",
+ filter->zero_ref_count);
+#endif
+
+ i = 0;
+ do
+ {
+ if (egg_tree_model_filter_visible (filter, &iter))
+ {
+ FilterElt filter_elt;
+
+ filter_elt.offset = i;
+ filter_elt.zero_ref_count = 0;
+ filter_elt.ref_count = 0;
+ filter_elt.children = NULL;
+ filter_elt.visible = TRUE;
+
+ if (EGG_TREE_MODEL_FILTER_CACHE_CHILD_ITERS (filter))
+ filter_elt.iter = iter;
+
+ g_array_append_val (new_level->array, filter_elt);
+ }
+ i++;
+ }
+ while (gtk_tree_model_iter_next (filter->child_model, &iter));
+}
+
+static void
+egg_tree_model_filter_free_level (EggTreeModelFilter *filter,
+ FilterLevel *filter_level)
+{
+ gint i;
+
+ g_assert (filter_level);
+
+ if (filter_level->ref_count == 0)
+ {
+ FilterLevel *parent_level = filter_level->parent_level;
+ FilterElt *parent_elt = filter_level->parent_elt;
+
+ do
+ {
+ if (parent_elt)
+ parent_elt->zero_ref_count--;
+
+ if (parent_level)
+ {
+ parent_elt = parent_level->parent_elt;
+ parent_level = parent_level->parent_level;
+ }
+ }
+ while (parent_level);
+ filter->zero_ref_count--;
+ }
+
+#ifdef VERBOSE
+ g_print ("freeing level\n");
+ g_print ("zero ref count is %d\n", filter->zero_ref_count);
+#endif
+
+ for (i = 0; i < filter_level->array->len; i++)
+ {
+ if (g_array_index (filter_level->array, FilterElt, i).children)
+ egg_tree_model_filter_free_level (filter,
+ FILTER_LEVEL (g_array_index (filter_level->array, FilterElt, i).children));
+ }
+
+ if (filter_level->parent_elt)
+ filter_level->parent_elt->children = NULL;
+ else
+ filter->root = NULL;
+
+ g_array_free (filter_level->array, TRUE);
+ filter_level->array = NULL;
+
+ g_free (filter_level);
+ filter_level = NULL;
+}
+
+static GtkTreePath *
+egg_tree_model_filter_elt_get_path (FilterLevel *level,
+ FilterElt *elt,
+ GtkTreePath *root)
+{
+ FilterLevel *walker = level;
+ FilterElt *walker2 = elt;
+ GtkTreePath *path;
+ GtkTreePath *real_path;
+
+ g_return_val_if_fail (level != NULL, NULL);
+ g_return_val_if_fail (elt != NULL, NULL);
+
+ path = gtk_tree_path_new ();
+
+ while (walker)
+ {
+ gtk_tree_path_prepend_index (path, walker2->offset);
+
+ walker2 = walker->parent_elt;
+ walker = walker->parent_level;
+ }
+
+ if (root)
+ {
+ real_path = gtk_tree_path_copy (root);
+
+ egg_tree_model_filter_add_root (real_path, path);
+ gtk_tree_path_free (path);
+ return real_path;
+ }
+
+ return path;
+}
+
+static GtkTreePath *
+egg_tree_model_filter_add_root (GtkTreePath *src,
+ GtkTreePath *root)
+{
+ GtkTreePath *retval;
+ gint i;
+
+ retval = gtk_tree_path_copy (root);
+
+ for (i = 0; i < gtk_tree_path_get_depth (src); i++)
+ gtk_tree_path_append_index (retval, gtk_tree_path_get_indices (src)[i]);
+
+ return retval;
+}
+
+static GtkTreePath *
+egg_tree_model_filter_remove_root (GtkTreePath *src,
+ GtkTreePath *root)
+{
+ GtkTreePath *retval;
+ gint i;
+ gint depth;
+ gint *indices;
+
+ if (gtk_tree_path_get_depth (src) <= gtk_tree_path_get_depth (root))
+ return NULL;
+
+ depth = gtk_tree_path_get_depth (src);
+ indices = gtk_tree_path_get_indices (src);
+
+ for (i = 0; i < gtk_tree_path_get_depth (root); i++)
+ if (indices[i] != gtk_tree_path_get_indices (root)[i])
+ return NULL;
+
+ retval = gtk_tree_path_new ();
+
+ for (; i < depth; i++)
+ gtk_tree_path_append_index (retval, indices[i]);
+
+ return retval;
+}
+
+static void
+egg_tree_model_filter_increment_stamp (EggTreeModelFilter *filter)
+{
+ do
+ {
+ filter->stamp++;
+ }
+ while (filter->stamp == 0);
+
+ egg_tree_model_filter_clear_cache (filter);
+}
+
+static gboolean
+egg_tree_model_filter_visible (EggTreeModelFilter *filter,
+ GtkTreeIter *child_iter)
+{
+ if (filter->visible_func)
+ {
+ return (filter->visible_func (filter->child_model,
+ child_iter,
+ filter->visible_data));
+ }
+ else if (filter->visible_column >= 0)
+ {
+ GValue val = {0, };
+
+ gtk_tree_model_get_value (filter->child_model, child_iter,
+ filter->visible_column, &val);
+
+ if (g_value_get_boolean (&val))
+ {
+ g_value_unset (&val);
+ return TRUE;
+ }
+
+ g_value_unset (&val);
+ return FALSE;
+ }
+
+ /* no filter thing set, so always visible */
+ return TRUE;
+}
+
+static void
+egg_tree_model_filter_clear_cache_helper (EggTreeModelFilter *filter,
+ FilterLevel *level)
+{
+ gint i;
+
+ g_assert (level);
+
+ for (i = 0; i < level->array->len; i++)
+ {
+ if (g_array_index (level->array, FilterElt, i).zero_ref_count > 0)
+ egg_tree_model_filter_clear_cache_helper (filter, g_array_index (level->array, FilterElt, i).children);
+ }
+
+ if (level->ref_count == 0 && level != filter->root)
+ {
+ egg_tree_model_filter_free_level (filter, level);
+ return;
+ }
+}
+
+static gboolean
+egg_tree_model_filter_fetch_child (EggTreeModelFilter *filter,
+ FilterLevel *level,
+ gint offset)
+{
+ gint i = 0;
+ gint len;
+ GtkTreePath *c_path = NULL;
+ GtkTreeIter c_iter;
+ GtkTreePath *c_parent_path = NULL;
+ GtkTreeIter c_parent_iter;
+ FilterElt elt;
+
+#ifdef VERBOSE
+ g_print ("_fetch_child: for offset %d\n", offset);
+#endif
+
+ /* check if child exists and is visible */
+ if (level->parent_elt)
+ {
+ c_parent_path =
+ egg_tree_model_filter_elt_get_path (level->parent_level,
+ level->parent_elt,
+ filter->virtual_root);
+ if (!c_parent_path)
+ return FALSE;
+ }
+ else
+ {
+ if (filter->virtual_root)
+ c_parent_path = gtk_tree_path_copy (filter->virtual_root);
+ else
+ c_parent_path = NULL;
+ }
+
+ if (c_parent_path)
+ {
+ gtk_tree_model_get_iter (filter->child_model,
+ &c_parent_iter,
+ c_parent_path);
+ len = gtk_tree_model_iter_n_children (filter->child_model,
+ &c_parent_iter);
+
+ c_path = gtk_tree_path_copy (c_parent_path);
+ gtk_tree_path_free (c_parent_path);
+ }
+ else
+ {
+ len = gtk_tree_model_iter_n_children (filter->child_model, NULL);
+ c_path = gtk_tree_path_new ();
+ }
+
+ gtk_tree_path_append_index (c_path, offset);
+ gtk_tree_model_get_iter (filter->child_model, &c_iter, c_path);
+ gtk_tree_path_free (c_path);
+
+ if (offset >= len || !egg_tree_model_filter_visible (filter, &c_iter))
+ return FALSE;
+
+ /* add child */
+ elt.offset = offset;
+ elt.zero_ref_count = 0;
+ elt.ref_count = 0;
+ elt.children = NULL;
+ /* visibility should be FALSE as we don't emit row_inserted */
+ elt.visible = FALSE;
+
+ if (EGG_TREE_MODEL_FILTER_CACHE_CHILD_ITERS (filter))
+ elt.iter = c_iter;
+
+ /* find index */
+ for (i = 0; i < level->array->len; i++)
+ if (g_array_index (level->array, FilterElt, i).offset > offset)
+ break;
+
+ g_array_insert_val (level->array, i, elt);
+
+ for (i = 0; i < level->array->len; i++)
+ {
+ FilterElt *e = &(g_array_index (level->array, FilterElt, i));
+ if (e->children)
+ e->children->parent_elt = e;
+ }
+
+ return TRUE;
+}
+
+static void
+egg_tree_model_filter_remove_node (EggTreeModelFilter *filter,
+ GtkTreeIter *iter,
+ gboolean emit_signal)
+{
+ FilterElt *elt, *parent;
+ FilterLevel *level, *parent_level;
+ gint offset, i, length, level_refcount;
+
+ /* FIXME: this function is very ugly. I need to rethink and
+ * rewrite it someday.
+ */
+
+ level = FILTER_LEVEL (iter->user_data);
+ elt = FILTER_ELT (iter->user_data2);
+
+ parent = level->parent_elt;
+ parent_level = level->parent_level;
+ length = level->array->len;
+ offset = elt->offset;
+
+#ifdef VERBOSE
+ g_print ("|___ removing node\n");
+#endif
+
+ /* ref counting */
+ while (elt->ref_count > 0)
+ egg_tree_model_filter_real_unref_node (GTK_TREE_MODEL (filter),
+ iter, FALSE);
+
+ level_refcount = level->ref_count;
+
+ /* do the ref counting first! this touches the stamp */
+ if (emit_signal)
+ {
+ GtkTreePath *path;
+
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (filter), iter);
+ egg_tree_model_filter_increment_stamp (filter);
+ gtk_tree_model_row_deleted (GTK_TREE_MODEL (filter), path);
+ gtk_tree_path_free (path);
+ }
+
+ if ((length == 1 || level_refcount == 0) &&
+ emit_signal && iter->user_data != filter->root)
+ {
+ /* above code destroyed the level */
+ goto emit_has_child_toggled;
+ }
+
+ if (length == 1)
+ {
+ /* kill the level */
+#ifdef VERBOSE
+ g_print ("killing level ...\n");
+#endif
+ egg_tree_model_filter_free_level (filter, level);
+
+ if (!filter->root)
+ /* we killed the root */
+ return;
+ }
+ else
+ {
+#ifdef VERBOSE
+ g_print ("removing the node...\n");
+#endif
+
+ /* remove the node */
+ for (i = 0; i < level->array->len; i++)
+ if (elt->offset == g_array_index (level->array, FilterElt, i).offset)
+ break;
+
+ g_array_remove_index (level->array, i);
+
+ for (i = 0; i < level->array->len; i++)
+ {
+ /* NOTE: here we do *not* decrease offsets, because the node was
+ * not removed from the child model
+ */
+ elt = &g_array_index (level->array, FilterElt, i);
+ if (elt->children)
+ elt->children->parent_elt = elt;
+ }
+ }
+
+emit_has_child_toggled:
+ /* children are being handled first, so we can check it this way
+ *
+ * yes this if-statement is ugly
+ */
+ if ((parent && parent->children && parent->children->array->len <= 1) ||
+ (length == 1 && emit_signal && iter->user_data != filter->root))
+ {
+ /* latest child has been removed, level has been destroyed */
+ GtkTreeIter piter;
+ GtkTreePath *ppath;
+
+ piter.stamp = filter->stamp;
+ piter.user_data = parent_level;
+ piter.user_data2 = parent;
+
+ ppath = gtk_tree_model_get_path (GTK_TREE_MODEL (filter), &piter);
+
+#ifdef VERBOSE
+ g_print ("emitting has_child_toggled (by _filter_remove)\n");
+#endif
+
+ gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (filter),
+ ppath, &piter);
+ gtk_tree_path_free (ppath);
+ }
+}
+
+static void
+egg_tree_model_filter_update_childs (EggTreeModelFilter *filter,
+ FilterLevel *level,
+ FilterElt *elt)
+{
+ GtkTreeIter c_iter;
+ GtkTreeIter iter;
+
+#ifdef VERBOSE
+ g_print ("~~ a node came back, search childs\n");
+#endif
+
+ if (!elt->visible)
+ {
+#ifdef VERBOSE
+ g_print (" + given elt not visible -- bailing out\n");
+#endif
+ return;
+ }
+
+ iter.stamp = filter->stamp;
+ iter.user_data = level;
+ iter.user_data2 = elt;
+
+ egg_tree_model_filter_convert_iter_to_child_iter (filter, &c_iter, &iter);
+
+ if (gtk_tree_model_iter_has_child (filter->child_model, &c_iter))
+ {
+ GtkTreePath *path = gtk_tree_model_get_path (GTK_TREE_MODEL (filter),
+ &iter);
+ gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (filter),
+ path,
+ &iter);
+ if (path)
+ gtk_tree_path_free (path);
+ }
+}
+
+/* TreeModel signals */
+static void
+egg_tree_model_filter_row_changed (GtkTreeModel *c_model,
+ GtkTreePath *c_path,
+ GtkTreeIter *c_iter,
+ gpointer data)
+{
+ EggTreeModelFilter *filter = EGG_TREE_MODEL_FILTER (data);
+ GtkTreeIter iter;
+ GtkTreeIter real_c_iter;
+ GtkTreePath *path;
+
+ FilterElt *elt;
+ FilterLevel *level;
+ gint offset;
+
+ gboolean new;
+ gboolean free_c_path = FALSE;
+
+ g_return_if_fail (c_path != NULL || c_iter != NULL);
+
+ if (!c_path)
+ {
+ c_path = gtk_tree_model_get_path (c_model, c_iter);
+ free_c_path = TRUE;
+ }
+
+ if (c_iter)
+ real_c_iter = *c_iter;
+ else
+ gtk_tree_model_get_iter (c_model, &real_c_iter, c_path);
+
+ if (!filter->root)
+ {
+ gint i;
+ FilterLevel *root;
+
+ /* build root level */
+ egg_tree_model_filter_build_level (filter, NULL, NULL);
+
+ root = FILTER_LEVEL (filter->root);
+
+ /* FIXME:
+ * we set the visibilities to FALSE here, so we ever emit
+ * a row_inserted. maybe it's even better to emit row_inserted
+ * here, not sure.
+ */
+ if (root)
+ for (i = 0; i < root->array->len; i++)
+ g_array_index (root->array, FilterElt, i).visible = FALSE;
+ }
+
+ path = egg_real_tree_model_filter_convert_child_path_to_path (filter,
+ c_path,
+ FALSE,
+ TRUE);
+ if (!path)
+ goto done;
+
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (filter), &iter, path);
+
+ level = FILTER_LEVEL (iter.user_data);
+ elt = FILTER_ELT (iter.user_data2);
+ offset = elt->offset;
+ new = egg_tree_model_filter_visible (filter, c_iter);
+
+ if (elt->visible == TRUE && new == FALSE)
+ {
+#ifdef VERBOSE
+ g_print ("visible to false -> delete row\n");
+#endif
+ egg_tree_model_filter_remove_node (filter, &iter, TRUE);
+ }
+ else if (elt->visible == FALSE && new == TRUE)
+ {
+ GtkTreeIter childs;
+
+#ifdef VERBOSE
+ g_print ("visible to true -> insert row\n");
+#endif
+
+ elt->visible = TRUE;
+
+ egg_tree_model_filter_increment_stamp (filter);
+ /* update stamp */
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (filter), &iter, path);
+ gtk_tree_model_row_inserted (GTK_TREE_MODEL (filter), path, &iter);
+
+ if (gtk_tree_model_iter_children (c_model, &childs, c_iter))
+ egg_tree_model_filter_update_childs (filter, level, elt);
+ }
+ else if (elt->visible == FALSE && new == FALSE)
+ {
+#ifdef VERBOSE
+ g_print ("remove node in silence\n");
+#endif
+ egg_tree_model_filter_remove_node (filter, &iter, FALSE);
+ }
+ else
+ {
+ GtkTreeIter childs;
+
+#ifdef VERBOSE
+ g_print ("no change in visibility -- pass row_changed\n");
+#endif
+
+ gtk_tree_model_row_changed (GTK_TREE_MODEL (filter), path, &iter);
+
+ if (gtk_tree_model_iter_children (c_model, &childs, c_iter) &&
+ elt->visible)
+ egg_tree_model_filter_update_childs (filter, level, elt);
+ }
+
+ gtk_tree_path_free (path);
+
+done:
+ if (free_c_path)
+ gtk_tree_path_free (c_path);
+}
+
+static void
+egg_tree_model_filter_row_inserted (GtkTreeModel *c_model,
+ GtkTreePath *c_path,
+ GtkTreeIter *c_iter,
+ gpointer data)
+{
+ EggTreeModelFilter *filter = EGG_TREE_MODEL_FILTER (data);
+ GtkTreePath *path;
+ GtkTreePath *real_path;
+ GtkTreeIter iter;
+
+ GtkTreeIter real_c_iter;
+
+ FilterElt *elt;
+ FilterLevel *level;
+ FilterLevel *parent_level;
+
+ gint i = 0, offset, index = -1;
+
+ gboolean free_c_path = FALSE;
+
+ g_return_if_fail (c_path != NULL || c_iter != NULL);
+
+ if (!c_path)
+ {
+ c_path = gtk_tree_model_get_path (c_model, c_iter);
+ free_c_path = TRUE;
+ }
+
+ if (c_iter)
+ real_c_iter = *c_iter;
+ else
+ gtk_tree_model_get_iter (c_model, &real_c_iter, c_path);
+
+ /* the row has already been inserted. so we need to fixup the
+ * virtual root here first
+ */
+ if (filter->virtual_root)
+ {
+ if (gtk_tree_path_get_depth (filter->virtual_root) >=
+ gtk_tree_path_get_depth (c_path))
+ {
+ gint level;
+ gint *v_indices, *c_indices;
+
+ level = gtk_tree_path_get_depth (c_path) - 1;
+ v_indices = gtk_tree_path_get_indices (filter->virtual_root);
+ c_indices = gtk_tree_path_get_indices (c_path);
+
+ if (v_indices[level] >= c_indices[level])
+ (v_indices[level])++;
+ }
+ }
+
+ if (!filter->root)
+ {
+ egg_tree_model_filter_build_level (filter, NULL, NULL);
+ /* that already put the inserted iter in the level */
+
+ goto done_and_emit;
+ }
+
+ parent_level = level = FILTER_LEVEL (filter->root);
+
+ /* subtract virtual root if necessary */
+ if (filter->virtual_root)
+ {
+ real_path = egg_tree_model_filter_remove_root (c_path,
+ filter->virtual_root);
+ /* not our kiddo */
+ if (!real_path)
+ goto done;
+ }
+ else
+ real_path = gtk_tree_path_copy (c_path);
+
+ if (gtk_tree_path_get_depth (real_path) - 1 >= 1)
+ {
+ /* find the parent level */
+ while (i < gtk_tree_path_get_depth (real_path) - 1)
+ {
+ gint j;
+
+ if (!level)
+ /* we don't cover this signal */
+ goto done;
+
+ elt = NULL;
+ for (j = 0; j < level->array->len; j++)
+ if (g_array_index (level->array, FilterElt, j).offset ==
+ gtk_tree_path_get_indices (real_path)[i])
+ {
+ elt = &g_array_index (level->array, FilterElt, j);
+ break;
+ }
+
+ if (!elt)
+ /* parent is probably being filtered out */
+ goto done;
+
+ if (!elt->children)
+ {
+ GtkTreePath *tmppath;
+ GtkTreeIter tmpiter;
+
+ tmpiter.stamp = filter->stamp;
+ tmpiter.user_data = level;
+ tmpiter.user_data2 = elt;
+
+ tmppath = gtk_tree_model_get_path (GTK_TREE_MODEL (data),
+ &tmpiter);
+
+ if (tmppath)
+ {
+ gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (data),
+ tmppath, &tmpiter);
+ gtk_tree_path_free (tmppath);
+ }
+
+ /* not covering this signal */
+ goto done;
+ }
+
+ level = elt->children;
+ parent_level = level;
+ i++;
+ }
+ }
+
+ if (!parent_level)
+ goto done;
+
+ /* let's try to insert the value */
+ offset = gtk_tree_path_get_indices (real_path)[gtk_tree_path_get_depth (real_path) - 1];
+
+ /* only insert when visible */
+ if (egg_tree_model_filter_visible (filter, &real_c_iter))
+ {
+ FilterElt felt;
+
+ if (EGG_TREE_MODEL_FILTER_CACHE_CHILD_ITERS (filter))
+ felt.iter = real_c_iter;
+ felt.offset = offset;
+ felt.zero_ref_count = 0;
+ felt.ref_count = 0;
+ felt.visible = TRUE;
+ felt.children = NULL;
+
+ for (i = 0; i < level->array->len; i++)
+ if (g_array_index (level->array, FilterElt, i).offset > offset)
+ break;
+
+ g_array_insert_val (level->array, i, felt);
+ index = i;
+ }
+
+ /* update the offsets, yes if we didn't insert the node above, there will
+ * be a gap here. This will be filled with the node (via fetch_child) when
+ * it becomes visible
+ */
+ for (i = 0; i < level->array->len; i++)
+ {
+ FilterElt *e = &g_array_index (level->array, FilterElt, i);
+ if ((e->offset >= offset) && i != index)
+ e->offset++;
+ if (e->children)
+ e->children->parent_elt = e;
+ }
+
+ /* don't emit the signal if we aren't visible */
+ if (!egg_tree_model_filter_visible (filter, &real_c_iter))
+ goto done;
+
+done_and_emit:
+ /* NOTE: pass c_path here and NOT real_path. This function does
+ * root subtraction itself
+ */
+ path = egg_real_tree_model_filter_convert_child_path_to_path (filter,
+ c_path,
+ FALSE, TRUE);
+
+ if (!path)
+ return;
+
+ egg_tree_model_filter_increment_stamp (filter);
+
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (data), &iter, path);
+ gtk_tree_model_row_inserted (GTK_TREE_MODEL (data), path, &iter);
+
+#ifdef VERBOSE
+ g_print ("inserted row with offset %d\n", index);
+#endif
+
+done:
+ if (free_c_path)
+ gtk_tree_path_free (c_path);
+}
+
+static void
+egg_tree_model_filter_row_has_child_toggled (GtkTreeModel *c_model,
+ GtkTreePath *c_path,
+ GtkTreeIter *c_iter,
+ gpointer data)
+{
+ EggTreeModelFilter *filter = EGG_TREE_MODEL_FILTER (data);
+ GtkTreePath *path;
+ GtkTreeIter iter;
+
+ g_return_if_fail (c_path != NULL && c_iter != NULL);
+
+ /* FIXME: does this code work? */
+
+ if (!egg_tree_model_filter_visible (filter, c_iter))
+ return;
+
+ path = egg_real_tree_model_filter_convert_child_path_to_path (filter,
+ c_path,
+ FALSE,
+ TRUE);
+ if (!path)
+ return;
+
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (data), &iter, path);
+ gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (data), path, &iter);
+
+ gtk_tree_path_free (path);
+}
+
+static void
+egg_tree_model_filter_row_deleted (GtkTreeModel *c_model,
+ GtkTreePath *c_path,
+ gpointer data)
+{
+ EggTreeModelFilter *filter = EGG_TREE_MODEL_FILTER (data);
+ GtkTreePath *path;
+ GtkTreeIter iter;
+ FilterElt *elt;
+ FilterLevel *level;
+ gint offset;
+ gboolean emit_signal = TRUE;
+ gint i;
+
+ g_return_if_fail (c_path != NULL);
+
+ /* special case the deletion of an ancestor of the virtual root */
+ if (filter->virtual_root &&
+ (gtk_tree_path_is_ancestor (c_path, filter->virtual_root) ||
+ !gtk_tree_path_compare (c_path, filter->virtual_root)))
+ {
+ gint i;
+ GtkTreePath *path;
+ FilterLevel *level = FILTER_LEVEL (filter->root);
+
+ if (!level)
+ return;
+
+ /* remove everything in the filter model
+ *
+ * For now, we just iterate over the root level and emit a
+ * row_deleted for each FilterElt. Not sure if this is correct.
+ */
+
+ egg_tree_model_filter_increment_stamp (filter);
+ path = gtk_tree_path_new ();
+ gtk_tree_path_append_index (path, 0);
+
+ for (i = 0; i < level->array->len; i++)
+ gtk_tree_model_row_deleted (GTK_TREE_MODEL (data), path);
+
+ gtk_tree_path_free (path);
+ egg_tree_model_filter_free_level (filter, filter->root);
+
+ return;
+ }
+
+ /* fixup virtual root */
+ if (filter->virtual_root)
+ {
+ if (gtk_tree_path_get_depth (filter->virtual_root) >=
+ gtk_tree_path_get_depth (c_path))
+ {
+ gint level;
+ gint *v_indices, *c_indices;
+
+ level = gtk_tree_path_get_depth (c_path) - 1;
+ v_indices = gtk_tree_path_get_indices (filter->virtual_root);
+ c_indices = gtk_tree_path_get_indices (c_path);
+
+ if (v_indices[level] > c_indices[level])
+ (v_indices[level])--;
+ }
+ }
+
+ path = egg_real_tree_model_filter_convert_child_path_to_path (filter,
+ c_path,
+ FALSE,
+ FALSE);
+ if (!path)
+ {
+ path = egg_real_tree_model_filter_convert_child_path_to_path (filter,
+ c_path,
+ FALSE,
+ TRUE);
+
+ if (!path)
+ {
+ /* fixup the offsets */
+ GtkTreePath *real_path;
+
+ if (!filter->root)
+ return;
+
+ level = FILTER_LEVEL (filter->root);
+
+ /* subtract vroot if necessary */
+ if (filter->virtual_root)
+ {
+ real_path = egg_tree_model_filter_remove_root (c_path,
+ filter->virtual_root);
+ /* we don't handle this */
+ if (!real_path)
+ return;
+ }
+ else
+ real_path = gtk_tree_path_copy (c_path);
+
+ i = 0;
+ if (gtk_tree_path_get_depth (real_path) - 1 >= 1)
+ {
+ while (i < gtk_tree_path_get_depth (real_path) - 1)
+ {
+ gint j;
+
+ if (!level)
+ {
+ /* we don't cover this */
+ gtk_tree_path_free (real_path);
+ return;
+ }
+
+ elt = NULL;
+ for (j = 0; j < level->array->len; j++)
+ if (g_array_index (level->array, FilterElt, j).offset ==
+ gtk_tree_path_get_indices (real_path)[i])
+ {
+ elt = &g_array_index (level->array, FilterElt, j);
+ break;
+ }
+
+ if (!elt || !elt->children)
+ {
+ /* parent is filtered out, so no level */
+ gtk_tree_path_free (real_path);
+ return;
+ }
+
+ level = elt->children;
+ i++;
+ }
+ }
+
+ offset = gtk_tree_path_get_indices (real_path)[gtk_tree_path_get_depth (real_path) - 1];
+ gtk_tree_path_free (real_path);
+
+ if (!level)
+ return;
+
+ /* we need:
+ * - the offset of the removed item
+ * - the level
+ */
+ for (i = 0; i < level->array->len; i++)
+ {
+ elt = &g_array_index (level->array, FilterElt, i);
+ if (elt->offset > offset)
+ elt->offset--;
+ if (elt->children)
+ elt->children->parent_elt = elt;
+ }
+
+ return;
+ }
+
+ emit_signal = FALSE;
+ }
+
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (data), &iter, path);
+
+ level = FILTER_LEVEL (iter.user_data);
+ elt = FILTER_ELT (iter.user_data2);
+ offset = elt->offset;
+
+ if (emit_signal)
+ {
+ if (level->ref_count == 0 && level != filter->root)
+ {
+ egg_tree_model_filter_increment_stamp (filter);
+ gtk_tree_model_row_deleted (GTK_TREE_MODEL (data), path);
+
+ gtk_tree_path_free (path);
+ return;
+ }
+
+ egg_tree_model_filter_increment_stamp (filter);
+ gtk_tree_model_row_deleted (GTK_TREE_MODEL (data), path);
+ iter.stamp = filter->stamp;
+
+ while (elt->ref_count > 0)
+ egg_tree_model_filter_real_unref_node (GTK_TREE_MODEL (data), &iter,
+ FALSE);
+ }
+
+ if (level->array->len == 1)
+ {
+ /* kill level */
+ egg_tree_model_filter_free_level (filter, level);
+ }
+ else
+ {
+ /* remove the row */
+ for (i = 0; i < level->array->len; i++)
+ if (elt->offset == g_array_index (level->array, FilterElt, i).offset)
+ break;
+
+ offset = g_array_index (level->array, FilterElt, i).offset;
+ g_array_remove_index (level->array, i);
+
+ for (i = 0; i < level->array->len; i++)
+ {
+ elt = &g_array_index (level->array, FilterElt, i);
+ if (elt->offset > offset)
+ elt->offset--;
+ if (elt->children)
+ elt->children->parent_elt = elt;
+ }
+ }
+
+ gtk_tree_path_free (path);
+}
+
+static void
+egg_tree_model_filter_rows_reordered (GtkTreeModel *c_model,
+ GtkTreePath *c_path,
+ GtkTreeIter *c_iter,
+ gint *new_order,
+ gpointer data)
+{
+ FilterElt *elt;
+ FilterLevel *level;
+ EggTreeModelFilter *filter = EGG_TREE_MODEL_FILTER (data);
+
+ GtkTreePath *path;
+ GtkTreeIter iter;
+
+ gint *tmp_array;
+ gint i, j, elt_count;
+ gint length;
+
+ GArray *new_array;
+
+ g_return_if_fail (new_order != NULL);
+
+#ifdef VERBOSE
+ g_print ("filter: reordering\n");
+#endif
+
+ if (c_path == NULL || gtk_tree_path_get_indices (c_path) == NULL)
+ {
+ if (!filter->root)
+ return;
+
+ length = gtk_tree_model_iter_n_children (c_model, NULL);
+
+ if (filter->virtual_root)
+ {
+ gint new_pos = -1;
+
+ /* reorder root level of path */
+ for (i = 0; i < length; i++)
+ if (new_order[i] == gtk_tree_path_get_indices (filter->virtual_root)[0])
+ new_pos = i;
+
+ if (new_pos < 0)
+ return;
+
+ gtk_tree_path_get_indices (filter->virtual_root)[0] = new_pos;
+ return;
+ }
+
+ path = gtk_tree_path_new ();
+ level = FILTER_LEVEL (filter->root);
+ }
+ else
+ {
+ GtkTreeIter child_iter;
+
+ /* virtual root anchor reordering */
+ if (filter->virtual_root &&
+ gtk_tree_path_get_depth (c_path) <
+ gtk_tree_path_get_depth (filter->virtual_root))
+ {
+ gint new_pos = -1;
+ gint length;
+ gint level;
+ GtkTreeIter real_c_iter;
+
+ level = gtk_tree_path_get_depth (c_path);
+
+ if (c_iter)
+ real_c_iter = *c_iter;
+ else
+ gtk_tree_model_get_iter (c_model, &real_c_iter, c_path);
+
+ length = gtk_tree_model_iter_n_children (c_model, &real_c_iter);
+
+ for (i = 0; i < length; i++)
+ if (new_order[i] == gtk_tree_path_get_indices (filter->virtual_root)[level])
+ new_pos = i;
+
+ if (new_pos < 0)
+ return;
+
+ gtk_tree_path_get_indices (filter->virtual_root)[level] = new_pos;
+ return;
+ }
+
+ path = egg_real_tree_model_filter_convert_child_path_to_path (filter,
+ c_path,
+ FALSE,
+ FALSE);
+ if (!path && filter->virtual_root &&
+ gtk_tree_path_compare (c_path, filter->virtual_root))
+ return;
+
+ if (!path && !filter->virtual_root)
+ return;
+
+ if (!path)
+ {
+ /* root level mode */
+ if (!c_iter)
+ gtk_tree_model_get_iter (c_model, c_iter, c_path);
+ length = gtk_tree_model_iter_n_children (c_model, c_iter);
+ path = gtk_tree_path_new ();
+ level = FILTER_LEVEL (filter->root);
+ }
+ else
+ {
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (data), &iter, path);
+
+ level = FILTER_LEVEL (iter.user_data);
+ elt = FILTER_ELT (iter.user_data2);
+
+ if (!elt->children)
+ {
+ gtk_tree_path_free (path);
+ return;
+ }
+
+ level = elt->children;
+
+ egg_tree_model_filter_convert_iter_to_child_iter (EGG_TREE_MODEL_FILTER (filter), &child_iter, &iter);
+ length = gtk_tree_model_iter_n_children (c_model, &child_iter);
+ }
+ }
+
+ if (level->array->len < 1)
+ return;
+
+ /* NOTE: we do not bail out here if level->array->len < 2 like
+ * GtkTreeModelSort does. This because we do some special tricky
+ * reordering.
+ */
+
+ /* construct a new array */
+ new_array = g_array_sized_new (FALSE, FALSE, sizeof (FilterElt),
+ level->array->len);
+ tmp_array = g_new (gint, level->array->len);
+
+ for (i = 0, elt_count = 0; i < length; i++)
+ {
+ FilterElt *e = NULL;
+ gint old_offset = -1;
+
+ for (j = 0; j < level->array->len; j++)
+ if (g_array_index (level->array, FilterElt, j).offset == new_order[i])
+ {
+ e = &g_array_index (level->array, FilterElt, j);
+ old_offset = j;
+ break;
+ }
+
+ if (!e)
+ continue;
+
+ tmp_array[elt_count] = old_offset;
+ g_array_append_val (new_array, *e);
+ g_array_index (new_array, FilterElt, elt_count).offset = i;
+ elt_count++;
+ }
+
+ g_array_free (level->array, TRUE);
+ level->array = new_array;
+
+ /* fix up stuff */
+ for (i = 0; i < level->array->len; i++)
+ {
+ FilterElt *e = &g_array_index (level->array, FilterElt, i);
+ if (e->children)
+ e->children->parent_elt = e;
+ }
+
+ /* emit rows_reordered */
+ if (!gtk_tree_path_get_indices (path))
+ gtk_tree_model_rows_reordered (GTK_TREE_MODEL (data), path, NULL,
+ tmp_array);
+ else
+ gtk_tree_model_rows_reordered (GTK_TREE_MODEL (data), path, &iter,
+ tmp_array);
+
+ /* done */
+ g_free (tmp_array);
+ gtk_tree_path_free (path);
+}
+
+/* TreeModelIface implementation */
+static guint
+egg_tree_model_filter_get_flags (GtkTreeModel *model)
+{
+ g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model), 0);
+
+ return 0;
+}
+
+static gint
+egg_tree_model_filter_get_n_columns (GtkTreeModel *model)
+{
+ EggTreeModelFilter *filter = (EggTreeModelFilter *)model;
+
+ g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model), 0);
+ g_return_val_if_fail (filter->child_model != NULL, 0);
+
+ if (filter->child_model == NULL)
+ return 0;
+
+ /* so we can't modify the modify func after this ... */
+ filter->modify_func_set = TRUE;
+
+ if (filter->modify_n_columns > 0)
+ return filter->modify_n_columns;
+
+ return gtk_tree_model_get_n_columns (filter->child_model);
+}
+
+static GType
+egg_tree_model_filter_get_column_type (GtkTreeModel *model,
+ gint index)
+{
+ EggTreeModelFilter *filter = (EggTreeModelFilter *)model;
+
+ g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model), G_TYPE_INVALID);
+ g_return_val_if_fail (filter->child_model != NULL, G_TYPE_INVALID);
+
+ /* so we can't modify the modify func after this ... */
+ filter->modify_func_set = TRUE;
+
+ if (filter->modify_types)
+ {
+ g_return_val_if_fail (index < filter->modify_n_columns, G_TYPE_INVALID);
+
+ return filter->modify_types[index];
+ }
+
+ return gtk_tree_model_get_column_type (filter->child_model, index);
+}
+
+static gboolean
+egg_tree_model_filter_get_iter (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ GtkTreePath *path)
+{
+ EggTreeModelFilter *filter = (EggTreeModelFilter *)model;
+ gint *indices;
+ FilterLevel *level;
+ gint depth, i;
+
+ g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model), FALSE);
+ g_return_val_if_fail (filter->child_model != NULL, FALSE);
+
+ indices = gtk_tree_path_get_indices (path);
+
+ if (filter->root == NULL)
+ egg_tree_model_filter_build_level (filter, NULL, NULL);
+ level = FILTER_LEVEL (filter->root);
+
+ depth = gtk_tree_path_get_depth (path);
+ if (!depth)
+ {
+ iter->stamp = 0;
+ return FALSE;
+ }
+
+ for (i = 0; i < depth - 1; i++)
+ {
+ if (!level || indices[i] >= level->array->len)
+ {
+ return FALSE;
+ }
+
+ if (!g_array_index (level->array, FilterElt, indices[i]).children)
+ egg_tree_model_filter_build_level (filter, level,
+ &g_array_index (level->array,
+ FilterElt,
+ indices[i]));
+ level = g_array_index (level->array, FilterElt, indices[i]).children;
+ }
+
+ if (!level || indices[i] >= level->array->len)
+ {
+ iter->stamp = 0;
+ return FALSE;
+ }
+
+ iter->stamp = filter->stamp;
+ iter->user_data = level;
+ iter->user_data2 = &g_array_index (level->array, FilterElt,
+ indices[depth - 1]);
+
+ return TRUE;
+}
+
+static GtkTreePath *
+egg_tree_model_filter_get_path (GtkTreeModel *model,
+ GtkTreeIter *iter)
+{
+ GtkTreePath *retval;
+ FilterLevel *level;
+ FilterElt *elt;
+
+ g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model), NULL);
+ g_return_val_if_fail (EGG_TREE_MODEL_FILTER (model)->child_model != NULL, NULL);
+ g_return_val_if_fail (EGG_TREE_MODEL_FILTER (model)->stamp == iter->stamp, NULL);
+
+ retval = gtk_tree_path_new ();
+ level = iter->user_data;
+ elt = iter->user_data2;
+
+ while (level)
+ {
+ gtk_tree_path_prepend_index (retval,
+ elt - FILTER_ELT (level->array->data));
+ elt = level->parent_elt;
+ level = level->parent_level;
+ }
+
+ return retval;
+}
+
+static void
+egg_tree_model_filter_get_value (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gint column,
+ GValue *value)
+{
+ GtkTreeIter child_iter;
+ EggTreeModelFilter *filter = EGG_TREE_MODEL_FILTER (model);
+
+ g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (model));
+ g_return_if_fail (EGG_TREE_MODEL_FILTER (model)->child_model != NULL);
+ g_return_if_fail (EGG_TREE_MODEL_FILTER (model)->stamp == iter->stamp);
+
+ if (filter->modify_func)
+ {
+ g_return_if_fail (column < filter->modify_n_columns);
+
+ g_value_init (value, filter->modify_types[column]);
+ filter->modify_func (model,
+ iter,
+ value,
+ column,
+ filter->modify_data);
+
+ return;
+ }
+
+ egg_tree_model_filter_convert_iter_to_child_iter (EGG_TREE_MODEL_FILTER (model), &child_iter, iter);
+ gtk_tree_model_get_value (EGG_TREE_MODEL_FILTER (model)->child_model,
+ &child_iter, column, value);
+}
+
+static gboolean
+egg_tree_model_filter_iter_next (GtkTreeModel *model,
+ GtkTreeIter *iter)
+{
+ FilterLevel *level;
+ FilterElt *elt;
+
+ g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model), FALSE);
+ g_return_val_if_fail (EGG_TREE_MODEL_FILTER (model)->child_model != NULL, FALSE);
+ g_return_val_if_fail (EGG_TREE_MODEL_FILTER (model)->stamp == iter->stamp, FALSE);
+
+ level = iter->user_data;
+ elt = iter->user_data2;
+
+ if (elt - FILTER_ELT (level->array->data) >= level->array->len - 1)
+ {
+ iter->stamp = 0;
+ return FALSE;
+ }
+
+ iter->user_data2 = elt + 1;
+
+ return TRUE;
+}
+
+static gboolean
+egg_tree_model_filter_iter_children (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ GtkTreeIter *parent)
+{
+ EggTreeModelFilter *filter = (EggTreeModelFilter *)model;
+ FilterLevel *level;
+
+ iter->stamp = 0;
+ g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model), FALSE);
+ g_return_val_if_fail (filter->child_model != NULL, FALSE);
+ if (parent)
+ g_return_val_if_fail (filter->stamp == parent->stamp, FALSE);
+
+ if (!parent)
+ {
+ if (!filter->root)
+ egg_tree_model_filter_build_level (filter, NULL, NULL);
+ if (!filter->root)
+ return FALSE;
+
+ level = filter->root;
+ iter->stamp = filter->stamp;
+ iter->user_data = level;
+ iter->user_data2 = level->array->data;
+ }
+ else
+ {
+ if (FILTER_ELT (parent->user_data2)->children == NULL)
+ egg_tree_model_filter_build_level (filter,
+ FILTER_LEVEL (parent->user_data),
+ FILTER_ELT (parent->user_data2));
+ if (FILTER_ELT (parent->user_data2)->children == NULL)
+ return FALSE;
+
+ iter->stamp = filter->stamp;
+ iter->user_data = FILTER_ELT (parent->user_data2)->children;
+ iter->user_data2 = FILTER_LEVEL (iter->user_data)->array->data;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+egg_tree_model_filter_iter_has_child (GtkTreeModel *model,
+ GtkTreeIter *iter)
+{
+ GtkTreeIter child_iter;
+ EggTreeModelFilter *filter = (EggTreeModelFilter *)model;
+ FilterElt *elt;
+
+ g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model), FALSE);
+ g_return_val_if_fail (filter->child_model != NULL, FALSE);
+ g_return_val_if_fail (filter->stamp == iter->stamp, FALSE);
+
+ filter = EGG_TREE_MODEL_FILTER (model);
+
+ egg_tree_model_filter_convert_iter_to_child_iter (EGG_TREE_MODEL_FILTER (model), &child_iter, iter);
+ elt = FILTER_ELT (iter->user_data2);
+
+ /* we need to build the level to check if not all children are filtered
+ * out
+ */
+ if (!elt->children
+ && gtk_tree_model_iter_has_child (filter->child_model, &child_iter))
+ egg_tree_model_filter_build_level (filter, FILTER_LEVEL (iter->user_data),
+ elt);
+
+ if (elt->children && elt->children->array->len > 0)
+ return TRUE;
+
+ return FALSE;
+}
+
+static gint
+egg_tree_model_filter_iter_n_children (GtkTreeModel *model,
+ GtkTreeIter *iter)
+{
+ GtkTreeIter child_iter;
+ EggTreeModelFilter *filter = (EggTreeModelFilter *)model;
+ FilterElt *elt;
+
+ g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model), 0);
+ g_return_val_if_fail (filter->child_model != NULL, 0);
+ if (iter)
+ g_return_val_if_fail (filter->stamp == iter->stamp, 0);
+
+ if (!iter)
+ {
+ int i = 0;
+ int count = 0;
+ GArray *a;
+
+ if (!filter->root)
+ egg_tree_model_filter_build_level (filter, NULL, NULL);
+
+ a = FILTER_LEVEL (filter->root)->array;
+
+ /* count visible nodes */
+
+ for (i = 0; i < a->len; i++)
+ if (g_array_index (a, FilterElt, i).visible)
+ count++;
+
+ return count;
+ }
+
+ elt = FILTER_ELT (iter->user_data2);
+ egg_tree_model_filter_convert_iter_to_child_iter (EGG_TREE_MODEL_FILTER (model), &child_iter, iter);
+
+ if (!elt->children &&
+ gtk_tree_model_iter_has_child (filter->child_model, &child_iter))
+ egg_tree_model_filter_build_level (filter,
+ FILTER_LEVEL (iter->user_data),
+ elt);
+
+ if (elt->children && elt->children->array->len)
+ {
+ int i = 0;
+ int count = 0;
+ GArray *a = elt->children->array;
+
+ /* count visible nodes */
+
+ for (i = 0; i < a->len; i++)
+ if (g_array_index (a, FilterElt, i).visible)
+ count++;
+
+ return count;
+ }
+
+ return 0;
+}
+
+static gboolean
+egg_tree_model_filter_iter_nth_child (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ GtkTreeIter *parent,
+ gint n)
+{
+ FilterLevel *level;
+ GtkTreeIter children;
+
+ g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model), FALSE);
+ if (parent)
+ g_return_val_if_fail (EGG_TREE_MODEL_FILTER (model)->stamp == parent->stamp, FALSE);
+
+ /* use this instead of has_Child to force us to build the level, if needed */
+ if (egg_tree_model_filter_iter_children (model, &children, parent) == FALSE)
+ {
+ iter->stamp = 0;
+ return FALSE;
+ }
+
+ level = children.user_data;
+ if (n >= level->array->len)
+ {
+ iter->stamp = 0;
+ return FALSE;
+ }
+
+ iter->stamp = EGG_TREE_MODEL_FILTER (model)->stamp;
+ iter->user_data = level;
+ iter->user_data2 = &g_array_index (level->array, FilterElt, n);
+
+ return TRUE;
+}
+
+static gboolean
+egg_tree_model_filter_iter_parent (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ GtkTreeIter *child)
+{
+ FilterLevel *level;
+
+ iter->stamp = 0;
+ g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (model), FALSE);
+ g_return_val_if_fail (EGG_TREE_MODEL_FILTER (model)->child_model != NULL, FALSE);
+ g_return_val_if_fail (EGG_TREE_MODEL_FILTER (model)->stamp == child->stamp, FALSE);
+
+ level = child->user_data;
+
+ if (level->parent_level)
+ {
+ iter->stamp = EGG_TREE_MODEL_FILTER (model)->stamp;
+ iter->user_data = level->parent_level;
+ iter->user_data2 = level->parent_elt;
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+egg_tree_model_filter_ref_node (GtkTreeModel *model,
+ GtkTreeIter *iter)
+{
+ EggTreeModelFilter *filter = (EggTreeModelFilter *)model;
+ GtkTreeIter child_iter;
+ FilterLevel *level;
+ FilterElt *elt;
+
+ g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (model));
+ g_return_if_fail (EGG_TREE_MODEL_FILTER (model)->child_model != NULL);
+ g_return_if_fail (EGG_TREE_MODEL_FILTER (model)->stamp == iter->stamp);
+
+ egg_tree_model_filter_convert_iter_to_child_iter (EGG_TREE_MODEL_FILTER (model), &child_iter, iter);
+
+ gtk_tree_model_ref_node (filter->child_model, &child_iter);
+
+ level = iter->user_data;
+ elt = iter->user_data2;
+
+ elt->ref_count++;
+ level->ref_count++;
+ if (level->ref_count == 1)
+ {
+ FilterLevel *parent_level = level->parent_level;
+ FilterElt *parent_elt = level->parent_elt;
+
+ /* we were at zero -- time to decrease the zero_ref_count val */
+ do
+ {
+ if (parent_elt)
+ parent_elt->zero_ref_count--;
+
+ if (parent_level)
+ {
+ parent_elt = parent_level->parent_elt;
+ parent_level = parent_level->parent_level;
+ }
+ }
+ while (parent_level);
+ filter->zero_ref_count--;
+ }
+
+#ifdef VERBOSE
+ g_print ("reffed %p\n", iter->user_data2);
+ g_print ("zero ref count is now %d\n", filter->zero_ref_count);
+ if (filter->zero_ref_count < 0)
+ g_warning ("zero_ref_count < 0.");
+#endif
+}
+
+static void
+egg_tree_model_filter_unref_node (GtkTreeModel *model,
+ GtkTreeIter *iter)
+{
+ egg_tree_model_filter_real_unref_node (model, iter, TRUE);
+}
+
+static void
+egg_tree_model_filter_real_unref_node (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gboolean propagate_unref)
+{
+ EggTreeModelFilter *filter = (EggTreeModelFilter *)model;
+ FilterLevel *level;
+ FilterElt *elt;
+
+ g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (model));
+ g_return_if_fail (filter->child_model != NULL);
+ g_return_if_fail (filter->stamp == iter->stamp);
+
+ if (propagate_unref)
+ {
+ GtkTreeIter child_iter;
+ egg_tree_model_filter_convert_iter_to_child_iter (EGG_TREE_MODEL_FILTER (model), &child_iter, iter);
+ gtk_tree_model_unref_node (filter->child_model, &child_iter);
+ }
+
+ level = iter->user_data;
+ elt = iter->user_data2;
+
+ g_return_if_fail (elt->ref_count > 0);
+
+ elt->ref_count--;
+ level->ref_count--;
+ if (level->ref_count == 0)
+ {
+ FilterLevel *parent_level = level->parent_level;
+ FilterElt *parent_elt = level->parent_elt;
+
+ /* we are at zero -- time to increase the zero_ref_count val */
+ while (parent_level)
+ {
+ parent_elt->zero_ref_count++;
+
+ parent_elt = parent_level->parent_elt;
+ parent_level = parent_level->parent_level;
+ }
+ filter->zero_ref_count++;
+ }
+
+#ifdef VERBOSE
+ g_print ("unreffed %p\n", iter->user_data2);
+ g_print ("zero ref count is now %d\n", filter->zero_ref_count);
+#endif
+}
+
+/* bits and pieces */
+static void
+egg_tree_model_filter_set_model (EggTreeModelFilter *filter,
+ GtkTreeModel *child_model)
+{
+ g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (filter));
+
+ if (filter->child_model)
+ {
+ g_signal_handler_disconnect (G_OBJECT (filter->child_model),
+ filter->changed_id);
+ g_signal_handler_disconnect (G_OBJECT (filter->child_model),
+ filter->inserted_id);
+ g_signal_handler_disconnect (G_OBJECT (filter->child_model),
+ filter->has_child_toggled_id);
+ g_signal_handler_disconnect (G_OBJECT (filter->child_model),
+ filter->deleted_id);
+ g_signal_handler_disconnect (G_OBJECT (filter->child_model),
+ filter->reordered_id);
+
+ /* reset our state */
+ if (filter->root)
+ egg_tree_model_filter_free_level (filter, filter->root);
+
+ filter->root = NULL;
+ g_object_unref (G_OBJECT (filter->child_model));
+ filter->visible_column = -1;
+ /* FIXME: destroy more crack here? the funcs? */
+ }
+
+ filter->child_model = child_model;
+
+ if (child_model)
+ {
+ g_object_ref (G_OBJECT (filter->child_model));
+ filter->changed_id =
+ g_signal_connect (child_model, "row_changed",
+ G_CALLBACK (egg_tree_model_filter_row_changed),
+ filter);
+ filter->inserted_id =
+ g_signal_connect (child_model, "row_inserted",
+ G_CALLBACK (egg_tree_model_filter_row_inserted),
+ filter);
+ filter->has_child_toggled_id =
+ g_signal_connect (child_model, "row_has_child_toggled",
+ G_CALLBACK (egg_tree_model_filter_row_has_child_toggled),
+ filter);
+ filter->deleted_id =
+ g_signal_connect (child_model, "row_deleted",
+ G_CALLBACK (egg_tree_model_filter_row_deleted),
+ filter);
+ filter->reordered_id =
+ g_signal_connect (child_model, "rows_reordered",
+ G_CALLBACK (egg_tree_model_filter_rows_reordered),
+ filter);
+
+ filter->child_flags = gtk_tree_model_get_flags (child_model);
+ filter->stamp = g_random_int ();
+ }
+}
+
+static void
+egg_tree_model_filter_set_root (EggTreeModelFilter *filter,
+ GtkTreePath *root)
+{
+ g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (filter));
+
+ if (!root)
+ filter->virtual_root = NULL;
+ else
+ filter->virtual_root = gtk_tree_path_copy (root);
+}
+
+/* public API */
+
+GtkTreeModel *
+egg_tree_model_filter_new (GtkTreeModel *child_model,
+ GtkTreePath *root)
+{
+ GtkTreeModel *retval;
+
+ g_return_val_if_fail (GTK_IS_TREE_MODEL (child_model), NULL);
+
+ retval = GTK_TREE_MODEL (g_object_new (egg_tree_model_filter_get_type (), NULL));
+
+ egg_tree_model_filter_set_model (EGG_TREE_MODEL_FILTER (retval),
+ child_model);
+ egg_tree_model_filter_set_root (EGG_TREE_MODEL_FILTER (retval), root);
+
+ return retval;
+}
+
+GtkTreeModel *
+egg_tree_model_filter_get_model (EggTreeModelFilter *filter)
+{
+ g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (filter), NULL);
+
+ return filter->child_model;
+}
+
+void
+egg_tree_model_filter_set_visible_func (EggTreeModelFilter *filter,
+ EggTreeModelFilterVisibleFunc func,
+ gpointer data,
+ GtkDestroyNotify destroy)
+{
+ g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (filter));
+ g_return_if_fail (func != NULL);
+ g_return_if_fail (filter->visible_method_set == FALSE);
+
+ if (filter->visible_func)
+ {
+ GtkDestroyNotify d = filter->visible_destroy;
+
+ filter->visible_destroy = NULL;
+ d (filter->visible_data);
+ }
+
+ filter->visible_func = func;
+ filter->visible_data = data;
+ filter->visible_destroy = destroy;
+
+ filter->visible_method_set = TRUE;
+}
+
+void
+egg_tree_model_filter_set_modify_func (EggTreeModelFilter *filter,
+ gint n_columns,
+ GType *types,
+ EggTreeModelFilterModifyFunc func,
+ gpointer data,
+ GtkDestroyNotify destroy)
+{
+ g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (filter));
+ g_return_if_fail (func != NULL);
+ g_return_if_fail (filter->modify_func_set == FALSE);
+
+ if (filter->modify_destroy)
+ {
+ GtkDestroyNotify d = filter->modify_destroy;
+
+ filter->modify_destroy = NULL;
+ d (filter->modify_data);
+ }
+
+ filter->modify_n_columns = n_columns;
+ filter->modify_types = g_new0 (GType, n_columns);
+ memcpy (filter->modify_types, types, sizeof (GType) * n_columns);
+ filter->modify_func = func;
+ filter->modify_data = data;
+ filter->modify_destroy = destroy;
+
+ filter->modify_func_set = TRUE;
+}
+
+void
+egg_tree_model_filter_set_visible_column (EggTreeModelFilter *filter,
+ gint column)
+{
+ g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (filter));
+ g_return_if_fail (column >= 0);
+ g_return_if_fail (filter->visible_method_set == FALSE);
+
+ filter->visible_column = column;
+
+ filter->visible_method_set = TRUE;
+}
+
+/* conversion */
+void
+egg_tree_model_filter_convert_child_iter_to_iter (EggTreeModelFilter *filter,
+ GtkTreeIter *filter_iter,
+ GtkTreeIter *child_iter)
+{
+ GtkTreePath *child_path, *path;
+
+ g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (filter));
+ g_return_if_fail (filter->child_model != NULL);
+ g_return_if_fail (filter_iter != NULL);
+ g_return_if_fail (child_iter != NULL);
+
+ filter_iter->stamp = 0;
+
+ child_path = gtk_tree_model_get_path (filter->child_model, child_iter);
+ g_return_if_fail (child_path != NULL);
+
+ path = egg_tree_model_filter_convert_child_path_to_path (filter,
+ child_path);
+ gtk_tree_path_free (child_path);
+ g_return_if_fail (path != NULL);
+
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (filter), filter_iter, path);
+ gtk_tree_path_free (path);
+}
+
+void
+egg_tree_model_filter_convert_iter_to_child_iter (EggTreeModelFilter *filter,
+ GtkTreeIter *child_iter,
+ GtkTreeIter *filter_iter)
+{
+ g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (filter));
+ g_return_if_fail (filter->child_model != NULL);
+ g_return_if_fail (child_iter != NULL);
+ g_return_if_fail (filter_iter != NULL);
+ g_return_if_fail (filter_iter->stamp == filter->stamp);
+
+ if (EGG_TREE_MODEL_FILTER_CACHE_CHILD_ITERS (filter))
+ {
+ *child_iter = FILTER_ELT (filter_iter->user_data2)->iter;
+ }
+ else
+ {
+ GtkTreePath *path;
+
+ path = egg_tree_model_filter_elt_get_path (filter_iter->user_data,
+ filter_iter->user_data2,
+ NULL);
+ gtk_tree_model_get_iter (filter->child_model, child_iter, path);
+ gtk_tree_path_free (path);
+ }
+}
+
+static GtkTreePath *
+egg_real_tree_model_filter_convert_child_path_to_path (EggTreeModelFilter *filter,
+ GtkTreePath *child_path,
+ gboolean build_levels,
+ gboolean fetch_childs)
+{
+ gint *child_indices;
+ GtkTreePath *retval;
+ GtkTreePath *real_path;
+ FilterLevel *level;
+ gint i;
+
+ g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (filter), NULL);
+ g_return_val_if_fail (filter->child_model != NULL, NULL);
+ g_return_val_if_fail (child_path != NULL, NULL);
+
+ if (!filter->virtual_root)
+ real_path = gtk_tree_path_copy (child_path);
+ else
+ real_path = egg_tree_model_filter_remove_root (child_path,
+ filter->virtual_root);
+
+ if (!real_path)
+ return NULL;
+
+ retval = gtk_tree_path_new ();
+ child_indices = gtk_tree_path_get_indices (real_path);
+
+ if (filter->root == NULL && build_levels)
+ egg_tree_model_filter_build_level (filter, NULL, NULL);
+ level = FILTER_LEVEL (filter->root);
+
+ for (i = 0; i < gtk_tree_path_get_depth (real_path); i++)
+ {
+ gint j;
+ gboolean found_child = FALSE;
+
+ if (!level)
+ {
+ gtk_tree_path_free (real_path);
+ gtk_tree_path_free (retval);
+ return NULL;
+ }
+
+ for (j = 0; j < level->array->len; j++)
+ {
+ if ((g_array_index (level->array, FilterElt, j)).offset == child_indices[i])
+ {
+ gtk_tree_path_append_index (retval, j);
+ if (g_array_index (level->array, FilterElt, j).children == NULL && build_levels)
+ egg_tree_model_filter_build_level (filter,
+ level,
+ &g_array_index (level->array, FilterElt, j));
+ level = g_array_index (level->array, FilterElt, j).children;
+ found_child = TRUE;
+ break;
+ }
+ }
+
+ if (!found_child && fetch_childs)
+ {
+ /* didn't find the child, let's try to bring it back */
+ if (!egg_tree_model_filter_fetch_child (filter, level, child_indices[i]))
+ {
+ /* not there */
+ gtk_tree_path_free (real_path);
+ gtk_tree_path_free (retval);
+ return NULL;
+ }
+
+ /* yay, let's search for the child again */
+ for (j = 0; j < level->array->len; j++)
+ {
+ if ((g_array_index (level->array, FilterElt, j)).offset == child_indices[i])
+ {
+ gtk_tree_path_append_index (retval, j);
+ if (g_array_index (level->array, FilterElt, j).children == NULL && build_levels)
+ egg_tree_model_filter_build_level (filter,
+ level,
+ &g_array_index (level->array, FilterElt, j));
+ level = g_array_index (level->array, FilterElt, j).children;
+ found_child = TRUE;
+ break;
+ }
+ }
+
+ if (!found_child)
+ {
+ /* our happy fun fetch attempt failed ?!?!?! no child! */
+ gtk_tree_path_free (real_path);
+ gtk_tree_path_free (retval);
+ return NULL;
+ }
+ }
+ else if (!found_child && !fetch_childs)
+ {
+ /* no path */
+ gtk_tree_path_free (real_path);
+ gtk_tree_path_free (retval);
+ return NULL;
+ }
+ }
+
+ gtk_tree_path_free (real_path);
+ return retval;
+}
+
+GtkTreePath *
+egg_tree_model_filter_convert_child_path_to_path (EggTreeModelFilter *filter,
+ GtkTreePath *child_path)
+{
+ /* this function does the sanity checks */
+ return egg_real_tree_model_filter_convert_child_path_to_path (filter,
+ child_path,
+ TRUE,
+ TRUE);
+}
+
+GtkTreePath *
+egg_tree_model_filter_convert_path_to_child_path (EggTreeModelFilter *filter,
+ GtkTreePath *filter_path)
+{
+ gint *filter_indices;
+ GtkTreePath *retval;
+ FilterLevel *level;
+ gint i;
+
+ g_return_val_if_fail (EGG_IS_TREE_MODEL_FILTER (filter), NULL);
+ g_return_val_if_fail (filter->child_model != NULL, NULL);
+ g_return_val_if_fail (filter_path != NULL, NULL);
+
+ /* convert path */
+ retval = gtk_tree_path_new ();
+ filter_indices = gtk_tree_path_get_indices (filter_path);
+ if (!filter->root)
+ egg_tree_model_filter_build_level (filter, NULL, NULL);
+ level = FILTER_LEVEL (filter->root);
+
+ for (i = 0; i < gtk_tree_path_get_depth (filter_path); i++)
+ {
+ gint count = filter_indices[i];
+
+ if (!level || level->array->len <= filter_indices[i])
+ {
+ gtk_tree_path_free (retval);
+ return NULL;
+ }
+
+ if (g_array_index (level->array, FilterElt, count).children == NULL)
+ egg_tree_model_filter_build_level (filter, level, &g_array_index (level->array, FilterElt, count));
+
+ if (!level || level->array->len <= filter_indices[i])
+ {
+ gtk_tree_path_free (retval);
+ return NULL;
+ }
+
+ gtk_tree_path_append_index (retval, g_array_index (level->array, FilterElt, count).offset);
+ level = g_array_index (level->array, FilterElt, count).children;
+ }
+
+ /* apply vroot */
+
+ if (filter->virtual_root)
+ {
+ GtkTreePath *real_retval;
+
+ real_retval = egg_tree_model_filter_add_root (retval,
+ filter->virtual_root);
+ gtk_tree_path_free (retval);
+
+ return real_retval;
+ }
+
+ return retval;
+}
+
+void
+egg_tree_model_filter_clear_cache (EggTreeModelFilter *filter)
+{
+ g_return_if_fail (EGG_IS_TREE_MODEL_FILTER (filter));
+
+ if (filter->zero_ref_count)
+ egg_tree_model_filter_clear_cache_helper (filter,
+ FILTER_LEVEL (filter->root));
+}
diff --git a/lib/widgets/eggtreemodelfilter.h b/lib/widgets/eggtreemodelfilter.h
new file mode 100644
index 000000000..ada78c1be
--- /dev/null
+++ b/lib/widgets/eggtreemodelfilter.h
@@ -0,0 +1,123 @@
+/* eggtreemodelfilter.h
+ * Copyright (C) 2000,2001 Red Hat, Inc., Jonathan Blandford <jrb@redhat.com>
+ * Copyright (C) 2001,2002 Kristian Rietveld <kris@gtk.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __EGG_TREE_MODEL_FILTER_H__
+#define __EGG_TREE_MODEL_FILTER_H__
+
+#include <gtk/gtktreemodel.h>
+
+G_BEGIN_DECLS
+
+#define EGG_TYPE_TREE_MODEL_FILTER (egg_tree_model_filter_get_type ())
+#define EGG_TREE_MODEL_FILTER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_TREE_MODEL_FILTER, EggTreeModelFilter))
+#define EGG_TREE_MODEL_FILTER_CLASS(vtable) (G_TYPE_CHECK_CLASS_CAST ((vtable), EGG_TYPE_TREE_MODEL_FILTER, EggTreeModelFilterClass))
+#define EGG_IS_TREE_MODEL_FILTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_TREE_MODEL_FILTER))
+#define EGG_IS_TREE_MODEL_FILTER_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), EGG_TYPE_TREE_MODEL_FILTER))
+#define EGG_TREE_MODEL_FILTER_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((obj), EGG_TYPE_TREE_MODEL_FILTER, EggTreeModelFilterClass))
+
+typedef gboolean (* EggTreeModelFilterVisibleFunc) (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer data);
+typedef void (* EggTreeModelFilterModifyFunc) (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ GValue *value,
+ gint column,
+ gpointer data);
+
+typedef struct _EggTreeModelFilter EggTreeModelFilter;
+typedef struct _EggTreeModelFilterClass EggTreeModelFilterClass;
+
+struct _EggTreeModelFilter
+{
+ GObject parent;
+
+ /*< private >*/
+ gpointer root;
+ gint stamp;
+ guint child_flags;
+ GtkTreeModel *child_model;
+ gint zero_ref_count;
+
+ GtkTreePath *virtual_root;
+
+ EggTreeModelFilterVisibleFunc visible_func;
+ gpointer visible_data;
+ GtkDestroyNotify visible_destroy;
+
+ gint modify_n_columns;
+ GType *modify_types;
+ EggTreeModelFilterModifyFunc modify_func;
+ gpointer modify_data;
+ gpointer modify_destroy;
+
+ gint visible_column;
+
+ gboolean visible_method_set;
+ gboolean modify_func_set;
+
+ /* signal ids */
+ guint changed_id;
+ guint inserted_id;
+ guint has_child_toggled_id;
+ guint deleted_id;
+ guint reordered_id;
+};
+
+struct _EggTreeModelFilterClass
+{
+ GObjectClass parent_class;
+};
+
+GType egg_tree_model_filter_get_type (void);
+GtkTreeModel * egg_tree_model_filter_new (GtkTreeModel *child_model,
+ GtkTreePath *root);
+void egg_tree_model_filter_set_visible_func (EggTreeModelFilter *filter,
+ EggTreeModelFilterVisibleFunc func,
+ gpointer data,
+ GtkDestroyNotify destroy);
+void egg_tree_model_filter_set_modify_func (EggTreeModelFilter *filter,
+ gint n_columns,
+ GType *types,
+ EggTreeModelFilterModifyFunc func,
+ gpointer data,
+ GtkDestroyNotify destroy);
+void egg_tree_model_filter_set_visible_column (EggTreeModelFilter *filter,
+ gint column);
+
+GtkTreeModel *egg_tree_model_filter_get_model (EggTreeModelFilter *filter);
+
+/* conversion */
+void egg_tree_model_filter_convert_child_iter_to_iter (EggTreeModelFilter *filter,
+ GtkTreeIter *filter_iter,
+ GtkTreeIter *child_iter);
+void egg_tree_model_filter_convert_iter_to_child_iter (EggTreeModelFilter *filter,
+ GtkTreeIter *child_iter,
+ GtkTreeIter *filter_iter);
+GtkTreePath *egg_tree_model_filter_convert_child_path_to_path (EggTreeModelFilter *filter,
+ GtkTreePath *child_path);
+GtkTreePath *egg_tree_model_filter_convert_path_to_child_path (EggTreeModelFilter *path,
+ GtkTreePath *filter_path);
+
+
+void egg_tree_model_filter_clear_cache (EggTreeModelFilter *filter);
+
+G_END_DECLS
+
+#endif /* __EGG_TREE_MODEL_FILTER_H__ */
diff --git a/lib/widgets/eggtreemultidnd.c b/lib/widgets/eggtreemultidnd.c
new file mode 100644
index 000000000..8be54f442
--- /dev/null
+++ b/lib/widgets/eggtreemultidnd.c
@@ -0,0 +1,415 @@
+/* eggtreemultidnd.c
+ * Copyright (C) 2001 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library 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.
+ */
+
+#include <string.h>
+#include <gtk/gtktreeselection.h>
+#include <gtk/gtksignal.h>
+#include <gtk/gtkwidget.h>
+#include <gtk/gtkmain.h>
+#include "eggtreemultidnd.h"
+
+#define EGG_TREE_MULTI_DND_STRING "EggTreeMultiDndString"
+
+typedef struct
+{
+ guint pressed_button;
+ gint x;
+ gint y;
+ guint motion_notify_handler;
+ guint button_release_handler;
+ guint drag_data_get_handler;
+ GSList *event_list;
+} EggTreeMultiDndData;
+
+/* CUT-N-PASTE from gtktreeview.c */
+typedef struct _TreeViewDragInfo TreeViewDragInfo;
+struct _TreeViewDragInfo
+{
+ GdkModifierType start_button_mask;
+ GtkTargetList *source_target_list;
+ GdkDragAction source_actions;
+
+ GtkTargetList *dest_target_list;
+
+ guint source_set : 1;
+ guint dest_set : 1;
+};
+
+
+GType
+egg_tree_multi_drag_source_get_type (void)
+{
+ static GType our_type = 0;
+
+ if (!our_type)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (EggTreeMultiDragSourceIface), /* class_size */
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ NULL,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ 0,
+ 0, /* n_preallocs */
+ NULL
+ };
+
+ our_type = g_type_register_static (G_TYPE_INTERFACE, "EggTreeMultiDragSource", &our_info, 0);
+ }
+
+ return our_type;
+}
+
+
+/**
+ * egg_tree_multi_drag_source_row_draggable:
+ * @drag_source: a #EggTreeMultiDragSource
+ * @path: row on which user is initiating a drag
+ *
+ * Asks the #EggTreeMultiDragSource whether a particular row can be used as
+ * the source of a DND operation. If the source doesn't implement
+ * this interface, the row is assumed draggable.
+ *
+ * Return value: %TRUE if the row can be dragged
+ **/
+gboolean
+egg_tree_multi_drag_source_row_draggable (EggTreeMultiDragSource *drag_source,
+ GList *path_list)
+{
+ EggTreeMultiDragSourceIface *iface = EGG_TREE_MULTI_DRAG_SOURCE_GET_IFACE (drag_source);
+
+ g_return_val_if_fail (EGG_IS_TREE_MULTI_DRAG_SOURCE (drag_source), FALSE);
+ g_return_val_if_fail (iface->row_draggable != NULL, FALSE);
+ g_return_val_if_fail (path_list != NULL, FALSE);
+
+ if (iface->row_draggable)
+ return (* iface->row_draggable) (drag_source, path_list);
+ else
+ return TRUE;
+}
+
+
+/**
+ * egg_tree_multi_drag_source_drag_data_delete:
+ * @drag_source: a #EggTreeMultiDragSource
+ * @path: row that was being dragged
+ *
+ * Asks the #EggTreeMultiDragSource to delete the row at @path, because
+ * it was moved somewhere else via drag-and-drop. Returns %FALSE
+ * if the deletion fails because @path no longer exists, or for
+ * some model-specific reason. Should robustly handle a @path no
+ * longer found in the model!
+ *
+ * Return value: %TRUE if the row was successfully deleted
+ **/
+gboolean
+egg_tree_multi_drag_source_drag_data_delete (EggTreeMultiDragSource *drag_source,
+ GList *path_list)
+{
+ EggTreeMultiDragSourceIface *iface = EGG_TREE_MULTI_DRAG_SOURCE_GET_IFACE (drag_source);
+
+ g_return_val_if_fail (EGG_IS_TREE_MULTI_DRAG_SOURCE (drag_source), FALSE);
+ g_return_val_if_fail (iface->drag_data_delete != NULL, FALSE);
+ g_return_val_if_fail (path_list != NULL, FALSE);
+
+ return (* iface->drag_data_delete) (drag_source, path_list);
+}
+
+/**
+ * egg_tree_multi_drag_source_drag_data_get:
+ * @drag_source: a #EggTreeMultiDragSource
+ * @path: row that was dragged
+ * @selection_data: a #EggSelectionData to fill with data from the dragged row
+ *
+ * Asks the #EggTreeMultiDragSource to fill in @selection_data with a
+ * representation of the row at @path. @selection_data->target gives
+ * the required type of the data. Should robustly handle a @path no
+ * longer found in the model!
+ *
+ * Return value: %TRUE if data of the required type was provided
+ **/
+gboolean
+egg_tree_multi_drag_source_drag_data_get (EggTreeMultiDragSource *drag_source,
+ GList *path_list,
+ guint info,
+ GtkSelectionData *selection_data)
+{
+ EggTreeMultiDragSourceIface *iface = EGG_TREE_MULTI_DRAG_SOURCE_GET_IFACE (drag_source);
+
+ g_return_val_if_fail (EGG_IS_TREE_MULTI_DRAG_SOURCE (drag_source), FALSE);
+ g_return_val_if_fail (iface->drag_data_get != NULL, FALSE);
+ g_return_val_if_fail (path_list != NULL, FALSE);
+ g_return_val_if_fail (selection_data != NULL, FALSE);
+
+ return (* iface->drag_data_get) (drag_source, path_list, info, selection_data);
+}
+
+static void
+stop_drag_check (GtkWidget *widget)
+{
+ EggTreeMultiDndData *priv_data;
+ GSList *l;
+
+ priv_data = g_object_get_data (G_OBJECT (widget), EGG_TREE_MULTI_DND_STRING);
+
+ for (l = priv_data->event_list; l != NULL; l = l->next)
+ gdk_event_free (l->data);
+
+ g_slist_free (priv_data->event_list);
+ priv_data->event_list = NULL;
+ g_signal_handler_disconnect (widget, priv_data->motion_notify_handler);
+ g_signal_handler_disconnect (widget, priv_data->button_release_handler);
+}
+
+static gboolean
+egg_tree_multi_drag_button_release_event (GtkWidget *widget,
+ GdkEventButton *event,
+ gpointer data)
+{
+ EggTreeMultiDndData *priv_data;
+ GSList *l;
+
+ priv_data = g_object_get_data (G_OBJECT (widget), EGG_TREE_MULTI_DND_STRING);
+
+ for (l = priv_data->event_list; l != NULL; l = l->next)
+ gtk_propagate_event (widget, l->data);
+
+ stop_drag_check (widget);
+
+ return FALSE;
+}
+
+static void
+selection_foreach (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ GList **list_ptr;
+
+ list_ptr = (GList **) data;
+
+ *list_ptr = g_list_prepend (*list_ptr, gtk_tree_row_reference_new (model, path));
+}
+
+static void
+path_list_free (GList *path_list)
+{
+ g_list_foreach (path_list, (GFunc) gtk_tree_row_reference_free, NULL);
+ g_list_free (path_list);
+}
+
+static void
+set_context_data (GdkDragContext *context,
+ GList *path_list)
+{
+ g_object_set_data_full (G_OBJECT (context),
+ "egg-tree-view-multi-source-row",
+ path_list,
+ (GDestroyNotify) path_list_free);
+}
+
+static GList *
+get_context_data (GdkDragContext *context)
+{
+ return g_object_get_data (G_OBJECT (context),
+ "egg-tree-view-multi-source-row");
+}
+
+/* CUT-N-PASTE from gtktreeview.c */
+static TreeViewDragInfo*
+get_info (GtkTreeView *tree_view)
+{
+ return g_object_get_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info");
+}
+
+
+static void
+egg_tree_multi_drag_drag_data_get (GtkWidget *widget,
+ GdkDragContext *context,
+ GtkSelectionData *selection_data,
+ guint info,
+ guint time)
+{
+ GtkTreeView *tree_view;
+ GtkTreeModel *model;
+ TreeViewDragInfo *di;
+ GList *path_list;
+
+ tree_view = GTK_TREE_VIEW (widget);
+
+ model = gtk_tree_view_get_model (tree_view);
+
+ if (model == NULL)
+ return;
+
+ di = get_info (GTK_TREE_VIEW (widget));
+
+ if (di == NULL)
+ return;
+
+ path_list = get_context_data (context);
+
+ if (path_list == NULL)
+ return;
+
+ /* We can implement the GTK_TREE_MODEL_ROW target generically for
+ * any model; for DragSource models there are some other targets
+ * we also support.
+ */
+
+ if (EGG_IS_TREE_MULTI_DRAG_SOURCE (model))
+ {
+ egg_tree_multi_drag_source_drag_data_get (EGG_TREE_MULTI_DRAG_SOURCE (model),
+ path_list,
+ info,
+ selection_data);
+ }
+}
+
+static gboolean
+egg_tree_multi_drag_motion_event (GtkWidget *widget,
+ GdkEventMotion *event,
+ gpointer data)
+{
+ EggTreeMultiDndData *priv_data;
+
+ priv_data = g_object_get_data (G_OBJECT (widget), EGG_TREE_MULTI_DND_STRING);
+
+ if (gtk_drag_check_threshold (widget,
+ priv_data->x,
+ priv_data->y,
+ event->x,
+ event->y))
+ {
+ GList *path_list = NULL;
+ GtkTreeSelection *selection;
+ GtkTreeModel *model;
+ GdkDragContext *context;
+ TreeViewDragInfo *di;
+
+ di = get_info (GTK_TREE_VIEW (widget));
+
+ if (di == NULL)
+ return FALSE;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
+ stop_drag_check (widget);
+ gtk_tree_selection_selected_foreach (selection, selection_foreach, &path_list);
+ path_list = g_list_reverse (path_list);
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget));
+
+ if (egg_tree_multi_drag_source_row_draggable (EGG_TREE_MULTI_DRAG_SOURCE (model), path_list))
+ {
+ context = gtk_drag_begin (widget,
+ di->source_target_list,
+ di->source_actions,
+ priv_data->pressed_button,
+ (GdkEvent*)event);
+ set_context_data (context, path_list);
+ }
+ else
+ {
+ path_list_free (path_list);
+ }
+ }
+
+ return TRUE;
+}
+
+static gboolean
+egg_tree_multi_drag_button_press_event (GtkWidget *widget,
+ GdkEventButton *event,
+ gpointer data)
+{
+ GtkTreeView *tree_view;
+ GtkTreePath *path = NULL;
+ GtkTreeViewColumn *column = NULL;
+ gint cell_x, cell_y;
+ GtkTreeSelection *selection;
+ EggTreeMultiDndData *priv_data;
+
+ if (event->button == 3)
+ return FALSE;
+
+ tree_view = GTK_TREE_VIEW (widget);
+ priv_data = g_object_get_data (G_OBJECT (tree_view), EGG_TREE_MULTI_DND_STRING);
+ if (priv_data == NULL)
+ {
+ priv_data = g_new0 (EggTreeMultiDndData, 1);
+ g_object_set_data (G_OBJECT (tree_view), EGG_TREE_MULTI_DND_STRING, priv_data);
+ }
+
+ if (g_slist_find (priv_data->event_list, event))
+ return FALSE;
+
+ if (priv_data->event_list)
+ {
+ /* save the event to be propagated in order */
+ priv_data->event_list = g_slist_append (priv_data->event_list, gdk_event_copy ((GdkEvent*)event));
+ return TRUE;
+ }
+
+ if (event->type == GDK_2BUTTON_PRESS)
+ return FALSE;
+
+ gtk_tree_view_get_path_at_pos (tree_view,
+ event->x, event->y,
+ &path, &column,
+ &cell_x, &cell_y);
+
+ selection = gtk_tree_view_get_selection (tree_view);
+
+ if (path && gtk_tree_selection_path_is_selected (selection, path))
+ {
+ priv_data->pressed_button = event->button;
+ priv_data->x = event->x;
+ priv_data->y = event->y;
+ priv_data->event_list = g_slist_append (priv_data->event_list, gdk_event_copy ((GdkEvent*)event));
+ priv_data->motion_notify_handler =
+ g_signal_connect (G_OBJECT (tree_view), "motion_notify_event", G_CALLBACK (egg_tree_multi_drag_motion_event), NULL);
+ priv_data->button_release_handler =
+ g_signal_connect (G_OBJECT (tree_view), "button_release_event", G_CALLBACK (egg_tree_multi_drag_button_release_event), NULL);
+
+ if (priv_data->drag_data_get_handler == 0)
+ {
+ priv_data->drag_data_get_handler =
+ g_signal_connect (G_OBJECT (tree_view), "drag_data_get", G_CALLBACK (egg_tree_multi_drag_drag_data_get), NULL);
+ }
+
+ return TRUE;
+ }
+
+ if (path)
+ {
+ gtk_tree_path_free (path);
+ }
+
+ return FALSE;
+}
+
+void
+egg_tree_multi_drag_add_drag_support (GtkTreeView *tree_view)
+{
+ g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
+ g_signal_connect (G_OBJECT (tree_view), "button_press_event", G_CALLBACK (egg_tree_multi_drag_button_press_event), NULL);
+}
+
diff --git a/lib/widgets/eggtreemultidnd.h b/lib/widgets/eggtreemultidnd.h
new file mode 100644
index 000000000..460e60239
--- /dev/null
+++ b/lib/widgets/eggtreemultidnd.h
@@ -0,0 +1,78 @@
+/* eggtreednd.h
+ * Copyright (C) 2001 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library 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 __EGG_TREE_MULTI_DND_H__
+#define __EGG_TREE_MULTI_DND_H__
+
+#include <gtk/gtktreemodel.h>
+#include <gtk/gtktreeview.h>
+#include <gtk/gtkdnd.h>
+
+G_BEGIN_DECLS
+
+#define EGG_TYPE_TREE_MULTI_DRAG_SOURCE (egg_tree_multi_drag_source_get_type ())
+#define EGG_TREE_MULTI_DRAG_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_TREE_MULTI_DRAG_SOURCE, EggTreeMultiDragSource))
+#define EGG_IS_TREE_MULTI_DRAG_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_TREE_MULTI_DRAG_SOURCE))
+#define EGG_TREE_MULTI_DRAG_SOURCE_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), EGG_TYPE_TREE_MULTI_DRAG_SOURCE, EggTreeMultiDragSourceIface))
+
+typedef struct _EggTreeMultiDragSource EggTreeMultiDragSource; /* Dummy typedef */
+typedef struct _EggTreeMultiDragSourceIface EggTreeMultiDragSourceIface;
+
+struct _EggTreeMultiDragSourceIface
+{
+ GTypeInterface g_iface;
+
+ /* VTable - not signals */
+ gboolean (* row_draggable) (EggTreeMultiDragSource *drag_source,
+ GList *path_list);
+
+ gboolean (* drag_data_get) (EggTreeMultiDragSource *drag_source,
+ GList *path_list,
+ guint info,
+ GtkSelectionData *selection_data);
+
+ gboolean (* drag_data_delete) (EggTreeMultiDragSource *drag_source,
+ GList *path_list);
+};
+
+GType egg_tree_multi_drag_source_get_type (void) G_GNUC_CONST;
+
+/* Returns whether the given row can be dragged */
+gboolean egg_tree_multi_drag_source_row_draggable (EggTreeMultiDragSource *drag_source,
+ GList *path_list);
+
+/* Deletes the given row, or returns FALSE if it can't */
+gboolean egg_tree_multi_drag_source_drag_data_delete (EggTreeMultiDragSource *drag_source,
+ GList *path_list);
+
+
+/* Fills in selection_data with type selection_data->target based on the row
+ * denoted by path, returns TRUE if it does anything
+ */
+gboolean egg_tree_multi_drag_source_drag_data_get (EggTreeMultiDragSource *drag_source,
+ GList *path_list,
+ guint info,
+ GtkSelectionData *selection_data);
+void egg_tree_multi_drag_add_drag_support (GtkTreeView *tree_view);
+
+
+
+G_END_DECLS
+
+#endif /* __EGG_TREE_MULTI_DND_H__ */
diff --git a/lib/widgets/ephy-autocompletion-window.c b/lib/widgets/ephy-autocompletion-window.c
new file mode 100644
index 000000000..9c639a52a
--- /dev/null
+++ b/lib/widgets/ephy-autocompletion-window.c
@@ -0,0 +1,854 @@
+/*
+ * Copyright (C) 2002 Ricardo Fernández Pascual
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <libgnome/gnome-i18n.h>
+#include <gtk/gtkcellrenderertext.h>
+#include <gtk/gtktreeview.h>
+#include <gtk/gtkscrolledwindow.h>
+#include <gtk/gtktreeselection.h>
+#include <gtk/gtkliststore.h>
+#include <gtk/gtkwindow.h>
+#include <gtk/gtkmain.h>
+#include <gtk/gtkvbox.h>
+#include <gdk/gdkkeysyms.h>
+#include <gtk/gtkframe.h>
+
+#include "ephy-autocompletion-window.h"
+#include "ephy-gobject-misc.h"
+#include "ephy-string.h"
+#include "ephy-marshal.h"
+#include "ephy-gui.h"
+
+/* This is copied from gtkscrollbarwindow.c */
+#define DEFAULT_SCROLLBAR_SPACING 3
+
+#define SCROLLBAR_SPACING(w) \
+ (GTK_SCROLLED_WINDOW_GET_CLASS (w)->scrollbar_spacing >= 0 ? \
+ GTK_SCROLLED_WINDOW_GET_CLASS (w)->scrollbar_spacing : DEFAULT_SCROLLBAR_SPACING)
+
+#define MAX_VISIBLE_ROWS 9
+#define MAX_COMPLETION_ALTERNATIVES 7
+
+//#define DEBUG_MSG(x) g_print x
+#define DEBUG_MSG(x)
+
+//#define DEBUG_TIME
+
+#ifdef DEBUG_TIME
+#include <glib/gtimer.h>
+#endif
+
+/**
+ * Private data
+ */
+struct _EphyAutocompletionWindowPrivate {
+ EphyAutocompletion *autocompletion;
+ GtkWidget *parent;
+
+ GtkWidget *window;
+ GtkScrolledWindow *scrolled_window;
+ GtkTreeView *tree_view;
+ GtkTreeViewColumn *col1;
+ GtkTreeView *action_tree_view;
+ GtkTreeViewColumn *action_col1;
+ GtkTreeView *active_tree_view;
+ gboolean only_actions;
+
+ char *selected;
+
+ GtkListStore *list_store;
+ GtkListStore *action_list_store;
+ guint last_added_match;
+ int view_nitems;
+
+ gboolean shown;
+};
+
+/**
+ * Private functions, only availble from this file
+ */
+static void ephy_autocompletion_window_class_init (EphyAutocompletionWindowClass *klass);
+static void ephy_autocompletion_window_init (EphyAutocompletionWindow *aw);
+static void ephy_autocompletion_window_finalize_impl (GObject *o);
+static void ephy_autocompletion_window_init_widgets (EphyAutocompletionWindow *aw);
+static void ephy_autocompletion_window_selection_changed_cb (GtkTreeSelection *treeselection,
+ EphyAutocompletionWindow *aw);
+static gboolean ephy_autocompletion_window_button_press_event_cb (GtkWidget *widget,
+ GdkEventButton *event,
+ EphyAutocompletionWindow *aw);
+static gboolean ephy_autocompletion_window_key_press_cb (GtkWidget *widget,
+ GdkEventKey *event,
+ EphyAutocompletionWindow *aw);
+static void ephy_autocompletion_window_event_after_cb (GtkWidget *wid, GdkEvent *event,
+ EphyAutocompletionWindow *aw);
+static void ephy_autocompletion_window_fill_store_chunk (EphyAutocompletionWindow *aw);
+
+
+static gpointer g_object_class;
+
+enum EphyAutocompletionWindowSignalsEnum {
+ ACTIVATED,
+ EPHY_AUTOCOMPLETION_WINDOW_HIDDEN,
+ EPHY_AUTOCOMPLETION_WINDOW_LAST_SIGNAL
+};
+static gint EphyAutocompletionWindowSignals[EPHY_AUTOCOMPLETION_WINDOW_LAST_SIGNAL];
+
+/**
+ * AutocompletionWindow object
+ */
+
+MAKE_GET_TYPE (ephy_autocompletion_window, "EphyAutocompletionWindow", EphyAutocompletionWindow,
+ ephy_autocompletion_window_class_init,
+ ephy_autocompletion_window_init, G_TYPE_OBJECT);
+
+static void
+ephy_autocompletion_window_class_init (EphyAutocompletionWindowClass *klass)
+{
+ G_OBJECT_CLASS (klass)->finalize = ephy_autocompletion_window_finalize_impl;
+ g_object_class = g_type_class_peek_parent (klass);
+
+ EphyAutocompletionWindowSignals[ACTIVATED] = g_signal_new (
+ "activated", G_OBJECT_CLASS_TYPE (klass),
+ G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST | G_SIGNAL_RUN_CLEANUP,
+ G_STRUCT_OFFSET (EphyAutocompletionWindowClass, activated),
+ NULL, NULL,
+ ephy_marshal_VOID__STRING_INT,
+ G_TYPE_NONE,
+ 2,
+ G_TYPE_STRING,
+ G_TYPE_INT);
+
+ EphyAutocompletionWindowSignals[EPHY_AUTOCOMPLETION_WINDOW_HIDDEN] = g_signal_new (
+ "hidden", G_OBJECT_CLASS_TYPE (klass),
+ G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST | G_SIGNAL_RUN_CLEANUP,
+ G_STRUCT_OFFSET (EphyAutocompletionWindowClass, hidden),
+ NULL, NULL,
+ ephy_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+}
+
+static void
+ephy_autocompletion_window_init (EphyAutocompletionWindow *aw)
+{
+ EphyAutocompletionWindowPrivate *p = g_new0 (EphyAutocompletionWindowPrivate, 1);
+ GtkTreeSelection *s;
+
+ aw->priv = p;
+ p->selected = NULL;
+
+ ephy_autocompletion_window_init_widgets (aw);
+
+ s = gtk_tree_view_get_selection (p->tree_view);
+ /* I would like to use GTK_SELECTION_SINGLE, but it seems to require that one
+ item is selected always */
+ gtk_tree_selection_set_mode (s, GTK_SELECTION_MULTIPLE);
+
+ g_signal_connect (s, "changed", G_CALLBACK (ephy_autocompletion_window_selection_changed_cb), aw);
+
+ s = gtk_tree_view_get_selection (p->action_tree_view);
+ gtk_tree_selection_set_mode (s, GTK_SELECTION_MULTIPLE);
+
+ g_signal_connect (s, "changed", G_CALLBACK (ephy_autocompletion_window_selection_changed_cb), aw);
+}
+
+static void
+ephy_autocompletion_window_finalize_impl (GObject *o)
+{
+ EphyAutocompletionWindow *aw = EPHY_AUTOCOMPLETION_WINDOW (o);
+ EphyAutocompletionWindowPrivate *p = aw->priv;
+
+ if (p->list_store) g_object_unref (p->list_store);
+ if (p->action_list_store) g_object_unref (p->action_list_store);
+ if (p->parent) g_object_unref (p->parent);
+ if (p->window) gtk_widget_destroy (p->window);
+
+ if (p->autocompletion)
+ {
+ g_signal_handlers_disconnect_matched (p->autocompletion, G_SIGNAL_MATCH_DATA, 0, 0,
+ NULL, NULL, aw);
+ g_object_unref (p->autocompletion);
+ }
+
+ g_free (p->selected);
+ g_free (p);
+
+ gdk_pointer_ungrab (GDK_CURRENT_TIME);
+ gdk_keyboard_ungrab (GDK_CURRENT_TIME);
+
+ G_OBJECT_CLASS (g_object_class)->finalize (o);
+}
+
+static void
+ephy_autocompletion_window_init_widgets (EphyAutocompletionWindow *aw)
+{
+ EphyAutocompletionWindowPrivate *p = aw->priv;
+ GtkWidget *sw;
+ GtkCellRenderer *renderer;
+ GtkWidget *frame;
+ GtkWidget *vbox;
+ GdkColor *bg_color;
+ guint32 base, dark;
+ GValue v = { 0 };
+
+ p->window = gtk_window_new (GTK_WINDOW_POPUP);
+ gtk_window_set_resizable (GTK_WINDOW (p->window), FALSE);
+
+ frame = gtk_frame_new (NULL);
+ gtk_frame_set_shadow_type (GTK_FRAME (frame),
+ GTK_SHADOW_OUT);
+ gtk_container_add (GTK_CONTAINER (p->window), frame);
+ gtk_widget_show (frame);
+
+ vbox = gtk_vbox_new (FALSE, 0);
+ gtk_widget_show (vbox);
+ gtk_container_add (GTK_CONTAINER (frame), vbox);
+
+ sw = gtk_scrolled_window_new (NULL, NULL);
+ gtk_box_pack_start (GTK_BOX (vbox),
+ sw, TRUE, TRUE, 0);
+ gtk_scrolled_window_set_shadow_type
+ (GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
+ GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+ p->scrolled_window = GTK_SCROLLED_WINDOW (sw);
+ gtk_widget_show (sw);
+
+ p->tree_view = GTK_TREE_VIEW (gtk_tree_view_new ());
+ gtk_container_add (GTK_CONTAINER (sw), GTK_WIDGET (p->tree_view));
+
+ renderer = gtk_cell_renderer_text_new ();
+ p->col1 = gtk_tree_view_column_new ();
+ gtk_tree_view_column_pack_start (p->col1, renderer, TRUE);
+ gtk_tree_view_column_set_attributes (p->col1, renderer,
+ "text", 0,
+ NULL);
+ gtk_tree_view_append_column (p->tree_view, p->col1);
+
+ gtk_tree_view_set_headers_visible (p->tree_view, FALSE);
+ gtk_widget_show (GTK_WIDGET(p->tree_view));
+
+ p->action_tree_view = GTK_TREE_VIEW (gtk_tree_view_new ());
+ gtk_box_pack_start (GTK_BOX (vbox),
+ GTK_WIDGET (p->action_tree_view),
+ FALSE, TRUE, 0);
+
+ renderer = gtk_cell_renderer_text_new ();
+
+ g_value_init (&v, GDK_TYPE_COLOR);
+ g_object_get_property (G_OBJECT (renderer), "cell_background_gdk", &v);
+ bg_color = g_value_peek_pointer (&v);
+ base = ephy_gui_gdk_color_to_rgb (bg_color);
+ dark = ephy_gui_rgb_shift_color (base, 0.15);
+ *bg_color = ephy_gui_gdk_rgb_to_color (dark);
+ g_object_set_property (G_OBJECT (renderer), "cell_background_gdk", &v);
+
+ p->action_col1 = gtk_tree_view_column_new ();
+ gtk_tree_view_column_pack_start (p->action_col1, renderer, TRUE);
+ gtk_tree_view_column_set_attributes (p->action_col1, renderer,
+ "text", 0,
+ NULL);
+ gtk_tree_view_append_column (p->action_tree_view, p->action_col1);
+
+ gtk_tree_view_set_headers_visible (p->action_tree_view, FALSE);
+ gtk_widget_show (GTK_WIDGET(p->action_tree_view));
+}
+
+EphyAutocompletionWindow *
+ephy_autocompletion_window_new (EphyAutocompletion *ac, GtkWidget *w)
+{
+ EphyAutocompletionWindow *ret = g_object_new (EPHY_TYPE_AUTOCOMPLETION_WINDOW, NULL);
+ ephy_autocompletion_window_set_parent_widget (ret, w);
+ ephy_autocompletion_window_set_autocompletion (ret, ac);
+ return ret;
+}
+
+void
+ephy_autocompletion_window_set_parent_widget (EphyAutocompletionWindow *aw, GtkWidget *w)
+{
+ if (aw->priv->parent) g_object_unref (aw->priv->parent);
+ aw->priv->parent = g_object_ref (w);
+}
+
+void
+ephy_autocompletion_window_set_autocompletion (EphyAutocompletionWindow *aw,
+ EphyAutocompletion *ac)
+{
+ EphyAutocompletionWindowPrivate *p = aw->priv;
+
+ if (p->autocompletion)
+ {
+ g_signal_handlers_disconnect_matched (p->autocompletion, G_SIGNAL_MATCH_DATA, 0, 0,
+ NULL, NULL, aw);
+
+ g_object_unref (p->autocompletion);
+
+ }
+ p->autocompletion = g_object_ref (ac);
+}
+
+static void
+ephy_autocompletion_window_selection_changed_cb (GtkTreeSelection *treeselection,
+ EphyAutocompletionWindow *aw)
+{
+ GList *l;
+ GtkTreeModel *model;
+
+ if (aw->priv->selected) g_free (aw->priv->selected);
+
+ l = gtk_tree_selection_get_selected_rows (treeselection, &model);
+ if (l)
+ {
+ GtkTreePath *path;
+ GtkTreeIter iter;
+ path = (GtkTreePath *)l->data;
+
+ gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_model_get (model, &iter, 1,
+ &aw->priv->selected, -1);
+
+ g_list_foreach (l, (GFunc)gtk_tree_path_free, NULL);
+ g_list_free (l);
+ }
+ else
+ {
+ aw->priv->selected = NULL;
+ }
+}
+
+static void
+ephy_autocompletion_window_get_dimensions (EphyAutocompletionWindow *aw,
+ int *x, int *y, int *width, int *height)
+{
+ GtkBin *popwin;
+ GtkWidget *widget;
+ GtkScrolledWindow *popup;
+ gint real_height;
+ GtkRequisition list_requisition;
+ gboolean show_vscroll = FALSE;
+ gint avail_height;
+ gint min_height;
+ gint alloc_width;
+ gint work_height;
+ gint old_height;
+ gint old_width;
+ int row_height;
+
+ widget = GTK_WIDGET (aw->priv->parent);
+ popup = GTK_SCROLLED_WINDOW (aw->priv->scrolled_window);
+ popwin = GTK_BIN (aw->priv->window);
+
+ gdk_window_get_origin (widget->window, x, y);
+ real_height = MIN (widget->requisition.height,
+ widget->allocation.height);
+ *y += real_height;
+ avail_height = gdk_screen_height () - *y;
+
+ gtk_widget_size_request (GTK_WIDGET(aw->priv->tree_view),
+ &list_requisition);
+
+ alloc_width = (widget->allocation.width -
+ 2 * popwin->child->style->xthickness -
+ 2 * GTK_CONTAINER (popwin->child)->border_width -
+ 2 * GTK_CONTAINER (popup)->border_width -
+ 2 * GTK_CONTAINER (GTK_BIN (popup)->child)->border_width -
+ 2 * GTK_BIN (popup)->child->style->xthickness);
+
+ work_height = (2 * popwin->child->style->ythickness +
+ 2 * GTK_CONTAINER (popwin->child)->border_width +
+ 2 * GTK_CONTAINER (popup)->border_width +
+ 2 * GTK_CONTAINER (GTK_BIN (popup)->child)->border_width +
+ 2 * GTK_BIN (popup)->child->style->ythickness);
+
+ min_height = MIN (list_requisition.height,
+ popup->vscrollbar->requisition.height);
+
+ row_height = list_requisition.height / MAX (aw->priv->view_nitems, 1);
+ DEBUG_MSG (("Real list requisition %d, Items %d\n", list_requisition.height, aw->priv->view_nitems));
+ list_requisition.height = MIN (row_height * MAX_VISIBLE_ROWS, list_requisition.height);
+ DEBUG_MSG (("Row Height %d, Fake list requisition %d\n",
+ row_height, list_requisition.height));
+
+ do
+ {
+ old_width = alloc_width;
+ old_height = work_height;
+
+ if (!show_vscroll &&
+ work_height + list_requisition.height > avail_height)
+ {
+ if (work_height + min_height > avail_height &&
+ *y - real_height > avail_height)
+ {
+ *y -= (work_height + list_requisition.height +
+ real_height);
+ break;
+ }
+ alloc_width -= (popup->vscrollbar->requisition.width +
+ SCROLLBAR_SPACING (popup));
+ show_vscroll = TRUE;
+ }
+ } while (old_width != alloc_width || old_height != work_height);
+
+ *width = widget->allocation.width;
+
+ if (*x < 0) *x = 0;
+
+ *height = MIN (work_height + list_requisition.height,
+ avail_height);
+
+ /* Action view */
+ work_height = (2 * GTK_CONTAINER (popup)->border_width +
+ 2 * GTK_WIDGET (popup)->style->ythickness);
+
+ if (!GTK_WIDGET_VISIBLE (aw->priv->scrolled_window))
+ {
+ *height = work_height;
+ }
+
+ gtk_widget_size_request (GTK_WIDGET(aw->priv->action_tree_view),
+ &list_requisition);
+
+ if (GTK_WIDGET_VISIBLE (aw->priv->action_tree_view))
+ {
+ *height += list_requisition.height;
+ }
+}
+
+static void
+ephy_autocompletion_window_fill_store_chunk (EphyAutocompletionWindow *aw)
+{
+ EphyAutocompletionWindowPrivate *p = aw->priv;
+ const EphyAutocompletionMatch *matches;
+ guint i;
+ gboolean changed;
+ guint nmatches;
+ guint last;
+ guint completion_nitems = 0, action_nitems = 0, substring_nitems = 0;
+#ifdef DEBUG_TIME
+ GTimer *timer;
+#endif
+ DEBUG_MSG (("ACW: Filling the list from %d\n", last));
+
+#ifdef DEBUG_TIME
+ timer = g_timer_new ();
+ g_timer_start (timer);
+#endif
+
+ nmatches = ephy_autocompletion_get_num_matches (p->autocompletion);
+ matches = ephy_autocompletion_get_matches_sorted_by_score (p->autocompletion,
+ &changed);
+ if (!changed) return;
+
+ if (p->list_store) g_object_unref (p->list_store);
+ p->list_store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
+
+ if (p->action_list_store) g_object_unref (p->action_list_store);
+ p->action_list_store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
+
+ last = p->last_added_match = 0;
+
+ for (i = 0; last < nmatches; i++, last++)
+ {
+ const EphyAutocompletionMatch *m = &matches[last];
+ GtkTreeIter iter;
+ GtkListStore *store;
+
+ if (m->is_action || m->substring ||
+ completion_nitems <= MAX_COMPLETION_ALTERNATIVES)
+ {
+ if (m->is_action)
+ {
+ store = p->action_list_store;
+ action_nitems ++;
+ }
+ else if (m->substring)
+ {
+ store = p->list_store;
+ substring_nitems ++;
+ }
+ else
+ {
+ store = p->list_store;
+ completion_nitems ++;
+ }
+
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter,
+ 0, m->title,
+ 1, m->target,
+ -1);
+ }
+ }
+
+ p->view_nitems = substring_nitems + completion_nitems;
+
+ gtk_widget_show (GTK_WIDGET (p->scrolled_window));
+ gtk_widget_show (GTK_WIDGET (p->action_tree_view));
+ if (p->view_nitems == 0)
+ {
+ gtk_widget_hide (GTK_WIDGET (p->scrolled_window));
+ }
+ if (action_nitems == 0)
+ {
+ gtk_widget_hide (GTK_WIDGET (p->action_tree_view));
+ }
+
+ p->last_added_match = last;
+
+#ifdef DEBUG_TIME
+ DEBUG_MSG (("ACW: %f elapsed filling the gtkliststore\n", g_timer_elapsed (timer, NULL)));
+ g_timer_destroy (timer);
+#endif
+}
+
+void
+ephy_autocompletion_window_show (EphyAutocompletionWindow *aw)
+{
+ EphyAutocompletionWindowPrivate *p = aw->priv;
+ gint x, y, height, width;
+ guint nmatches;
+#ifdef DEBUG_TIME
+ GTimer *timer1;
+ GTimer *timer2;
+#endif
+
+ g_return_if_fail (p->window);
+ g_return_if_fail (p->autocompletion);
+
+ nmatches = ephy_autocompletion_get_num_matches (p->autocompletion);
+ if (nmatches <= 0)
+ {
+ ephy_autocompletion_window_hide (aw);
+ return;
+ }
+
+#ifdef DEBUG_TIME
+ DEBUG_MSG (("ACW: showing window.\n"));
+ timer1 = g_timer_new ();
+ g_timer_start (timer1);
+#endif
+
+#ifdef DEBUG_TIME
+ timer2 = g_timer_new ();
+ g_timer_start (timer2);
+#endif
+
+ ephy_autocompletion_window_fill_store_chunk (aw);
+
+ p->only_actions = (!GTK_WIDGET_VISIBLE (p->scrolled_window) ||
+ GTK_WIDGET_HAS_FOCUS (p->action_tree_view));
+ if (p->only_actions)
+ {
+ p->active_tree_view = p->action_tree_view;
+ }
+ else
+ {
+ p->active_tree_view = p->tree_view;
+ }
+
+#ifdef DEBUG_TIME
+ DEBUG_MSG (("ACW: %f elapsed creating liststore\n", g_timer_elapsed (timer2, NULL)));
+#endif
+
+ gtk_tree_view_set_model (p->tree_view, GTK_TREE_MODEL (p->list_store));
+ gtk_tree_view_set_model (p->action_tree_view, GTK_TREE_MODEL (p->action_list_store));
+
+#ifdef DEBUG_TIME
+ g_timer_start (timer2);
+#endif
+
+ ephy_autocompletion_window_get_dimensions (aw, &x, &y, &width, &height);
+
+#ifdef DEBUG_TIME
+ DEBUG_MSG (("ACW: %f elapsed calculating dimensions\n", g_timer_elapsed (timer2, NULL)));
+ g_timer_destroy (timer2);
+#endif
+
+ gtk_widget_set_size_request (GTK_WIDGET (p->window), width,
+ height);
+ gtk_window_move (GTK_WINDOW (p->window), x, y);
+
+ if (!p->shown)
+ {
+ gtk_widget_show (p->window);
+
+ gdk_pointer_grab (p->parent->window, TRUE,
+ GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK |
+ GDK_BUTTON_RELEASE_MASK,
+ NULL, NULL, GDK_CURRENT_TIME);
+ gdk_keyboard_grab (p->parent->window, TRUE, GDK_CURRENT_TIME);\
+ gtk_grab_add (p->window);
+
+ g_signal_connect (p->window, "button-press-event",
+ G_CALLBACK (ephy_autocompletion_window_button_press_event_cb),
+ aw);
+ g_signal_connect (p->window, "key-press-event",
+ G_CALLBACK (ephy_autocompletion_window_key_press_cb),
+ aw);
+ g_signal_connect (p->tree_view, "event-after",
+ G_CALLBACK (ephy_autocompletion_window_event_after_cb),
+ aw);
+ g_signal_connect (p->action_tree_view, "event-after",
+ G_CALLBACK (ephy_autocompletion_window_event_after_cb),
+ aw);
+
+ p->shown = TRUE;
+ }
+
+ gtk_tree_view_scroll_to_point (GTK_TREE_VIEW (p->tree_view), 0, 0);
+
+ gtk_widget_grab_focus (GTK_WIDGET (p->tree_view));
+#ifdef DEBUG_TIME
+ DEBUG_MSG (("ACW: %f elapsed showing window\n", g_timer_elapsed (timer1, NULL)));
+ g_timer_destroy (timer1);
+#endif
+}
+
+static gboolean
+ephy_autocompletion_window_button_press_event_cb (GtkWidget *widget,
+ GdkEventButton *event,
+ EphyAutocompletionWindow *aw)
+{
+ GtkWidget *event_widget;
+
+ event_widget = gtk_get_event_widget ((GdkEvent *) event);
+
+ /* Check to see if button press happened inside the alternatives
+ window. If not, destroy the window. */
+ if (event_widget != aw->priv->window)
+ {
+ while (event_widget)
+ {
+ if (event_widget == aw->priv->window)
+ return FALSE;
+ event_widget = event_widget->parent;
+ }
+ }
+ ephy_autocompletion_window_hide (aw);
+
+ return TRUE;
+}
+
+static GtkTreeView *
+hack_tree_view_move_selection (GtkTreeView *tv, GtkTreeView *alternate, int dir)
+{
+ GtkTreeSelection *ts = gtk_tree_view_get_selection (tv);
+ GtkTreeModel *model;
+ GList *selected = NULL;
+ selected = gtk_tree_selection_get_selected_rows (ts, &model);
+ gboolean prev_result = TRUE;
+
+ gtk_tree_selection_unselect_all (ts);
+
+ if (!selected)
+ {
+ GtkTreePath *p = gtk_tree_path_new_first ();
+ gtk_tree_selection_select_path (ts, p);
+ gtk_tree_view_scroll_to_cell (tv, p, NULL, FALSE, 0, 0);
+ gtk_tree_path_free (p);
+ }
+ else
+ {
+ GtkTreePath *p = selected->data;
+ int i;
+ if (dir > 0)
+ {
+ for (i = 0; i < dir; ++i)
+ {
+ gtk_tree_path_next (p);
+ }
+ }
+ else
+ {
+ for (i = 0; i > dir; --i)
+ {
+ prev_result = gtk_tree_path_prev (p);
+ }
+ }
+
+ if (prev_result)
+ {
+ gtk_tree_selection_select_path (ts, p);
+ gtk_tree_view_scroll_to_cell (tv, p, NULL, FALSE, 0, 0);
+ }
+ }
+
+ g_list_foreach (selected, (GFunc) gtk_tree_path_free, NULL);
+ g_list_free (selected);
+
+ if (!prev_result)
+ {
+ GtkTreeModel *model;
+ int c;
+ GtkTreeIter iter;
+ GtkTreePath *p;
+ GtkTreeSelection *selection;
+
+ model = gtk_tree_view_get_model (alternate);
+ c = gtk_tree_model_iter_n_children (model, NULL);
+ gtk_tree_model_iter_nth_child (model, &iter, NULL, c - 1);
+ p = gtk_tree_model_get_path (model, &iter);
+ selection = gtk_tree_view_get_selection (alternate);
+ gtk_tree_selection_select_path (selection, p);
+ gtk_tree_view_scroll_to_cell (alternate, p, NULL, FALSE, 0, 0);
+ gtk_tree_path_free (p);
+ return alternate;
+ }
+ else if (gtk_tree_selection_count_selected_rows (ts) == 0)
+ {
+ hack_tree_view_move_selection (alternate, tv, dir);
+ return alternate;
+ }
+
+ return tv;
+}
+
+static gboolean
+ephy_autocompletion_window_key_press_hack (EphyAutocompletionWindow *aw,
+ guint keyval)
+{
+ GtkTreeView *tree_view, *alt;
+ EphyAutocompletionWindowPrivate *p = aw->priv;
+ gboolean action;
+
+ action = (p->active_tree_view == p->action_tree_view);
+ tree_view = action ? p->action_tree_view : p->tree_view;
+ alt = action ? p->tree_view : p->action_tree_view;
+ alt = p->only_actions ? p->action_tree_view : alt;
+
+ switch (keyval)
+ {
+ case GDK_Up:
+ p->active_tree_view = hack_tree_view_move_selection
+ (tree_view, alt, -1);
+ break;
+ case GDK_Down:
+ p->active_tree_view = hack_tree_view_move_selection
+ (tree_view, alt, +1);
+ break;
+ case GDK_Page_Down:
+ p->active_tree_view = hack_tree_view_move_selection
+ (tree_view, alt, +5);
+ break;
+ case GDK_Page_Up:
+ p->active_tree_view = hack_tree_view_move_selection
+ (tree_view, alt, -5);
+ break;
+ case GDK_Return:
+ case GDK_space:
+ if (aw->priv->selected)
+ {
+ g_signal_emit (aw, EphyAutocompletionWindowSignals
+ [ACTIVATED], 0, aw->priv->selected, action);
+ }
+ break;
+ default:
+ g_warning ("Unexpected keyval");
+ break;
+ }
+ return TRUE;
+}
+
+static gboolean
+ephy_autocompletion_window_key_press_cb (GtkWidget *widget,
+ GdkEventKey *event,
+ EphyAutocompletionWindow *aw)
+{
+ GdkEventKey tmp_event;
+ EphyAutocompletionWindowPrivate *p = aw->priv;
+ GtkWidget *dest_widget;
+
+ /* allow keyboard navigation in the alternatives clist */
+ if (event->keyval == GDK_Up || event->keyval == GDK_Down
+ || event->keyval == GDK_Page_Up || event->keyval == GDK_Page_Down
+ || ((event->keyval == GDK_space || event->keyval == GDK_Return)
+ && p->selected))
+ {
+ return ephy_autocompletion_window_key_press_hack
+ (aw, event->keyval);
+ }
+ else
+ {
+ dest_widget = p->parent;
+ }
+
+ if (dest_widget != widget)
+ {
+ //DEBUG_MSG (("Resending event\n"));
+
+ tmp_event = *event;
+ gtk_widget_event (dest_widget, (GdkEvent *)&tmp_event);
+
+ return TRUE;
+ }
+ else
+ {
+ if (widget == GTK_WIDGET (p->tree_view))
+ {
+ //DEBUG_MSG (("on the tree view "));
+ }
+ //DEBUG_MSG (("Ignoring event\n"));
+ return FALSE;
+ }
+
+}
+
+void
+ephy_autocompletion_window_hide (EphyAutocompletionWindow *aw)
+{
+ if (aw->priv->window)
+ {
+ gtk_widget_hide (aw->priv->window);
+ gtk_grab_remove (aw->priv->window);
+ gdk_pointer_ungrab (GDK_CURRENT_TIME);
+ gdk_keyboard_ungrab (GDK_CURRENT_TIME);
+ ephy_autocompletion_window_unselect (aw);
+ g_signal_emit (aw, EphyAutocompletionWindowSignals[EPHY_AUTOCOMPLETION_WINDOW_HIDDEN], 0);
+ }
+ g_free (aw->priv->selected);
+ aw->priv->selected = NULL;
+ aw->priv->shown = FALSE;
+}
+
+void
+ephy_autocompletion_window_unselect (EphyAutocompletionWindow *aw)
+{
+ EphyAutocompletionWindowPrivate *p = aw->priv;
+ GtkTreeSelection *ts = gtk_tree_view_get_selection (p->tree_view);
+ gtk_tree_selection_unselect_all (ts);
+}
+
+static void
+ephy_autocompletion_window_event_after_cb (GtkWidget *wid, GdkEvent *event,
+ EphyAutocompletionWindow *aw)
+{
+ gboolean action;
+ EphyAutocompletionWindowPrivate *p = aw->priv;
+
+ action = (wid == GTK_WIDGET (p->action_tree_view));
+
+ if (event->type == GDK_BUTTON_PRESS
+ && ((GdkEventButton *) event)->button == 1)
+ {
+ if (p->selected)
+ {
+ g_signal_emit (aw, EphyAutocompletionWindowSignals
+ [ACTIVATED], 0, p->selected, action);
+ }
+ }
+}
diff --git a/lib/widgets/ephy-autocompletion-window.h b/lib/widgets/ephy-autocompletion-window.h
new file mode 100644
index 000000000..b390fc35c
--- /dev/null
+++ b/lib/widgets/ephy-autocompletion-window.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2002 Ricardo Fernández Pascual
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EPHY_AUTOCOMPLETION_WINDOW_H
+#define EPHY_AUTOCOMPLETION_WINDOW_H
+
+#include <glib-object.h>
+#include <gtk/gtkwidget.h>
+
+#include "ephy-autocompletion.h"
+
+G_BEGIN_DECLS
+
+/* object forward declarations */
+
+typedef struct _EphyAutocompletionWindow EphyAutocompletionWindow;
+typedef struct _EphyAutocompletionWindowClass EphyAutocompletionWindowClass;
+typedef struct _EphyAutocompletionWindowPrivate EphyAutocompletionWindowPrivate;
+
+/**
+ * Editor object
+ */
+
+#define EPHY_TYPE_AUTOCOMPLETION_WINDOW (ephy_autocompletion_window_get_type())
+#define EPHY_AUTOCOMPLETION_WINDOW(object) (G_TYPE_CHECK_INSTANCE_CAST((object), \
+ EPHY_TYPE_AUTOCOMPLETION_WINDOW,\
+ EphyAutocompletionWindow))
+#define EPHY_AUTOCOMPLETION_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), \
+ EPHY_TYPE_AUTOCOMPLETION_WINDOW,\
+ EphyAutocompletionWindowClass))
+#define EPHY_IS_AUTOCOMPLETION_WINDOW(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), \
+ EPHY_TYPE_AUTOCOMPLETION_WINDOW))
+#define EPHY_IS_AUTOCOMPLETION_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), \
+ EPHY_TYPE_AUTOCOMPLETION_WINDOW))
+#define EPHY_AUTOCOMPLETION_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), \
+ EPHY_TYPE_AUTOCOMPLETION_WINDOW,\
+ EphyAutocompletionWindowClass))
+
+struct _EphyAutocompletionWindowClass
+{
+ GObjectClass parent_class;
+
+ /* signals */
+ void (*hidden) (EphyAutocompletionWindow *aw);
+ void (*activated) (EphyAutocompletionWindow *aw,
+ const char *target,
+ int action);
+
+};
+
+/* Remember: fields are public read-only */
+struct _EphyAutocompletionWindow
+{
+ GObject parent_object;
+
+ EphyAutocompletionWindowPrivate *priv;
+};
+
+GType ephy_autocompletion_window_get_type (void);
+EphyAutocompletionWindow *ephy_autocompletion_window_new (EphyAutocompletion *ac,
+ GtkWidget *parent);
+void ephy_autocompletion_window_set_parent_widget (EphyAutocompletionWindow *aw,
+ GtkWidget *w);
+void ephy_autocompletion_window_set_autocompletion (EphyAutocompletionWindow *aw,
+ EphyAutocompletion *ac);
+void ephy_autocompletion_window_show (EphyAutocompletionWindow *aw);
+void ephy_autocompletion_window_hide (EphyAutocompletionWindow *aw);
+void ephy_autocompletion_window_unselect (EphyAutocompletionWindow *aw);
+
+G_END_DECLS
+
+#endif
diff --git a/lib/widgets/ephy-ellipsizing-label.c b/lib/widgets/ephy-ellipsizing-label.c
new file mode 100644
index 000000000..13f911078
--- /dev/null
+++ b/lib/widgets/ephy-ellipsizing-label.c
@@ -0,0 +1,774 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+
+/* eel-ellipsizing-label.c: Subclass of GtkLabel that ellipsizes the text.
+
+ Copyright (C) 2001 Eazel, Inc.
+
+ The Gnome Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The Gnome 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
+ Library General Public License for more priv.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the Gnome Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Author: John Sullivan <sullivan@eazel.com>,
+ Marco Pesenti Gritti <marco@it.gnome.org> Markup support
+ */
+
+#include "ephy-ellipsizing-label.h"
+
+#include <string.h>
+
+struct EphyEllipsizingLabelPrivate
+{
+ char *full_text;
+
+ EphyEllipsizeMode mode;
+};
+
+static void ephy_ellipsizing_label_class_init (EphyEllipsizingLabelClass *class);
+static void ephy_ellipsizing_label_init (EphyEllipsizingLabel *label);
+
+static GObjectClass *parent_class = NULL;
+
+static int
+ephy_strcmp (const char *string_a, const char *string_b)
+{
+ return strcmp (string_a == NULL ? "" : string_a,
+ string_b == NULL ? "" : string_b);
+}
+
+static gboolean
+ephy_str_is_equal (const char *string_a, const char *string_b)
+{
+ return ephy_strcmp (string_a, string_b) == 0;
+}
+
+#define ELLIPSIS "..."
+
+/* Caution: this is an _expensive_ function */
+static int
+measure_string_width (const char *string,
+ PangoLayout *layout,
+ gboolean markup)
+{
+ int width;
+
+ if (markup)
+ {
+ pango_layout_set_markup (layout, string, -1);
+ }
+ else
+ {
+ pango_layout_set_text (layout, string, -1);
+ }
+
+ pango_layout_get_pixel_size (layout, &width, NULL);
+
+ return width;
+}
+
+/* this is also plenty slow */
+static void
+compute_character_widths (const char *string,
+ PangoLayout *layout,
+ int *char_len_return,
+ int **widths_return,
+ int **cuts_return,
+ gboolean markup)
+{
+ int *widths;
+ int *offsets;
+ int *cuts;
+ int char_len;
+ int byte_len;
+ const char *p;
+ const char *nm_string;
+ int i;
+ PangoLayoutIter *iter;
+ PangoLogAttr *attrs;
+
+#define BEGINS_UTF8_CHAR(x) (((x) & 0xc0) != 0x80)
+
+ if (markup)
+ {
+ pango_layout_set_markup (layout, string, -1);
+ }
+ else
+ {
+ pango_layout_set_text (layout, string, -1);
+ }
+
+ nm_string = pango_layout_get_text (layout);
+
+ char_len = g_utf8_strlen (nm_string, -1);
+ byte_len = strlen (nm_string);
+
+ widths = g_new (int, char_len);
+ offsets = g_new (int, byte_len);
+
+ /* Create a translation table from byte index to char offset */
+ p = nm_string;
+ i = 0;
+ while (*p) {
+ int byte_index = p - nm_string;
+
+ if (BEGINS_UTF8_CHAR (*p)) {
+ offsets[byte_index] = i;
+ ++i;
+ } else {
+ offsets[byte_index] = G_MAXINT; /* segv if we try to use this */
+ }
+
+ ++p;
+ }
+
+ /* Now fill in the widths array */
+ iter = pango_layout_get_iter (layout);
+
+ do {
+ PangoRectangle extents;
+ int byte_index;
+
+ byte_index = pango_layout_iter_get_index (iter);
+
+ if (byte_index < byte_len) {
+ pango_layout_iter_get_char_extents (iter, &extents);
+
+ g_assert (BEGINS_UTF8_CHAR (nm_string[byte_index]));
+ g_assert (offsets[byte_index] < char_len);
+
+ widths[offsets[byte_index]] = PANGO_PIXELS (extents.width);
+ }
+
+ } while (pango_layout_iter_next_char (iter));
+
+ pango_layout_iter_free (iter);
+
+ g_free (offsets);
+
+ *widths_return = widths;
+
+ /* Now compute character offsets that are legitimate places to
+ * chop the string
+ */
+ attrs = g_new (PangoLogAttr, char_len + 1);
+
+ pango_get_log_attrs (nm_string, byte_len, -1,
+ pango_context_get_language (
+ pango_layout_get_context (layout)),
+ attrs,
+ char_len + 1);
+
+ cuts = g_new (int, char_len);
+ i = 0;
+ while (i < char_len) {
+ cuts[i] = attrs[i].is_cursor_position;
+
+ ++i;
+ }
+
+ g_free (attrs);
+
+ *cuts_return = cuts;
+
+ *char_len_return = char_len;
+}
+
+typedef struct
+{
+ GString *string;
+ int start_offset;
+ int end_offset;
+ int position;
+} EllipsizeStringData;
+
+static void
+start_element_handler (GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ gpointer user_data,
+ GError **error)
+{
+ EllipsizeStringData *data = (EllipsizeStringData *)user_data;
+ int i;
+
+ g_string_append_c (data->string, '<');
+ g_string_append (data->string, element_name);
+
+ for (i = 0; attribute_names[i] != NULL; i++)
+ {
+ g_string_append_c (data->string, ' ');
+ g_string_append (data->string, attribute_names[i]);
+ g_string_append (data->string, "=\"");
+ g_string_append (data->string, attribute_values[i]);
+ g_string_append_c (data->string, '"');
+ }
+
+ g_string_append_c (data->string, '>');
+}
+
+static void
+end_element_handler (GMarkupParseContext *context,
+ const gchar *element_name,
+ gpointer user_data,
+ GError **error)
+{
+ EllipsizeStringData *data = (EllipsizeStringData *)user_data;
+
+ g_string_append (data->string, "</");
+ g_string_append (data->string, element_name);
+ g_string_append_c (data->string, '>');
+}
+
+static void
+append_ellipsized_text (const char *text,
+ EllipsizeStringData *data,
+ int text_len)
+{
+ int position;
+ int new_position;
+
+ position = data->position;
+ new_position = data->position + text_len;
+
+ if (position > data->start_offset &&
+ new_position < data->end_offset)
+ {
+ return;
+ }
+ else if ((position < data->start_offset &&
+ new_position < data->start_offset) ||
+ (position > data->end_offset &&
+ new_position > data->end_offset))
+ {
+ g_string_append (data->string,
+ text);
+ }
+ else if (position <= data->start_offset &&
+ new_position >= data->end_offset)
+ {
+ if (position < data->start_offset)
+ {
+ g_string_append_len (data->string,
+ text,
+ data->start_offset -
+ position);
+ }
+
+ g_string_append (data->string,
+ ELLIPSIS);
+
+ if (new_position > data->end_offset)
+ {
+ g_string_append_len (data->string,
+ text + data->end_offset -
+ position,
+ position + text_len -
+ data->end_offset);
+ }
+ }
+
+ data->position = new_position;
+}
+
+static void
+text_handler (GMarkupParseContext *context,
+ const gchar *text,
+ gsize text_len,
+ gpointer user_data,
+ GError **error)
+{
+ EllipsizeStringData *data = (EllipsizeStringData *)user_data;
+
+ append_ellipsized_text (text, data, text_len);
+}
+
+static GMarkupParser pango_markup_parser = {
+ start_element_handler,
+ end_element_handler,
+ text_handler,
+ NULL,
+ NULL
+};
+
+static char *
+ellipsize_string (const char *string,
+ int start_offset,
+ int end_offset,
+ gboolean markup)
+{
+ GString *str;
+ EllipsizeStringData data;
+ char *result;
+ GMarkupParseContext *c;
+
+ str = g_string_new (NULL);
+ data.string = str;
+ data.start_offset = start_offset;
+ data.end_offset = end_offset;
+ data.position = 0;
+
+ if (markup)
+ {
+ c = g_markup_parse_context_new (&pango_markup_parser,
+ 0, &data, NULL);
+ g_markup_parse_context_parse (c, string, -1, NULL);
+ g_markup_parse_context_free (c);
+ }
+ else
+ {
+ append_ellipsized_text (string, &data,
+ g_utf8_strlen (string, -1));
+ }
+
+ result = str->str;
+ g_string_free (str, FALSE);
+ return result;
+}
+
+static char *
+ephy_string_ellipsize_start (const char *string, PangoLayout *layout, int width, gboolean markup)
+{
+ int resulting_width;
+ int *cuts;
+ int *widths;
+ int char_len;
+ int truncate_offset;
+ int bytes_end;
+
+ /* Zero-length string can't get shorter - catch this here to
+ * avoid expensive calculations
+ */
+ if (*string == '\0')
+ return g_strdup ("");
+
+ /* I'm not sure if this short-circuit is a net win; it might be better
+ * to just dump this, and always do the compute_character_widths() etc.
+ * down below.
+ */
+ resulting_width = measure_string_width (string, layout, markup);
+
+ if (resulting_width <= width) {
+ /* String is already short enough. */
+ return g_strdup (string);
+ }
+
+ /* Remove width of an ellipsis */
+ width -= measure_string_width (ELLIPSIS, layout, markup);
+
+ if (width < 0) {
+ /* No room even for an ellipsis. */
+ return g_strdup ("");
+ }
+
+ /* Our algorithm involves removing enough chars from the string to bring
+ * the width to the required small size. However, due to ligatures,
+ * combining characters, etc., it's not guaranteed that the algorithm
+ * always works 100%. It's sort of a heuristic thing. It should work
+ * nearly all the time... but I wouldn't put in
+ * g_assert (width of resulting string < width).
+ *
+ * Hmm, another thing that this breaks with is explicit line breaks
+ * in "string"
+ */
+
+ compute_character_widths (string, layout, &char_len, &widths, &cuts, markup);
+
+ for (truncate_offset = 1; truncate_offset < char_len; truncate_offset++) {
+
+ resulting_width -= widths[truncate_offset];
+
+ if (resulting_width <= width &&
+ cuts[truncate_offset]) {
+ break;
+ }
+ }
+
+ g_free (cuts);
+ g_free (widths);
+
+ bytes_end = g_utf8_offset_to_pointer (string, truncate_offset) - string;
+
+ return ellipsize_string (string, 0, bytes_end, markup);
+}
+
+static char *
+ephy_string_ellipsize_end (const char *string, PangoLayout *layout, int width, gboolean markup)
+{
+ int resulting_width;
+ int *cuts;
+ int *widths;
+ int char_len;
+ int truncate_offset;
+ int bytes_end;
+
+ /* See explanatory comments in ellipsize_start */
+
+ if (*string == '\0')
+ return g_strdup ("");
+
+ resulting_width = measure_string_width (string, layout, markup);
+
+ if (resulting_width <= width) {
+ return g_strdup (string);
+ }
+
+ width -= measure_string_width (ELLIPSIS, layout, markup);
+
+ if (width < 0) {
+ return g_strdup ("");
+ }
+
+ compute_character_widths (string, layout, &char_len, &widths, &cuts, markup);
+
+ for (truncate_offset = char_len - 1; truncate_offset > 0; truncate_offset--) {
+ resulting_width -= widths[truncate_offset];
+ if (resulting_width <= width &&
+ cuts[truncate_offset]) {
+ break;
+ }
+ }
+
+ g_free (cuts);
+ g_free (widths);
+
+ bytes_end = g_utf8_offset_to_pointer (string, truncate_offset) - string;
+
+ return ellipsize_string (string, bytes_end,
+ char_len, markup);
+}
+
+static char *
+ephy_string_ellipsize_middle (const char *string, PangoLayout *layout, int width, gboolean markup)
+{
+ int resulting_width;
+ int *cuts;
+ int *widths;
+ int char_len;
+ int starting_fragment_length;
+ int ending_fragment_offset;
+ int bytes_start;
+ int bytes_end;
+
+ /* See explanatory comments in ellipsize_start */
+
+ if (*string == '\0')
+ return g_strdup ("");
+
+ resulting_width = measure_string_width (string, layout, markup);
+
+ if (resulting_width <= width) {
+ return g_strdup (string);
+ }
+
+ width -= measure_string_width (ELLIPSIS, layout, markup);
+
+ if (width < 0) {
+ return g_strdup ("");
+ }
+
+ compute_character_widths (string, layout, &char_len, &widths, &cuts, markup);
+
+ starting_fragment_length = char_len / 2;
+ ending_fragment_offset = starting_fragment_length + 1;
+
+ /* depending on whether the original string length is odd or even, start by
+ * shaving off the characters from the starting or ending fragment
+ */
+ if (char_len % 2) {
+ goto shave_end;
+ }
+
+ while (starting_fragment_length > 0 || ending_fragment_offset < char_len) {
+ if (resulting_width <= width &&
+ cuts[ending_fragment_offset] &&
+ cuts[starting_fragment_length]) {
+ break;
+ }
+
+ if (starting_fragment_length > 0) {
+ resulting_width -= widths[starting_fragment_length];
+ starting_fragment_length--;
+ }
+
+ shave_end:
+ if (resulting_width <= width &&
+ cuts[ending_fragment_offset] &&
+ cuts[starting_fragment_length]) {
+ break;
+ }
+
+ if (ending_fragment_offset < char_len) {
+ resulting_width -= widths[ending_fragment_offset];
+ ending_fragment_offset++;
+ }
+ }
+
+ g_free (cuts);
+ g_free (widths);
+
+ bytes_start = g_utf8_offset_to_pointer (string, starting_fragment_length) - string;
+ bytes_end = g_utf8_offset_to_pointer (string, ending_fragment_offset) - string;
+
+ return ellipsize_string (string, bytes_start, bytes_end, markup);
+}
+
+
+/**
+ * ephy_pango_layout_set_text_ellipsized
+ *
+ * @layout: a pango layout
+ * @string: A a string to be ellipsized.
+ * @width: Desired maximum width in points.
+ * @mode: The desired ellipsizing mode.
+ *
+ * Truncates a string if required to fit in @width and sets it on the
+ * layout. Truncation involves removing characters from the start, middle or end
+ * respectively and replacing them with "...". Algorithm is a bit
+ * fuzzy, won't work 100%.
+ *
+ */
+static void
+gul_pango_layout_set_text_ellipsized (PangoLayout *layout,
+ const char *string,
+ int width,
+ EphyEllipsizeMode mode,
+ gboolean markup)
+{
+ char *s;
+
+ g_return_if_fail (PANGO_IS_LAYOUT (layout));
+ g_return_if_fail (string != NULL);
+ g_return_if_fail (width >= 0);
+
+ switch (mode) {
+ case EPHY_ELLIPSIZE_START:
+ s = ephy_string_ellipsize_start (string, layout, width, markup);
+ break;
+ case EPHY_ELLIPSIZE_MIDDLE:
+ s = ephy_string_ellipsize_middle (string, layout, width, markup);
+ break;
+ case EPHY_ELLIPSIZE_END:
+ s = ephy_string_ellipsize_end (string, layout, width, markup);
+ break;
+ default:
+ g_return_if_reached ();
+ s = NULL;
+ }
+
+ if (markup)
+ {
+ pango_layout_set_markup (layout, s, -1);
+ }
+ else
+ {
+ pango_layout_set_text (layout, s, -1);
+ }
+
+ g_free (s);
+}
+
+GType
+ephy_ellipsizing_label_get_type (void)
+{
+ static GType ephy_ellipsizing_label_type = 0;
+
+ if (ephy_ellipsizing_label_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (EphyEllipsizingLabelClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) ephy_ellipsizing_label_class_init,
+ NULL,
+ NULL, /* class_data */
+ sizeof (EphyEllipsizingLabel),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) ephy_ellipsizing_label_init
+ };
+
+ ephy_ellipsizing_label_type = g_type_register_static (GTK_TYPE_LABEL,
+ "EphyEllipsizingLabel",
+ &our_info, 0);
+ }
+
+ return ephy_ellipsizing_label_type;
+}
+
+static void
+ephy_ellipsizing_label_init (EphyEllipsizingLabel *label)
+{
+ label->priv = g_new0 (EphyEllipsizingLabelPrivate, 1);
+
+ label->priv->mode = EPHY_ELLIPSIZE_NONE;
+}
+
+static void
+real_finalize (GObject *object)
+{
+ EphyEllipsizingLabel *label;
+
+ label = EPHY_ELLIPSIZING_LABEL (object);
+
+ g_free (label->priv->full_text);
+ g_free (label->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+GtkWidget*
+ephy_ellipsizing_label_new (const char *string)
+{
+ EphyEllipsizingLabel *label;
+
+ label = g_object_new (EPHY_TYPE_ELLIPSIZING_LABEL, NULL);
+ ephy_ellipsizing_label_set_text (label, string);
+
+ return GTK_WIDGET (label);
+}
+
+void
+ephy_ellipsizing_label_set_text (EphyEllipsizingLabel *label,
+ const char *string)
+{
+ g_return_if_fail (EPHY_IS_ELLIPSIZING_LABEL (label));
+
+ if (ephy_str_is_equal (string, label->priv->full_text)) {
+ return;
+ }
+
+ g_free (label->priv->full_text);
+ label->priv->full_text = g_strdup (string);
+
+ /* Queues a resize as side effect */
+ gtk_label_set_text (GTK_LABEL (label), label->priv->full_text);
+}
+
+void
+ephy_ellipsizing_label_set_markup (EphyEllipsizingLabel *label,
+ const char *string)
+{
+ g_return_if_fail (EPHY_IS_ELLIPSIZING_LABEL (label));
+
+ if (ephy_str_is_equal (string, label->priv->full_text)) {
+ return;
+ }
+
+ g_free (label->priv->full_text);
+ label->priv->full_text = g_strdup (string);
+
+ /* Queues a resize as side effect */
+ gtk_label_set_markup (GTK_LABEL (label), label->priv->full_text);
+}
+
+void
+ephy_ellipsizing_label_set_mode (EphyEllipsizingLabel *label,
+ EphyEllipsizeMode mode)
+{
+ g_return_if_fail (EPHY_IS_ELLIPSIZING_LABEL (label));
+
+ label->priv->mode = mode;
+}
+
+static void
+real_size_request (GtkWidget *widget, GtkRequisition *requisition)
+{
+ GTK_WIDGET_CLASS (parent_class)->size_request (widget, requisition);
+
+ /* Don't demand any particular width; will draw ellipsized into whatever size we're given */
+ requisition->width = 0;
+}
+
+static void
+real_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
+{
+ EphyEllipsizingLabel *label;
+ gboolean markup;
+
+ markup = gtk_label_get_use_markup (GTK_LABEL (widget));
+
+ label = EPHY_ELLIPSIZING_LABEL (widget);
+
+ /* This is the bad hack of the century, using private
+ * GtkLabel layout object. If the layout is NULL
+ * then it got blown away since size request,
+ * we just punt in that case, I don't know what to do really.
+ */
+
+ if (GTK_LABEL (label)->layout != NULL) {
+ if (label->priv->full_text == NULL) {
+ pango_layout_set_text (GTK_LABEL (label)->layout, "", -1);
+ } else {
+ EphyEllipsizeMode mode;
+
+ if (label->priv->mode != EPHY_ELLIPSIZE_NONE)
+ mode = label->priv->mode;
+
+ if (ABS (GTK_MISC (label)->xalign - 0.5) < 1e-12)
+ mode = EPHY_ELLIPSIZE_MIDDLE;
+ else if (GTK_MISC (label)->xalign < 0.5)
+ mode = EPHY_ELLIPSIZE_END;
+ else
+ mode = EPHY_ELLIPSIZE_START;
+
+ gul_pango_layout_set_text_ellipsized (GTK_LABEL (label)->layout,
+ label->priv->full_text,
+ allocation->width,
+ mode,
+ markup);
+
+ gtk_widget_queue_draw (GTK_WIDGET (label));
+ }
+ }
+
+ GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, allocation);
+}
+
+static gboolean
+real_expose_event (GtkWidget *widget, GdkEventExpose *event)
+{
+ EphyEllipsizingLabel *label;
+ GtkRequisition req;
+
+ label = EPHY_ELLIPSIZING_LABEL (widget);
+
+ /* push/pop the actual size so expose draws in the right
+ * place, yes this is bad hack central. Here we assume the
+ * ellipsized text has been set on the layout in size_allocate
+ */
+ GTK_WIDGET_CLASS (parent_class)->size_request (widget, &req);
+ widget->requisition.width = req.width;
+ GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event);
+ widget->requisition.width = 0;
+
+ return FALSE;
+}
+
+
+static void
+ephy_ellipsizing_label_class_init (EphyEllipsizingLabelClass *klass)
+{
+ GtkWidgetClass *widget_class;
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ widget_class = GTK_WIDGET_CLASS (klass);
+
+ G_OBJECT_CLASS (klass)->finalize = real_finalize;
+
+ widget_class->size_request = real_size_request;
+ widget_class->size_allocate = real_size_allocate;
+ widget_class->expose_event = real_expose_event;
+}
+
diff --git a/lib/widgets/ephy-ellipsizing-label.h b/lib/widgets/ephy-ellipsizing-label.h
new file mode 100644
index 000000000..6f596edfa
--- /dev/null
+++ b/lib/widgets/ephy-ellipsizing-label.h
@@ -0,0 +1,71 @@
+/* eel-ellipsizing-label.h: Subclass of GtkLabel that ellipsizes the text.
+
+ Copyright (C) 2001 Eazel, Inc.
+
+ The Gnome Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The Gnome 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the Gnome Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Author: John Sullivan <sullivan@eazel.com>,
+ */
+
+#ifndef EPHY_ELLIPSIZING_LABEL_H
+#define EPHY_ELLIPSIZING_LABEL_H
+
+#include <gtk/gtklabel.h>
+
+#define EPHY_TYPE_ELLIPSIZING_LABEL (ephy_ellipsizing_label_get_type ())
+#define EPHY_ELLIPSIZING_LABEL(obj) (GTK_CHECK_CAST ((obj), EPHY_TYPE_ELLIPSIZING_LABEL, EphyEllipsizingLabel))
+#define EPHY_ELLIPSIZING_LABEL_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), EPHY_TYPE_ELLIPSIZING_LABEL, EphyEllipsizingLabelClass))
+#define EPHY_IS_ELLIPSIZING_LABEL(obj) (GTK_CHECK_TYPE ((obj), EPHY_TYPE_ELLIPSIZING_LABEL))
+#define EPHY_IS_ELLIPSIZING_LABEL_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), EPHY_TYPE_ELLIPSIZING_LABEL))
+
+typedef struct EphyEllipsizingLabelPrivate EphyEllipsizingLabelPrivate;
+
+typedef enum
+{
+ EPHY_ELLIPSIZE_NONE,
+ EPHY_ELLIPSIZE_START,
+ EPHY_ELLIPSIZE_MIDDLE,
+ EPHY_ELLIPSIZE_END
+} EphyEllipsizeMode;
+
+typedef struct
+{
+ GtkLabel parent;
+
+ EphyEllipsizingLabelPrivate *priv;
+} EphyEllipsizingLabel;
+
+typedef struct
+{
+ GtkLabelClass parent_class;
+} EphyEllipsizingLabelClass;
+
+GtkType ephy_ellipsizing_label_get_type (void);
+
+GtkWidget *ephy_ellipsizing_label_new (const char *string);
+
+void ephy_ellipsizing_label_set_mode (EphyEllipsizingLabel *label,
+ EphyEllipsizeMode mode);
+
+void ephy_ellipsizing_label_set_text (EphyEllipsizingLabel *label,
+ const char *string);
+
+void ephy_ellipsizing_label_set_markup (EphyEllipsizingLabel *label,
+ const char *string);
+
+G_END_DECLS
+
+#endif /* EPHY_ELLIPSIZING_LABEL_H */
diff --git a/lib/widgets/ephy-location-entry.c b/lib/widgets/ephy-location-entry.c
new file mode 100644
index 000000000..b0669f89f
--- /dev/null
+++ b/lib/widgets/ephy-location-entry.c
@@ -0,0 +1,700 @@
+/*
+ * Copyright (C) 2002 Ricardo Fernández Pascual
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "ephy-location-entry.h"
+#include "ephy-autocompletion-window.h"
+#include "ephy-marshal.h"
+#include "ephy-gobject-misc.h"
+#include "eel-gconf-extensions.h"
+#include "ephy-prefs.h"
+
+#include <gtk/gtkentry.h>
+#include <gtk/gtkwindow.h>
+#include <gdk/gdkkeysyms.h>
+#include <gtk/gtkmain.h>
+#include <libgnomeui/gnome-entry.h>
+#include <string.h>
+
+//#define DEBUG_MSG(x) g_print x
+#define DEBUG_MSG(x)
+
+#define NOT_IMPLEMENTED g_warning ("not implemented: " G_STRLOC);
+
+/**
+ * Private data
+ */
+struct _EphyLocationEntryPrivate {
+ GtkWidget *combo;
+ GtkWidget *entry;
+ gchar *before_completion;
+ EphyAutocompletion *autocompletion;
+ EphyAutocompletionWindow *autocompletion_window;
+ gboolean autocompletion_window_visible;
+ gint autocompletion_timeout;
+ gint show_alternatives_timeout;
+ gboolean block_set_autocompletion_key;
+
+ gchar *autocompletion_key;
+ gchar *last_completion;
+ char *last_action_target;
+};
+
+#define AUTOCOMPLETION_DELAY 10
+#define SHOW_ALTERNATIVES_DELAY 100
+
+/**
+ * Private functions, only availble from this file
+ */
+static void ephy_location_entry_class_init (EphyLocationEntryClass *klass);
+static void ephy_location_entry_init (EphyLocationEntry *w);
+static void ephy_location_entry_finalize_impl (GObject *o);
+static void ephy_location_entry_build (EphyLocationEntry *w);
+static gboolean ephy_location_entry_key_press_event_cb (GtkWidget *entry, GdkEventKey *event,
+ EphyLocationEntry *w);
+static void ephy_location_entry_activate_cb (GtkEntry *entry,
+ EphyLocationEntry *w);
+static void ephy_location_entry_autocompletion_sources_changed_cb (EphyAutocompletion *aw,
+ EphyLocationEntry *w);
+static gint ephy_location_entry_autocompletion_to (EphyLocationEntry *w);
+static gint ephy_location_entry_autocompletion_show_alternatives_to (EphyLocationEntry *w);
+static void ephy_location_entry_autocompletion_window_url_activated_cb
+/***/ (EphyAutocompletionWindow *aw,
+ const gchar *target,
+ int action,
+ EphyLocationEntry *w);
+static void ephy_location_entry_list_event_after_cb (GtkWidget *list,
+ GdkEvent *event,
+ EphyLocationEntry *e);
+static void ephy_location_entry_editable_changed_cb (GtkEditable *editable,
+ EphyLocationEntry *e);
+static void ephy_location_entry_set_autocompletion_key (EphyLocationEntry *e);
+static void ephy_location_entry_autocompletion_show_alternatives (EphyLocationEntry *w);
+static void ephy_location_entry_autocompletion_hide_alternatives (EphyLocationEntry *w);
+static void ephy_location_entry_autocompletion_window_hidden_cb (EphyAutocompletionWindow *aw,
+ EphyLocationEntry *w);
+
+
+
+
+static gpointer gtk_hbox_class;
+
+/**
+ * Signals enums and ids
+ */
+enum EphyLocationEntrySignalsEnum {
+ ACTIVATED,
+ LAST_SIGNAL
+};
+static gint EphyLocationEntrySignals[LAST_SIGNAL];
+
+/**
+ * EphyLocationEntry object
+ */
+
+MAKE_GET_TYPE (ephy_location_entry, "EphyLocationEntry", EphyLocationEntry,
+ ephy_location_entry_class_init,
+ ephy_location_entry_init, GTK_TYPE_HBOX);
+
+static void
+ephy_location_entry_class_init (EphyLocationEntryClass *klass)
+{
+ G_OBJECT_CLASS (klass)->finalize = ephy_location_entry_finalize_impl;
+ gtk_hbox_class = g_type_class_peek_parent (klass);
+
+ EphyLocationEntrySignals[ACTIVATED] = g_signal_new (
+ "activated", G_OBJECT_CLASS_TYPE (klass),
+ G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST | G_SIGNAL_RUN_CLEANUP,
+ G_STRUCT_OFFSET (EphyLocationEntryClass, activated),
+ NULL, NULL,
+ ephy_marshal_VOID__STRING_STRING,
+ G_TYPE_NONE,
+ 2,
+ G_TYPE_STRING,
+ G_TYPE_STRING);
+}
+
+static void
+ephy_location_entry_init (EphyLocationEntry *w)
+{
+ EphyLocationEntryPrivate *p = g_new0 (EphyLocationEntryPrivate, 1);
+ w->priv = p;
+ p->last_action_target = NULL;
+
+ ephy_location_entry_build (w);
+}
+
+static void
+ephy_location_entry_finalize_impl (GObject *o)
+{
+ EphyLocationEntry *w = EPHY_LOCATION_ENTRY (o);
+ EphyLocationEntryPrivate *p = w->priv;
+
+ if (p->autocompletion)
+ {
+ g_signal_handlers_disconnect_matched (p->autocompletion, G_SIGNAL_MATCH_DATA, 0, 0,
+ NULL, NULL, w);
+
+ g_signal_handlers_disconnect_matched (p->autocompletion_window, G_SIGNAL_MATCH_DATA, 0, 0,
+ NULL, NULL, w);
+
+ g_object_unref (G_OBJECT (p->autocompletion));
+ g_object_unref (G_OBJECT (p->autocompletion_window));
+ }
+
+ DEBUG_MSG (("EphyLocationEntry finalized\n"));
+
+ g_free (p);
+ G_OBJECT_CLASS (gtk_hbox_class)->finalize (o);
+}
+
+EphyLocationEntry *
+ephy_location_entry_new (void)
+{
+ return EPHY_LOCATION_ENTRY (g_object_new (EPHY_TYPE_LOCATION_ENTRY, NULL));
+}
+
+static void
+ephy_location_entry_build (EphyLocationEntry *w)
+{
+ EphyLocationEntryPrivate *p = w->priv;
+ GtkWidget *list;
+
+ p->combo = gnome_entry_new ("ephy-url-history");
+ p->entry = GTK_COMBO (p->combo)->entry;
+ gtk_widget_show (p->combo);
+ gtk_box_pack_start (GTK_BOX (w), p->combo, TRUE, TRUE, 0);
+
+ g_signal_connect (p->entry, "key-press-event",
+ G_CALLBACK (ephy_location_entry_key_press_event_cb), w);
+
+ g_signal_connect (p->entry, "activate",
+ G_CALLBACK (ephy_location_entry_activate_cb), w);
+
+ g_signal_connect (p->entry, "changed",
+ G_CALLBACK (ephy_location_entry_editable_changed_cb), w);
+
+ list = GTK_COMBO (p->combo)->list;
+
+ g_signal_connect_after (list, "event-after",
+ G_CALLBACK (ephy_location_entry_list_event_after_cb), w);
+
+}
+
+static gboolean
+ephy_location_ignore_prefix (EphyLocationEntry *w)
+{
+ char *text;
+ int text_len;
+ int i, k;
+ gboolean result = FALSE;
+ static const gchar *prefixes[] = {
+ EPHY_AUTOCOMPLETION_USUAL_WEB_PREFIXES,
+ NULL
+ };
+
+ text = ephy_location_entry_get_location (w);
+ text_len = g_utf8_strlen (text, -1);
+
+ for (i = 0; prefixes[i] != NULL; i++)
+ {
+ const char *prefix = prefixes[i];
+
+ for (k = 0; k < g_utf8_strlen (prefix, -1); k++)
+ {
+ if (text_len == (k + 1) &&
+ (strncmp (text, prefix, k + 1) == 0))
+ {
+ result = TRUE;
+ }
+ }
+ }
+
+ g_free (text);
+
+ return result;
+}
+
+static gint
+ephy_location_entry_autocompletion_show_alternatives_to (EphyLocationEntry *w)
+{
+ EphyLocationEntryPrivate *p = w->priv;
+
+ if (ephy_location_ignore_prefix (w)) return FALSE;
+
+ if (p->autocompletion)
+ {
+ DEBUG_MSG (("+ephy_location_entry_autocompletion_show_alternatives_to\n"));
+ ephy_location_entry_set_autocompletion_key (w);
+ ephy_location_entry_autocompletion_show_alternatives (w);
+ }
+ p->show_alternatives_timeout = 0;
+ return FALSE;
+}
+
+static void
+ephy_location_entry_autocompletion_hide_alternatives (EphyLocationEntry *w)
+{
+ EphyLocationEntryPrivate *p = w->priv;
+ if (p->autocompletion_window)
+ {
+ ephy_autocompletion_window_hide (p->autocompletion_window);
+ p->autocompletion_window_visible = FALSE;
+ }
+}
+
+static void
+ephy_location_entry_autocompletion_show_alternatives (EphyLocationEntry *w)
+{
+ EphyLocationEntryPrivate *p = w->priv;
+ if (p->autocompletion_window)
+ {
+ ephy_autocompletion_window_show (p->autocompletion_window);
+ p->autocompletion_window_visible = TRUE;
+ }
+}
+
+static void
+ephy_location_entry_autocompletion_unselect_alternatives (EphyLocationEntry *w)
+{
+ EphyLocationEntryPrivate *p = w->priv;
+ if (p->autocompletion_window)
+ {
+ ephy_autocompletion_window_unselect (p->autocompletion_window);
+ }
+}
+
+static gint
+ephy_location_entry_autocompletion_to (EphyLocationEntry *w)
+{
+ EphyLocationEntryPrivate *p = w->priv;
+ gchar *text;
+ gchar *common_prefix;
+
+ DEBUG_MSG (("in ephy_location_entry_autocompletion_to\n"));
+
+ ephy_location_entry_set_autocompletion_key (w);
+
+ {
+ GtkEditable *editable = GTK_EDITABLE (p->entry);
+ gint sstart, send;
+ gint pos = gtk_editable_get_position (editable);
+ const gchar *text = gtk_entry_get_text (GTK_ENTRY (p->entry));
+ gint text_len = strlen (text);
+ gtk_editable_get_selection_bounds (editable, &sstart, &send);
+
+ if (pos != text_len
+ || send != text_len)
+ {
+ /* the user is editing the entry, don't mess it */
+ DEBUG_MSG (("The user seems editing the text: pos = %d, strlen (text) = %d, sstart = %d, send = %d\n",
+ pos, strlen (text), sstart, send));
+ p->autocompletion_timeout = 0;
+ return FALSE;
+ }
+ }
+
+ common_prefix = ephy_autocompletion_get_common_prefix (p->autocompletion);
+
+ DEBUG_MSG (("common_prefix: %s\n", common_prefix));
+
+ if (common_prefix && (!p->before_completion || p->before_completion[0] == '\0'))
+ {
+ text = ephy_location_entry_get_location (w);
+ g_free (p->before_completion);
+ p->before_completion = text;
+ }
+
+ if (common_prefix)
+ {
+ /* check original length */
+ guint text_len = strlen (p->autocompletion_key);
+
+ p->block_set_autocompletion_key = TRUE;
+
+ /* set entry to completed text */
+ gtk_entry_set_text (GTK_ENTRY (p->entry), common_prefix);
+
+ /* move selection appropriately */
+ gtk_editable_select_region (GTK_EDITABLE (p->entry), text_len, -1);
+
+ p->block_set_autocompletion_key = FALSE;
+
+ g_free (p->last_completion);
+ p->last_completion = common_prefix;
+ }
+
+ p->autocompletion_timeout = 0;
+ return FALSE;
+}
+
+/* this is from the old location entry, need to do the autocompletion before implementing this */
+static gboolean
+ephy_location_entry_key_press_event_cb (GtkWidget *entry, GdkEventKey *event, EphyLocationEntry *w)
+{
+ EphyLocationEntryPrivate *p = w->priv;
+ static gboolean suggest = FALSE;
+ guint keyval = event->keyval;
+
+ if (p->autocompletion_timeout != 0)
+ {
+ gtk_timeout_remove (p->autocompletion_timeout);
+ p->autocompletion_timeout = 0;
+ }
+
+ if (p->show_alternatives_timeout != 0)
+ {
+ gtk_timeout_remove (p->show_alternatives_timeout);
+ p->show_alternatives_timeout = 0;
+ }
+
+ /* only suggest heuristic completions if TAB is hit twice */
+ if (event->keyval != GDK_Tab)
+ {
+ suggest = FALSE;
+ }
+
+ if (((event->state & GDK_Control_L || event->state & GDK_Control_R) &&
+ (keyval == GDK_a || keyval == GDK_b || keyval == GDK_c ||
+ keyval == GDK_d || keyval == GDK_e || keyval == GDK_f ||
+ keyval == GDK_h || keyval == GDK_k || keyval == GDK_u ||
+ keyval == GDK_v || keyval == GDK_w || keyval == GDK_x)) ||
+ (event->state == 0 && event->keyval == GDK_BackSpace))
+ {
+ ephy_location_entry_autocompletion_hide_alternatives (w);
+ return FALSE;
+ }
+
+ /* don't grab alt combos, thus you can still access the menus. */
+ if (event->state & GDK_MOD1_MASK)
+ {
+ ephy_location_entry_autocompletion_hide_alternatives (w);
+ return FALSE;
+ }
+
+ /* make sure the end key works at all times */
+ if ((!((event->state & GDK_SHIFT_MASK) ||
+ (event->state & GDK_CONTROL_MASK) ||
+ (event->state & GDK_MOD1_MASK))
+ && (event->keyval == GDK_End)))
+ {
+ ephy_location_entry_autocompletion_hide_alternatives (w);
+ gtk_editable_select_region (GTK_EDITABLE (p->entry), 0, 0);
+ gtk_editable_set_position (GTK_EDITABLE (p->entry), -1);
+ ephy_location_entry_autocompletion_unselect_alternatives (w);
+ return TRUE;
+ }
+
+ switch (event->keyval)
+ {
+ case GDK_Left:
+ case GDK_Right:
+ ephy_location_entry_autocompletion_hide_alternatives (w);
+ return FALSE;
+ case GDK_Up:
+ case GDK_Down:
+ case GDK_Page_Up:
+ case GDK_Page_Down:
+ ephy_location_entry_autocompletion_hide_alternatives (w);
+ //ephy_embed_grab_focus (window->active_embed);
+ return FALSE;
+ case GDK_Tab:
+ {
+ gchar *common_prefix = NULL;
+ gchar *text;
+
+ ephy_location_entry_set_autocompletion_key (w);
+
+ gtk_editable_delete_selection (GTK_EDITABLE (p->entry));
+ text = ephy_location_entry_get_location (w);
+ ephy_location_entry_autocompletion_unselect_alternatives (w);
+
+ if (p->autocompletion)
+ {
+ common_prefix = ephy_autocompletion_get_common_prefix (p->autocompletion);
+ }
+ suggest = FALSE;
+ if (common_prefix)
+ {
+ if (!p->before_completion)
+ {
+ p->before_completion = g_strdup (text);
+ }
+
+ p->block_set_autocompletion_key = TRUE;
+
+ gtk_entry_set_text (GTK_ENTRY (p->entry), common_prefix);
+ gtk_editable_set_position (GTK_EDITABLE (p->entry), -1);
+
+ p->block_set_autocompletion_key = FALSE;
+
+ ephy_location_entry_autocompletion_show_alternatives (w);
+ if (!strcmp (common_prefix, text))
+ {
+ /* really suggest something the next time */
+ suggest = TRUE;
+ }
+ g_free (common_prefix);
+ }
+ else
+ {
+ ephy_location_entry_autocompletion_hide_alternatives (w);
+ }
+ g_free (text);
+ return TRUE;
+ }
+ case GDK_Escape:
+ ephy_location_entry_autocompletion_hide_alternatives (w);
+ if (p->before_completion)
+ {
+ ephy_location_entry_set_location (w, p->before_completion);
+ g_free (p->before_completion);
+ p->before_completion = NULL;
+ gtk_editable_set_position (GTK_EDITABLE (p->entry), -1);
+ return TRUE;
+ }
+ break;
+ default:
+ ephy_location_entry_autocompletion_unselect_alternatives (w);
+ if ((event->string[0] > 32) && (event->string[0] < 126))
+ {
+ p->show_alternatives_timeout = g_timeout_add
+ (SHOW_ALTERNATIVES_DELAY,
+ (GSourceFunc) ephy_location_entry_autocompletion_show_alternatives_to, w);
+ }
+ break;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+ephy_location_entry_content_is_text (const char *content)
+{
+ return ((g_strrstr (content, ".") == NULL) &&
+ (g_strrstr (content, "/") == NULL));
+}
+
+static void
+ephy_location_entry_activate_cb (GtkEntry *entry, EphyLocationEntry *w)
+{
+ char *content;
+ char *target = NULL;
+
+ content = gtk_editable_get_chars (GTK_EDITABLE(entry), 0, -1);
+ if (ephy_location_entry_content_is_text (content))
+ {
+ target = w->priv->last_action_target;
+ }
+
+ ephy_location_entry_autocompletion_hide_alternatives (w);
+
+ DEBUG_MSG (("In ephy_location_entry_activate_cb, activating %s\n", content));
+
+ g_signal_emit (w, EphyLocationEntrySignals[ACTIVATED], 0, target, content);
+ g_free (content);
+}
+
+static void
+ephy_location_entry_autocompletion_sources_changed_cb (EphyAutocompletion *aw,
+ EphyLocationEntry *w)
+{
+ EphyLocationEntryPrivate *p = w->priv;
+
+ DEBUG_MSG (("in ephy_location_entry_autocompletion_sources_changed_cb\n"));
+
+ if (p->autocompletion_timeout == 0
+ && p->last_completion
+ && !strcmp (p->last_completion, gtk_entry_get_text (GTK_ENTRY (p->entry))))
+ {
+ p->autocompletion_timeout = gtk_timeout_add
+ (AUTOCOMPLETION_DELAY,
+ (GSourceFunc) ephy_location_entry_autocompletion_to, w);
+ }
+
+ if (p->show_alternatives_timeout == 0
+ && p->autocompletion_window_visible)
+ {
+ p->show_alternatives_timeout = gtk_timeout_add
+ (SHOW_ALTERNATIVES_DELAY,
+ (GSourceFunc) ephy_location_entry_autocompletion_show_alternatives_to, w);
+ }
+}
+
+void
+ephy_location_entry_set_location (EphyLocationEntry *w,
+ const gchar *new_location)
+{
+ EphyLocationEntryPrivate *p = w->priv;
+ int pos;
+ gtk_editable_delete_text (GTK_EDITABLE (p->entry), 0, -1);
+ gtk_editable_insert_text (GTK_EDITABLE (p->entry), new_location, g_utf8_strlen (new_location, -1),
+ &pos);
+}
+
+gchar *
+ephy_location_entry_get_location (EphyLocationEntry *w)
+{
+ char *location = gtk_editable_get_chars (GTK_EDITABLE (w->priv->entry), 0, -1);
+ return location;
+}
+
+void
+ephy_location_entry_set_autocompletion (EphyLocationEntry *w,
+ EphyAutocompletion *ac)
+{
+ EphyLocationEntryPrivate *p = w->priv;
+ if (p->autocompletion)
+ {
+ g_signal_handlers_disconnect_matched (p->autocompletion, G_SIGNAL_MATCH_DATA, 0, 0,
+ NULL, NULL, w);
+
+ g_signal_handlers_disconnect_matched (p->autocompletion_window, G_SIGNAL_MATCH_DATA, 0, 0,
+ NULL, NULL, w);
+
+ g_object_unref (G_OBJECT (p->autocompletion));
+ g_object_unref (p->autocompletion_window);
+ }
+ p->autocompletion = ac;
+ if (p->autocompletion)
+ {
+ g_object_ref (G_OBJECT (p->autocompletion));
+ p->autocompletion_window = ephy_autocompletion_window_new (p->autocompletion,
+ p->entry);
+ g_signal_connect (p->autocompletion_window, "activated",
+ G_CALLBACK (ephy_location_entry_autocompletion_window_url_activated_cb),
+ w);
+
+ g_signal_connect (p->autocompletion_window, "hidden",
+ G_CALLBACK (ephy_location_entry_autocompletion_window_hidden_cb),
+ w);
+
+ g_signal_connect (p->autocompletion, "sources-changed",
+ G_CALLBACK (ephy_location_entry_autocompletion_sources_changed_cb),
+ w);
+
+ ephy_location_entry_set_autocompletion_key (w);
+ }
+
+}
+
+static void
+ephy_location_entry_autocompletion_window_url_activated_cb (EphyAutocompletionWindow *aw,
+ const char *target,
+ int action,
+ EphyLocationEntry *w)
+{
+ char *content;
+
+ if (action)
+ {
+ if (w->priv->last_action_target)
+ g_free (w->priv->last_action_target);
+ w->priv->last_action_target = g_strdup (target);
+ }
+ else
+ {
+ ephy_location_entry_set_location (w, target);
+ }
+
+ content = gtk_editable_get_chars (GTK_EDITABLE(w->priv->entry), 0, -1);
+
+ DEBUG_MSG (("In location_entry_autocompletion_window_url_activated_cb, going to %s\n", content));
+
+ ephy_location_entry_autocompletion_hide_alternatives (w);
+
+ g_signal_emit (w, EphyLocationEntrySignals[ACTIVATED], 0,
+ action ? content : NULL, target);
+
+ g_free (content);
+}
+
+static void
+ephy_location_entry_autocompletion_window_hidden_cb (EphyAutocompletionWindow *aw,
+ EphyLocationEntry *w)
+{
+ EphyLocationEntryPrivate *p = w->priv;
+
+ DEBUG_MSG (("In location_entry_autocompletion_window_hidden_cb\n"));
+
+ p->autocompletion_window_visible = FALSE;
+
+ if (p->show_alternatives_timeout)
+ {
+ g_source_remove (p->show_alternatives_timeout);
+ p->show_alternatives_timeout = 0;
+ }
+
+ if (p->autocompletion_timeout)
+ {
+ g_source_remove (p->autocompletion_timeout);
+ p->autocompletion_timeout = 0;
+ }
+}
+
+void
+ephy_location_entry_activate (EphyLocationEntry *w)
+{
+ GtkWidget *toplevel;
+
+ toplevel = gtk_widget_get_toplevel (w->priv->entry);
+
+ gtk_editable_select_region (GTK_EDITABLE(w->priv->entry),
+ 0, -1);
+ gtk_window_set_focus (GTK_WINDOW(toplevel),
+ w->priv->entry);
+}
+
+
+static void
+ephy_location_entry_list_event_after_cb (GtkWidget *list,
+ GdkEvent *event,
+ EphyLocationEntry *e)
+{
+ if (event->type == GDK_BUTTON_PRESS
+ && ((GdkEventButton *) event)->button == 1)
+ {
+ gchar *url = ephy_location_entry_get_location (e);
+ g_signal_emit
+ (e, EphyLocationEntrySignals[ACTIVATED], 0, url);
+ g_free (url);
+ }
+}
+
+static void
+ephy_location_entry_editable_changed_cb (GtkEditable *editable, EphyLocationEntry *e)
+{
+ ephy_location_entry_set_autocompletion_key (e);
+}
+
+static void
+ephy_location_entry_set_autocompletion_key (EphyLocationEntry *e)
+{
+ EphyLocationEntryPrivate *p = e->priv;
+ if (p->autocompletion && !p->block_set_autocompletion_key)
+ {
+ GtkEditable *editable = GTK_EDITABLE (p->entry);
+ gint sstart, send;
+ gchar *text;
+ gtk_editable_get_selection_bounds (editable, &sstart, &send);
+ text = gtk_editable_get_chars (editable, 0, sstart);
+ ephy_autocompletion_set_key (p->autocompletion, text);
+ g_free (p->autocompletion_key);
+ p->autocompletion_key = text;
+ }
+}
+
diff --git a/lib/widgets/ephy-location-entry.h b/lib/widgets/ephy-location-entry.h
new file mode 100644
index 000000000..eebacc770
--- /dev/null
+++ b/lib/widgets/ephy-location-entry.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2002 Ricardo Fernández Pascual
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EPHY_LOCATION_ENTRY_H
+#define EPHY_LOCATION_ENTRY_H
+
+#include <glib-object.h>
+#include <gtk/gtkhbox.h>
+
+#include "ephy-autocompletion.h"
+
+/* object forward declarations */
+
+typedef struct _EphyLocationEntry EphyLocationEntry;
+typedef struct _EphyLocationEntryClass EphyLocationEntryClass;
+typedef struct _EphyLocationEntryPrivate EphyLocationEntryPrivate;
+
+/**
+ * EphyFolderTbWidget object
+ */
+
+#define EPHY_TYPE_LOCATION_ENTRY (ephy_location_entry_get_type())
+#define EPHY_LOCATION_ENTRY(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EPHY_TYPE_LOCATION_ENTRY,\
+ EphyLocationEntry))
+#define EPHY_LOCATION_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EPHY_TYPE_LOCATION_ENTRY,\
+ EphyLocationEntryClass))
+#define EPHY_IS_LOCATION_ENTRY(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EPHY_TYPE_LOCATION_ENTRY))
+#define EPHY_IS_LOCATION_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), EPHY_TYPE_LOCATION_ENTRY))
+#define EPHY_LOCATION_ENTRY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EPHY_TYPE_LOCATION_ENTRY,\
+ EphyLocationEntryClass))
+
+struct _EphyLocationEntryClass
+{
+ GtkHBoxClass parent_class;
+
+ /* signals */
+ void (*activated) (EphyLocationEntry *w,
+ const char *content,
+ const char *target);
+};
+
+/* Remember: fields are public read-only */
+struct _EphyLocationEntry
+{
+ GtkHBox parent_object;
+
+ EphyLocationEntryPrivate *priv;
+};
+
+GType ephy_location_entry_get_type (void);
+EphyLocationEntry * ephy_location_entry_new (void);
+void ephy_location_entry_set_location (EphyLocationEntry *w,
+ const gchar *new_location);
+gchar * ephy_location_entry_get_location (EphyLocationEntry *w);
+void ephy_location_entry_set_autocompletion (EphyLocationEntry *w,
+ EphyAutocompletion *ac);
+void ephy_location_entry_activate (EphyLocationEntry *w);
+
+#endif
diff --git a/lib/widgets/ephy-notebook.c b/lib/widgets/ephy-notebook.c
new file mode 100644
index 000000000..c03dc878a
--- /dev/null
+++ b/lib/widgets/ephy-notebook.c
@@ -0,0 +1,843 @@
+/*
+ * Copyright (C) 2002 Christophe Fergeau
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "ephy-notebook.h"
+#include "eel-gconf-extensions.h"
+#include "ephy-prefs.h"
+#include "ephy-marshal.h"
+
+#include <gtk/gtk.h>
+#include <glib-object.h>
+#include <libgnome/gnome-i18n.h>
+
+#define AFTER_ALL_TABS -1
+#define NOT_IN_APP_WINDOWS -2
+#define TAB_MIN_SIZE 60
+#define TAB_NB_MAX 8
+
+struct EphyNotebookPrivate
+{
+ GList *focused_pages;
+ GList *opened_tabs;
+
+ /* Used during tab drag'n'drop */
+ gulong motion_notify_handler_id;
+ gint x_start, y_start;
+ gboolean drag_in_progress;
+ EphyNotebook *src_notebook;
+ gint src_page;
+};
+
+/* GObject boilerplate code */
+static void ephy_notebook_init (EphyNotebook *notebook);
+static void ephy_notebook_class_init (EphyNotebookClass *klass);
+static void ephy_notebook_finalize (GObject *object);
+
+/* Local variables */
+static GdkCursor *cursor = NULL;
+static GList *notebooks = NULL;
+
+
+/* Local functions */
+static void drag_start (EphyNotebook *notebook,
+ EphyNotebook *src_notebook,
+ gint src_page);
+static void drag_stop (EphyNotebook *notebook);
+
+static gboolean motion_notify_cb (EphyNotebook *notebook,
+ GdkEventMotion *event,
+ gpointer data);
+
+/* Signals */
+enum
+{
+ TAB_DROPPED,
+ TAB_DETACHED,
+ LAST_SIGNAL
+};
+
+static guint ephy_notebook_signals[LAST_SIGNAL] = { 0 };
+
+GType
+ephy_notebook_get_type (void)
+{
+ static GType ephy_notebook_type = 0;
+
+ if (ephy_notebook_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (EphyNotebookClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) ephy_notebook_class_init,
+ NULL,
+ NULL, /* class_data */
+ sizeof (EphyNotebook),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) ephy_notebook_init
+ };
+
+ ephy_notebook_type = g_type_register_static (GTK_TYPE_NOTEBOOK,
+ "EphyNotebook",
+ &our_info, 0);
+ }
+
+ return ephy_notebook_type;
+}
+
+static void
+ephy_notebook_class_init (EphyNotebookClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ object_class->finalize = ephy_notebook_finalize;
+
+ /* init signals */
+ ephy_notebook_signals[TAB_DROPPED] =
+ g_signal_new ("tab_dropped",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EphyNotebookClass,
+ tab_dropped),
+ NULL, NULL,
+ ephy_marshal_VOID__OBJECT_OBJECT_INT,
+ G_TYPE_NONE,
+ 3,
+ GTK_TYPE_WIDGET,
+ EPHY_NOTEBOOK_TYPE,
+ G_TYPE_INT);
+ ephy_notebook_signals[TAB_DETACHED] =
+ g_signal_new ("tab_detached",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EphyNotebookClass,
+ tab_detached),
+ NULL, NULL,
+ ephy_marshal_VOID__INT_INT_INT,
+ G_TYPE_NONE,
+ 3,
+ G_TYPE_INT,
+ G_TYPE_INT,
+ G_TYPE_INT);
+
+}
+
+static gboolean
+is_in_notebook_window (EphyNotebook *notebook,
+ gint abs_x, gint abs_y)
+{
+ gint x, y;
+ gint rel_x, rel_y;
+ gint width, height;
+ GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET(notebook));
+ GdkWindow *window = GTK_WIDGET(toplevel)->window;
+
+ gdk_window_get_origin (window, &x, &y);
+ rel_x = abs_x - x;
+ rel_y = abs_y - y;
+
+ x = GTK_WIDGET(notebook)->allocation.x;
+ y = GTK_WIDGET(notebook)->allocation.y;
+ height = GTK_WIDGET(notebook)->allocation.height;
+ width = GTK_WIDGET(notebook)->allocation.width;
+ return ((rel_x>=x) && (rel_y>=y) && (rel_x<=x+width) && (rel_y<=y+height));
+}
+
+static EphyNotebook *
+find_notebook_at_pointer (gint abs_x, gint abs_y)
+{
+ GList *l;
+ gint x, y;
+ GdkWindow *win_at_pointer = gdk_window_at_pointer (&x, &y);
+ GdkWindow *parent_at_pointer = NULL;
+
+ if (win_at_pointer == NULL)
+ {
+ /* We are outside all windows containing a notebook */
+ return NULL;
+ }
+
+ gdk_window_get_toplevel (win_at_pointer);
+ /* When we are in the notebook event window, win_at_pointer will be
+ this event window, and the toplevel window we are interested in
+ will be its parent
+ */
+ parent_at_pointer = gdk_window_get_parent (win_at_pointer);
+
+ for (l = notebooks; l != NULL; l = l->next)
+ {
+ EphyNotebook *nb = EPHY_NOTEBOOK (l->data);
+ GdkWindow *win = GTK_WIDGET (nb)->window;
+
+ win = gdk_window_get_toplevel (win);
+ if (((win == win_at_pointer) || (win == parent_at_pointer))
+ && is_in_notebook_window (nb, abs_x, abs_y))
+ {
+ return nb;
+ }
+ }
+ return NULL;
+}
+
+
+static gint
+find_tab_num_at_pos (EphyNotebook *notebook, gint abs_x, gint abs_y)
+{
+ GtkPositionType tab_pos;
+ int page_num = 0;
+ GtkNotebook *nb = GTK_NOTEBOOK (notebook);
+ GtkWidget *page;
+
+ tab_pos = gtk_notebook_get_tab_pos (GTK_NOTEBOOK (notebook));
+
+ if (GTK_NOTEBOOK (notebook)->first_tab == NULL)
+ {
+ return AFTER_ALL_TABS;
+ }
+
+ g_assert (is_in_notebook_window(notebook, abs_x, abs_y));
+
+ while ((page = gtk_notebook_get_nth_page (nb, page_num)))
+ {
+ GtkWidget *tab;
+ gint max_x, max_y;
+ gint x_root, y_root;
+
+ tab = gtk_notebook_get_tab_label (nb, page);
+ g_return_val_if_fail (tab != NULL, -1);
+
+ if (!GTK_WIDGET_MAPPED (GTK_WIDGET (tab)))
+ {
+ page_num++;
+ continue;
+ }
+
+ gdk_window_get_origin (GDK_WINDOW (tab->window),
+ &x_root, &y_root);
+
+ max_x = x_root + tab->allocation.x + tab->allocation.width;
+ max_y = y_root + tab->allocation.y + tab->allocation.height;
+
+ if (((tab_pos == GTK_POS_TOP)
+ || (tab_pos == GTK_POS_BOTTOM))
+ &&(abs_x<=max_x))
+ {
+ return page_num;
+ }
+ else if (((tab_pos == GTK_POS_LEFT)
+ || (tab_pos == GTK_POS_RIGHT))
+ && (abs_y<=max_y))
+ {
+ return page_num;
+ }
+
+ page_num++;
+ }
+ return AFTER_ALL_TABS;
+}
+
+
+static gint find_notebook_and_tab_at_pos (gint abs_x, gint abs_y,
+ EphyNotebook **notebook,
+ gint *page_num)
+{
+ *notebook = find_notebook_at_pointer (abs_x, abs_y);
+ if (*notebook == NULL)
+ {
+ return NOT_IN_APP_WINDOWS;
+ }
+ *page_num = find_tab_num_at_pos (*notebook, abs_x, abs_y);
+
+ if (*page_num < 0)
+ {
+ return *page_num;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+static void
+tab_label_set_size (GtkWidget *window, GtkWidget *label)
+{
+ int label_width;
+
+ label_width = window->allocation.width/TAB_NB_MAX;
+
+ if (label_width < TAB_MIN_SIZE) label_width = TAB_MIN_SIZE;
+
+ gtk_widget_set_size_request (label, label_width, -1);
+}
+
+static GtkWidget *
+tab_get_label (EphyNotebook *nb, GtkWidget *child)
+{
+ GtkWidget *hbox, *label;
+
+ hbox = gtk_notebook_get_tab_label (GTK_NOTEBOOK (nb),
+ child);
+ label = g_object_get_data (G_OBJECT (hbox), "label");
+
+ return label;
+}
+
+static void
+tab_label_size_request_cb (GtkWidget *window,
+ GtkRequisition *requisition,
+ GtkWidget *child)
+{
+ GtkWidget *hbox;
+ GtkWidget *nb;
+
+ nb = child->parent;
+
+ hbox = gtk_notebook_get_tab_label (GTK_NOTEBOOK (nb),
+ child);
+ tab_label_set_size (window, hbox);
+}
+
+
+void
+ephy_notebook_move_page (EphyNotebook *src, EphyNotebook *dest,
+ GtkWidget *src_page, gint dest_page)
+{
+ GtkWidget *tab_label;
+
+ tab_label = gtk_notebook_get_tab_label (GTK_NOTEBOOK (src), src_page);
+
+ /* We don't want gtk to destroy tab and src_page behind our back */
+ g_object_ref (G_OBJECT (src_page));
+ g_object_ref (G_OBJECT (tab_label));
+ ephy_notebook_remove_page (EPHY_NOTEBOOK (src), src_page);
+ ephy_notebook_insert_page (EPHY_NOTEBOOK (dest), src_page,
+ dest_page, TRUE);
+ gtk_notebook_set_tab_label (GTK_NOTEBOOK (dest), src_page, tab_label);
+ g_object_unref (G_OBJECT (src_page));
+ g_object_unref (G_OBJECT (tab_label));
+}
+
+
+
+static void
+move_tab_to_another_notebook(EphyNotebook *src,
+ EphyNotebook *dest, gint dest_page)
+{
+ GtkWidget *child;
+ gint cur_page;
+
+ /* This is getting tricky, the tab was dragged in a notebook
+ * in another window of the same app, we move the tab
+ * to that new notebook, and let this notebook handle the
+ * drag
+ */
+ g_assert (dest != NULL);
+ g_assert (dest != src);
+
+ /* Move the widgets (tab label and tab content) to the new
+ * notebook
+ */
+ cur_page = gtk_notebook_get_current_page (GTK_NOTEBOOK (src));
+ child = gtk_notebook_get_nth_page (GTK_NOTEBOOK (src), cur_page);
+ ephy_notebook_move_page (src, dest, child, dest_page);
+
+ /* "Give" drag handling to the new notebook */
+ drag_start (dest, src->priv->src_notebook, src->priv->src_page);
+ drag_stop (src);
+ gtk_grab_remove (GTK_WIDGET (src));
+
+ dest->priv->motion_notify_handler_id =
+ g_signal_connect (G_OBJECT (dest),
+ "motion-notify-event",
+ G_CALLBACK (motion_notify_cb),
+ NULL);
+}
+
+
+static void
+move_tab (EphyNotebook *notebook, gint dest_page_num)
+{
+ gint cur_page_num;
+
+ cur_page_num = gtk_notebook_get_current_page (GTK_NOTEBOOK (notebook));
+
+ if (dest_page_num != cur_page_num)
+ {
+ GtkWidget *cur_page;
+ cur_page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook),
+ cur_page_num);
+ gtk_notebook_reorder_child (GTK_NOTEBOOK (notebook), cur_page,
+ dest_page_num);
+
+ /* Reset the list of newly opened tabs when moving tabs. */
+ g_list_free (notebook->priv->opened_tabs);
+ notebook->priv->opened_tabs = NULL;
+ }
+}
+
+static void
+drag_start (EphyNotebook *notebook,
+ EphyNotebook *src_notebook,
+ gint src_page)
+{
+ notebook->priv->drag_in_progress = TRUE;
+ notebook->priv->src_notebook = src_notebook;
+ notebook->priv->src_page = src_page;
+
+ /* get a new cursor, if necessary */
+ if (!cursor) cursor = gdk_cursor_new (GDK_FLEUR);
+
+ /* grab the pointer */
+ gtk_grab_add (GTK_WIDGET (notebook));
+ if (!gdk_pointer_is_grabbed ()) {
+ gdk_pointer_grab (GDK_WINDOW(GTK_WIDGET (notebook)->window),
+ FALSE,
+ GDK_BUTTON1_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
+ NULL, cursor, GDK_CURRENT_TIME);
+ }
+}
+
+static void
+drag_stop (EphyNotebook *notebook)
+{
+ notebook->priv->drag_in_progress = FALSE;
+ notebook->priv->src_notebook = NULL;
+ notebook->priv->src_page = -1;
+ if (notebook->priv->motion_notify_handler_id != 0)
+ {
+ g_signal_handler_disconnect (G_OBJECT (notebook),
+ notebook->priv->motion_notify_handler_id);
+ notebook->priv->motion_notify_handler_id = 0;
+ }
+}
+
+/* Callbacks */
+static gboolean
+button_release_cb (EphyNotebook *notebook, GdkEventButton *event,
+ gpointer data)
+{
+ if (notebook->priv->drag_in_progress)
+ {
+ gint cur_page_num;
+ GtkWidget *cur_page;
+
+ cur_page_num =
+ gtk_notebook_get_current_page (GTK_NOTEBOOK (notebook));
+ cur_page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook),
+ cur_page_num);
+
+ if (!is_in_notebook_window (notebook, event->x_root, event->y_root))
+ {
+ /* Tab was detached */
+ g_signal_emit (G_OBJECT(notebook),
+ ephy_notebook_signals[TAB_DETACHED], 0,
+ cur_page_num, (gint)event->x_root,
+ (gint)event->y_root);
+ }
+ else
+ {
+ /* Tab was dragged and dropped (but it may have stayed
+ in the same place) */
+ g_signal_emit (G_OBJECT(notebook),
+ ephy_notebook_signals[TAB_DROPPED], 0,
+ cur_page,
+ notebook->priv->src_notebook,
+ notebook->priv->src_page);
+ }
+
+ /* ungrab the pointer if it's grabbed */
+ if (gdk_pointer_is_grabbed ())
+ {
+ gdk_pointer_ungrab (GDK_CURRENT_TIME);
+ gtk_grab_remove (GTK_WIDGET (notebook));
+ }
+ }
+ /* This must be called even if a drag isn't happening */
+ drag_stop (notebook);
+ return FALSE;
+}
+
+
+static gboolean
+motion_notify_cb (EphyNotebook *notebook, GdkEventMotion *event,
+ gpointer data)
+{
+ EphyNotebook *dest;
+ gint page_num;
+ gint result;
+
+ /* If the notebook only has one tab, we don't want to do
+ * anything since ephy can't handle empty notebooks
+ */
+ if (g_list_length (GTK_NOTEBOOK (notebook)->children) <= 1) {
+ return FALSE;
+ }
+
+ if ((notebook->priv->drag_in_progress == FALSE)
+ && (gtk_drag_check_threshold (GTK_WIDGET (notebook),
+ notebook->priv->x_start,
+ notebook->priv->y_start,
+ event->x_root, event->y_root)))
+ {
+ gint cur_page;
+
+ cur_page = gtk_notebook_get_current_page (GTK_NOTEBOOK (notebook));
+ drag_start (notebook, notebook, cur_page);
+ }
+
+ result = find_notebook_and_tab_at_pos ((gint)event->x_root,
+ (gint)event->y_root,
+ &dest, &page_num);
+
+ if (result != NOT_IN_APP_WINDOWS)
+ {
+ if (dest != notebook)
+ {
+ move_tab_to_another_notebook (notebook, dest,
+ page_num);
+ }
+ else
+ {
+ g_assert (page_num >= -1);
+ move_tab (notebook, page_num);
+ }
+ }
+
+ return FALSE;
+}
+
+static gboolean
+button_press_cb (EphyNotebook *notebook,
+ GdkEventButton *event,
+ gpointer data)
+{
+ gint tab_clicked = find_tab_num_at_pos (notebook,
+ event->x_root,
+ event->y_root);
+
+ if (notebook->priv->drag_in_progress)
+ {
+ return TRUE;
+ }
+
+ if ((event->button == 1) && (event->type == GDK_BUTTON_PRESS)
+ && (tab_clicked != -1))
+ {
+ notebook->priv->x_start = event->x_root;
+ notebook->priv->y_start = event->y_root;
+ notebook->priv->motion_notify_handler_id =
+ g_signal_connect (G_OBJECT (notebook),
+ "motion-notify-event",
+ G_CALLBACK (motion_notify_cb), NULL);
+ }
+
+ return FALSE;
+}
+
+GtkWidget *
+ephy_notebook_new (void)
+{
+ return GTK_WIDGET (g_object_new (EPHY_NOTEBOOK_TYPE, NULL));
+}
+
+static void
+ephy_notebook_switch_page_cb (GtkNotebook *notebook,
+ GtkNotebookPage *page,
+ guint page_num,
+ gpointer data)
+{
+ EphyNotebook *nb = EPHY_NOTEBOOK (notebook);
+ GtkWidget *child;
+
+ child = gtk_notebook_get_nth_page (notebook, page_num);
+
+ /* Remove the old page, we dont want to grow unnecessarily
+ * the list */
+ if (nb->priv->focused_pages)
+ {
+ nb->priv->focused_pages =
+ g_list_remove (nb->priv->focused_pages, child);
+ }
+
+ nb->priv->focused_pages = g_list_append (nb->priv->focused_pages,
+ child);
+
+ /* Reset the list of newly opened tabs when switching tabs. */
+ g_list_free (nb->priv->opened_tabs);
+ nb->priv->opened_tabs = NULL;
+}
+
+static void
+ephy_notebook_init (EphyNotebook *notebook)
+{
+ notebook->priv = g_new (EphyNotebookPrivate, 1);
+
+ notebook->priv->drag_in_progress = FALSE;
+ notebook->priv->motion_notify_handler_id = 0;
+ notebook->priv->src_notebook = NULL;
+ notebook->priv->src_page = -1;
+ notebook->priv->focused_pages = NULL;
+ notebook->priv->opened_tabs = NULL;
+
+ notebooks = g_list_append (notebooks, notebook);
+
+ g_signal_connect (notebook, "button-press-event",
+ (GCallback)button_press_cb, NULL);
+ g_signal_connect (notebook, "button-release-event",
+ (GCallback)button_release_cb, NULL);
+ gtk_widget_add_events (GTK_WIDGET (notebook), GDK_BUTTON1_MOTION_MASK);
+
+ g_signal_connect_after (G_OBJECT (notebook), "switch_page",
+ G_CALLBACK (ephy_notebook_switch_page_cb),
+ NULL);
+}
+
+static void
+ephy_notebook_finalize (GObject *object)
+{
+ EphyNotebook *notebook = EPHY_NOTEBOOK (object);
+
+ notebooks = g_list_remove (notebooks, notebook);
+
+ if (notebook->priv->focused_pages)
+ {
+ g_list_free (notebook->priv->focused_pages);
+ }
+ g_list_free (notebook->priv->opened_tabs);
+
+ g_free (notebook->priv);
+}
+
+
+void
+ephy_notebook_set_page_status (EphyNotebook *nb,
+ GtkWidget *child,
+ EphyNotebookPageLoadStatus status)
+{
+}
+
+static void
+ephy_tab_close_button_clicked_cb (GtkWidget *widget,
+ GtkWidget *child)
+{
+ EphyNotebook *notebook;
+
+ notebook = EPHY_NOTEBOOK (gtk_widget_get_parent (child));
+ ephy_notebook_remove_page (notebook, child);
+}
+
+static GtkWidget *
+tab_build_label (EphyNotebook *nb, GtkWidget *child)
+{
+ GtkWidget *label, *hbox, *close_button, *image;
+ int h, w;
+ GClosure *closure;
+ GtkWidget *window;
+
+ window = gtk_widget_get_toplevel (GTK_WIDGET (nb));
+
+ gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &w, &h);
+
+ hbox = gtk_hbox_new (FALSE, 0);
+
+ /* setup close button */
+ close_button = gtk_button_new ();
+ gtk_button_set_relief (GTK_BUTTON (close_button),
+ GTK_RELIEF_NONE);
+ image = gtk_image_new_from_stock (GTK_STOCK_CLOSE,
+ GTK_ICON_SIZE_MENU);
+ gtk_widget_set_size_request (close_button, w, h);
+ gtk_container_add (GTK_CONTAINER (close_button),
+ image);
+
+ /* setup label */
+ label = gtk_label_new (_("Untitled"));
+ gtk_misc_set_alignment (GTK_MISC (label), 0.00, 0.5);
+ gtk_misc_set_padding (GTK_MISC (label), 4, 0);
+ gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0);
+
+ tab_label_set_size (GTK_WIDGET (window), hbox);
+
+ closure = g_cclosure_new (G_CALLBACK (tab_label_size_request_cb),
+ child, NULL);
+ g_object_watch_closure (G_OBJECT (label), closure);
+ g_signal_connect_closure_by_id (G_OBJECT (window),
+ g_signal_lookup ("size_request",
+ G_OBJECT_TYPE (G_OBJECT (window))), 0,
+ closure,
+ FALSE);
+
+ /* setup button */
+ gtk_box_pack_start (GTK_BOX (hbox), close_button,
+ FALSE, FALSE, 0);
+
+ g_signal_connect (G_OBJECT (close_button), "clicked",
+ G_CALLBACK (ephy_tab_close_button_clicked_cb),
+ child);
+
+ gtk_widget_show (hbox);
+ gtk_widget_show (label);
+ gtk_widget_show (image);
+ gtk_widget_show (close_button);
+
+ g_object_set_data (G_OBJECT (hbox), "label", label);
+
+ return hbox;
+}
+
+/*
+ * update_tabs_visibility: Hide tabs if there is only one tab
+ * and the pref is not set.
+ * HACK We need to show tabs before inserting the second. Otherwise
+ * gtknotebook go crazy.
+ */
+static void
+update_tabs_visibility (EphyNotebook *nb, gboolean before_inserting)
+{
+ gboolean show_tabs;
+ guint tabs_num = 1;
+
+ if (before_inserting) tabs_num--;
+
+ show_tabs = gtk_notebook_get_nth_page (GTK_NOTEBOOK (nb), tabs_num) > 0;
+
+ gtk_notebook_set_show_tabs (GTK_NOTEBOOK (nb), show_tabs);
+}
+
+void
+ephy_notebook_insert_page (EphyNotebook *nb,
+ GtkWidget *child,
+ int position,
+ gboolean jump_to)
+{
+ GtkWidget *tab_hbox;
+
+ tab_hbox = tab_build_label (nb, child);
+
+ update_tabs_visibility (nb, TRUE);
+
+ if (position == EPHY_NOTEBOOK_INSERT_GROUPED)
+ {
+ /* Keep a list of newly opened tabs, if the list is empty open the new
+ * tab after the current one. If it's not, add it after the newly
+ * opened tabs.
+ */
+ if (nb->priv->opened_tabs != NULL)
+ {
+ GList *last = g_list_last (nb->priv->opened_tabs);
+ GtkWidget *last_tab = last->data;
+ position = gtk_notebook_page_num
+ (GTK_NOTEBOOK (nb), last_tab) + 1;
+ }
+ else
+ {
+ position = gtk_notebook_get_current_page
+ (GTK_NOTEBOOK (nb)) + 1;
+ }
+ nb->priv->opened_tabs =
+ g_list_append (nb->priv->opened_tabs, child);
+ }
+
+ gtk_notebook_insert_page (GTK_NOTEBOOK (nb),
+ child,
+ tab_hbox, position);
+
+ if (jump_to)
+ {
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (nb),
+ position);
+ g_object_set_data (G_OBJECT (child), "jump_to",
+ GINT_TO_POINTER (jump_to));
+ }
+}
+
+static void
+smart_tab_switching_on_closure (EphyNotebook *nb,
+ GtkWidget *child)
+{
+ gboolean jump_to;
+
+ jump_to = GPOINTER_TO_INT (g_object_get_data
+ (G_OBJECT (child), "jump_to"));
+
+ if (!jump_to || !nb->priv->focused_pages)
+ {
+ gtk_notebook_next_page (GTK_NOTEBOOK (nb));
+ }
+ else
+ {
+ GList *l;
+ GtkWidget *child;
+ int page_num;
+
+ /* activate the last focused tab */
+ l = g_list_last (nb->priv->focused_pages);
+ child = GTK_WIDGET (l->data);
+ page_num = gtk_notebook_page_num (GTK_NOTEBOOK (nb),
+ child);
+ gtk_notebook_set_current_page
+ (GTK_NOTEBOOK (nb), page_num);
+ }
+}
+
+void
+ephy_notebook_remove_page (EphyNotebook *nb,
+ GtkWidget *child)
+{
+ int position, cur;
+ gboolean last_tab;
+
+ last_tab = gtk_notebook_get_nth_page (GTK_NOTEBOOK (nb), 1) == NULL;
+ if (last_tab)
+ {
+ GtkWidget *window;
+ window = gtk_widget_get_toplevel (GTK_WIDGET (nb));
+ gtk_widget_destroy (window);
+ return;
+ }
+
+ /* Remove the page from the focused pages list */
+ nb->priv->focused_pages = g_list_remove (nb->priv->focused_pages,
+ child);
+ nb->priv->opened_tabs = g_list_remove (nb->priv->opened_tabs, child);
+
+
+ position = gtk_notebook_page_num (GTK_NOTEBOOK (nb),
+ child);
+
+ cur = gtk_notebook_get_current_page (GTK_NOTEBOOK (nb));
+ if (position == cur)
+ {
+ smart_tab_switching_on_closure (nb, child);
+ }
+
+ gtk_notebook_remove_page (GTK_NOTEBOOK (nb), position);
+
+ update_tabs_visibility (nb, FALSE);
+}
+
+void
+ephy_notebook_set_page_title (EphyNotebook *nb,
+ GtkWidget *child,
+ const char *title)
+{
+ GtkWidget *label;
+
+ label = tab_get_label (nb, child);
+ gtk_label_set_label (GTK_LABEL (label), title);
+}
diff --git a/lib/widgets/ephy-notebook.h b/lib/widgets/ephy-notebook.h
new file mode 100644
index 000000000..755eea84d
--- /dev/null
+++ b/lib/widgets/ephy-notebook.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2002 Christophe Fergeau
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EPHY_NOTEBOOK_H
+#define EPHY_NOTEBOOK_H
+
+#include <glib.h>
+#include <gtk/gtknotebook.h>
+
+G_BEGIN_DECLS
+
+typedef struct EphyNotebookClass EphyNotebookClass;
+
+#define EPHY_NOTEBOOK_TYPE (ephy_notebook_get_type ())
+#define EPHY_NOTEBOOK(obj) (GTK_CHECK_CAST ((obj), EPHY_NOTEBOOK_TYPE, EphyNotebook))
+#define EPHY_NOTEBOOK_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), EPHY_NOTEBOOK_TYPE, EphyNotebookClass))
+#define IS_EPHY_NOTEBOOK(obj) (GTK_CHECK_TYPE ((obj), EPHY_NOTEBOOK_TYPE))
+#define IS_EPHY_NOTEBOOK_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), EPHY_NOTEBOOK))
+
+typedef struct EphyNotebook EphyNotebook;
+typedef struct EphyNotebookPrivate EphyNotebookPrivate;
+
+typedef enum
+{
+ EPHY_NOTEBOOK_TAB_LOAD_NORMAL,
+ EPHY_NOTEBOOK_TAB_LOAD_LOADING,
+ EPHY_NOTEBOOK_TAB_LOAD_COMPLETED
+} EphyNotebookPageLoadStatus;
+
+enum
+{
+ EPHY_NOTEBOOK_INSERT_LAST = -1,
+ EPHY_NOTEBOOK_INSERT_GROUPED = -2
+};
+
+struct EphyNotebook
+{
+ GtkNotebook parent;
+ EphyNotebookPrivate *priv;
+};
+
+struct EphyNotebookClass
+{
+ GtkNotebookClass parent_class;
+
+ /* Signals */
+ void (* tab_dropped) (EphyNotebook *dest,
+ GtkWidget *widget,
+ EphyNotebook *src,
+ gint src_page);
+ void (* tab_detached) (EphyNotebook *dest,
+ gint cur_page,
+ gint root_x, gint root_y);
+
+};
+
+GType ephy_notebook_get_type (void);
+
+GtkWidget *ephy_notebook_new (void);
+
+void ephy_notebook_insert_page (EphyNotebook *nb,
+ GtkWidget *child,
+ int position,
+ gboolean jump_to);
+
+void ephy_notebook_remove_page (EphyNotebook *nb,
+ GtkWidget *child);
+
+void ephy_notebook_move_page (EphyNotebook *src,
+ EphyNotebook *dest,
+ GtkWidget *src_page,
+ gint dest_page);
+
+void ephy_notebook_set_page_status (EphyNotebook *nb,
+ GtkWidget *child,
+ EphyNotebookPageLoadStatus status);
+
+void ephy_notebook_set_page_title (EphyNotebook *nb,
+ GtkWidget *child,
+ const char *title);
+
+G_END_DECLS;
+
+#endif /* EPHY_NOTEBOOK_H */
diff --git a/lib/widgets/ephy-spinner.c b/lib/widgets/ephy-spinner.c
new file mode 100644
index 000000000..e4462f889
--- /dev/null
+++ b/lib/widgets/ephy-spinner.c
@@ -0,0 +1,897 @@
+/*
+ * Nautilus
+ *
+ * Copyright (C) 2000 Eazel, Inc.
+ * Copyright (C) 2002 Marco Pesenti Gritti
+ *
+ * Nautilus is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Nautilus 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Andy Hertzfeld <andy@eazel.com>
+ *
+ * Ephy port by Marco Pesenti Gritti <marco@it.gnome.org>
+ *
+ * This is the spinner (for busy feedback) for the location bar
+ *
+ */
+
+#include "config.h"
+#include "ephy-spinner.h"
+#include "eel-gconf-extensions.h"
+#include "ephy-prefs.h"
+#include "ephy-string.h"
+#include "ephy-file-helpers.h"
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gtk/gtkmenu.h>
+#include <gtk/gtkmenuitem.h>
+#include <gtk/gtksignal.h>
+#include <libgnome/gnome-macros.h>
+#include <libgnome/gnome-util.h>
+#include <math.h>
+#include <libgnomevfs/gnome-vfs.h>
+
+#define spinner_DEFAULT_TIMEOUT 100 /* Milliseconds Per Frame */
+
+struct EphySpinnerDetails {
+ GList *image_list;
+
+ GdkPixbuf *quiescent_pixbuf;
+
+ int max_frame;
+ int delay;
+ int current_frame;
+ guint timer_task;
+
+ gboolean ready;
+ gboolean small_mode;
+
+ gboolean button_in;
+ gboolean button_down;
+
+ gint theme_notif;
+};
+
+static void ephy_spinner_class_init (EphySpinnerClass *class);
+static void ephy_spinner_init (EphySpinner *spinner);
+static void ephy_spinner_load_images (EphySpinner *spinner);
+static void ephy_spinner_unload_images (EphySpinner *spinner);
+static void ephy_spinner_remove_update_callback (EphySpinner *spinner);
+
+
+static GList *spinner_directories = NULL;
+
+static void
+ephy_spinner_init_directory_list (void);
+static void
+ephy_spinner_search_directory (const gchar *base, GList **spinner_list);
+static EphySpinnerInfo *
+ephy_spinner_get_theme_info (const gchar *base, const gchar *theme_name);
+static gchar *
+ephy_spinner_get_theme_path (const gchar *theme_name);
+
+
+static GObjectClass *parent_class = NULL;
+
+GType
+ephy_spinner_get_type (void)
+{
+ static GType ephy_spinner_type = 0;
+
+ if (ephy_spinner_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (EphySpinnerClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) ephy_spinner_class_init,
+ NULL,
+ NULL, /* class_data */
+ sizeof (EphySpinner),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) ephy_spinner_init
+ };
+
+ ephy_spinner_type = g_type_register_static (GTK_TYPE_EVENT_BOX,
+ "EphySpinner",
+ &our_info, 0);
+
+ ephy_spinner_init_directory_list ();
+ }
+
+ return ephy_spinner_type;
+
+}
+
+/*
+ * ephy_spinner_new:
+ *
+ * Create a new #EphySpinner. The spinner is a widget
+ * that gives the user feedback about network status with
+ * an animated image.
+ *
+ * Return Value: the spinner #GtkWidget
+ **/
+GtkWidget *
+ephy_spinner_new (void)
+{
+ GtkWidget *s;
+
+ s = GTK_WIDGET (g_object_new (EPHY_SPINNER_TYPE, NULL));
+
+ return s;
+}
+
+static gboolean
+is_throbbing (EphySpinner *spinner)
+{
+ return spinner->details->timer_task != 0;
+}
+
+/* loop through all the images taking their union to compute the width and height of the spinner */
+static void
+get_spinner_dimensions (EphySpinner *spinner, int *spinner_width, int* spinner_height)
+{
+ int current_width, current_height;
+ int pixbuf_width, pixbuf_height;
+ GList *current_entry;
+ GdkPixbuf *pixbuf;
+
+ /* start with the quiescent image */
+ current_width = gdk_pixbuf_get_width (spinner->details->quiescent_pixbuf);
+ current_height = gdk_pixbuf_get_height (spinner->details->quiescent_pixbuf);
+
+ /* loop through all the installed images, taking the union */
+ current_entry = spinner->details->image_list;
+ while (current_entry != NULL) {
+ pixbuf = GDK_PIXBUF (current_entry->data);
+ pixbuf_width = gdk_pixbuf_get_width (pixbuf);
+ pixbuf_height = gdk_pixbuf_get_height (pixbuf);
+
+ if (pixbuf_width > current_width) {
+ current_width = pixbuf_width;
+ }
+
+ if (pixbuf_height > current_height) {
+ current_height = pixbuf_height;
+ }
+
+ current_entry = current_entry->next;
+ }
+
+ /* return the result */
+ *spinner_width = current_width;
+ *spinner_height = current_height;
+}
+
+/* handler for handling theme changes */
+static void
+ephy_spinner_theme_changed (GConfClient *client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ gpointer user_data)
+{
+ EphySpinner *spinner;
+
+ spinner = EPHY_SPINNER (user_data);
+ gtk_widget_hide (GTK_WIDGET (spinner));
+ ephy_spinner_load_images (spinner);
+ gtk_widget_show (GTK_WIDGET (spinner));
+ gtk_widget_queue_resize ( GTK_WIDGET (spinner));
+}
+
+static void
+ephy_spinner_init (EphySpinner *spinner)
+{
+ GtkWidget *widget = GTK_WIDGET (spinner);
+
+ GTK_WIDGET_UNSET_FLAGS (spinner, GTK_NO_WINDOW);
+
+ gtk_widget_set_events (widget,
+ gtk_widget_get_events (widget)
+ | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+ | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
+
+ spinner->details = g_new0 (EphySpinnerDetails, 1);
+
+ spinner->details->delay = spinner_DEFAULT_TIMEOUT;
+
+ ephy_spinner_load_images (spinner);
+ gtk_widget_show (widget);
+
+ spinner->details->theme_notif =
+ eel_gconf_notification_add (CONF_TOOLBAR_SPINNER_THEME,
+ (GConfClientNotifyFunc)
+ ephy_spinner_theme_changed,
+ spinner);
+}
+
+/* here's the routine that selects the image to draw, based on the spinner's state */
+
+static GdkPixbuf *
+select_spinner_image (EphySpinner *spinner)
+{
+ GList *element;
+
+ if (spinner->details->timer_task == 0) {
+ return g_object_ref (spinner->details->quiescent_pixbuf);
+ }
+
+ if (spinner->details->image_list == NULL) {
+ return NULL;
+ }
+
+ element = g_list_nth (spinner->details->image_list, spinner->details->current_frame);
+
+ return g_object_ref (element->data);
+}
+
+static guchar
+lighten_component (guchar cur_value)
+{
+ int new_value = cur_value;
+ new_value += 24 + (new_value >> 3);
+ if (new_value > 255) {
+ new_value = 255;
+ }
+ return (guchar) new_value;
+}
+
+static GdkPixbuf *
+create_new_pixbuf (GdkPixbuf *src)
+{
+ g_return_val_if_fail (gdk_pixbuf_get_colorspace (src) == GDK_COLORSPACE_RGB, NULL);
+ g_return_val_if_fail ((!gdk_pixbuf_get_has_alpha (src)
+ && gdk_pixbuf_get_n_channels (src) == 3)
+ || (gdk_pixbuf_get_has_alpha (src)
+ && gdk_pixbuf_get_n_channels (src) == 4), NULL);
+
+ return gdk_pixbuf_new (gdk_pixbuf_get_colorspace (src),
+ gdk_pixbuf_get_has_alpha (src),
+ gdk_pixbuf_get_bits_per_sample (src),
+ gdk_pixbuf_get_width (src),
+ gdk_pixbuf_get_height (src));
+}
+
+static GdkPixbuf *
+eel_create_darkened_pixbuf (GdkPixbuf *src, int saturation, int darken)
+{
+ gint i, j;
+ gint width, height, src_row_stride, dest_row_stride;
+ gboolean has_alpha;
+ guchar *target_pixels, *original_pixels;
+ guchar *pixsrc, *pixdest;
+ guchar intensity;
+ guchar alpha;
+ guchar negalpha;
+ guchar r, g, b;
+ GdkPixbuf *dest;
+
+ g_return_val_if_fail (gdk_pixbuf_get_colorspace (src) == GDK_COLORSPACE_RGB, NULL);
+ g_return_val_if_fail ((!gdk_pixbuf_get_has_alpha (src)
+ && gdk_pixbuf_get_n_channels (src) == 3)
+ || (gdk_pixbuf_get_has_alpha (src)
+ && gdk_pixbuf_get_n_channels (src) == 4), NULL);
+ g_return_val_if_fail (gdk_pixbuf_get_bits_per_sample (src) == 8, NULL);
+
+ dest = create_new_pixbuf (src);
+
+ has_alpha = gdk_pixbuf_get_has_alpha (src);
+ width = gdk_pixbuf_get_width (src);
+ height = gdk_pixbuf_get_height (src);
+ dest_row_stride = gdk_pixbuf_get_rowstride (dest);
+ src_row_stride = gdk_pixbuf_get_rowstride (src);
+ target_pixels = gdk_pixbuf_get_pixels (dest);
+ original_pixels = gdk_pixbuf_get_pixels (src);
+
+ for (i = 0; i < height; i++) {
+ pixdest = target_pixels + i * dest_row_stride;
+ pixsrc = original_pixels + i * src_row_stride;
+ for (j = 0; j < width; j++) {
+ r = *pixsrc++;
+ g = *pixsrc++;
+ b = *pixsrc++;
+ intensity = (r * 77 + g * 150 + b * 28) >> 8;
+ negalpha = ((255 - saturation) * darken) >> 8;
+ alpha = (saturation * darken) >> 8;
+ *pixdest++ = (negalpha * intensity + alpha * r) >> 8;
+ *pixdest++ = (negalpha * intensity + alpha * g) >> 8;
+ *pixdest++ = (negalpha * intensity + alpha * b) >> 8;
+ if (has_alpha) {
+ *pixdest++ = *pixsrc++;
+ }
+ }
+ }
+ return dest;
+}
+
+static GdkPixbuf *
+eel_create_spotlight_pixbuf (GdkPixbuf* src)
+{
+ GdkPixbuf *dest;
+ int i, j;
+ int width, height, has_alpha, src_row_stride, dst_row_stride;
+ guchar *target_pixels, *original_pixels;
+ guchar *pixsrc, *pixdest;
+
+ g_return_val_if_fail (gdk_pixbuf_get_colorspace (src) == GDK_COLORSPACE_RGB, NULL);
+ g_return_val_if_fail ((!gdk_pixbuf_get_has_alpha (src)
+ && gdk_pixbuf_get_n_channels (src) == 3)
+ || (gdk_pixbuf_get_has_alpha (src)
+ && gdk_pixbuf_get_n_channels (src) == 4), NULL);
+ g_return_val_if_fail (gdk_pixbuf_get_bits_per_sample (src) == 8, NULL);
+
+ dest = create_new_pixbuf (src);
+
+ has_alpha = gdk_pixbuf_get_has_alpha (src);
+ width = gdk_pixbuf_get_width (src);
+ height = gdk_pixbuf_get_height (src);
+ dst_row_stride = gdk_pixbuf_get_rowstride (dest);
+ src_row_stride = gdk_pixbuf_get_rowstride (src);
+ target_pixels = gdk_pixbuf_get_pixels (dest);
+ original_pixels = gdk_pixbuf_get_pixels (src);
+
+ for (i = 0; i < height; i++) {
+ pixdest = target_pixels + i * dst_row_stride;
+ pixsrc = original_pixels + i * src_row_stride;
+ for (j = 0; j < width; j++) {
+ *pixdest++ = lighten_component (*pixsrc++);
+ *pixdest++ = lighten_component (*pixsrc++);
+ *pixdest++ = lighten_component (*pixsrc++);
+ if (has_alpha) {
+ *pixdest++ = *pixsrc++;
+ }
+ }
+ }
+ return dest;
+}
+
+/* handle expose events */
+
+static int
+ephy_spinner_expose (GtkWidget *widget, GdkEventExpose *event)
+{
+ EphySpinner *spinner;
+ GdkPixbuf *pixbuf, *massaged_pixbuf;
+ int x_offset, y_offset, width, height;
+ GdkRectangle pix_area, dest;
+
+ g_return_val_if_fail (IS_EPHY_SPINNER (widget), FALSE);
+
+ spinner = EPHY_SPINNER (widget);
+ if (!spinner->details->ready) {
+ return FALSE;
+ }
+
+ pixbuf = select_spinner_image (spinner);
+ if (pixbuf == NULL) {
+ return FALSE;
+ }
+
+ /* Get the right tint on the image */
+
+ if (spinner->details->button_in) {
+ if (spinner->details->button_down) {
+ massaged_pixbuf = eel_create_darkened_pixbuf (pixbuf, 0.8 * 255, 0.8 * 255);
+ } else {
+ massaged_pixbuf = eel_create_spotlight_pixbuf (pixbuf);
+ }
+ g_object_unref (pixbuf);
+ pixbuf = massaged_pixbuf;
+ }
+
+ width = gdk_pixbuf_get_width (pixbuf);
+ height = gdk_pixbuf_get_height (pixbuf);
+
+ /* Compute the offsets for the image centered on our allocation */
+ x_offset = widget->allocation.x + (widget->allocation.width - width) / 2;
+ y_offset = widget->allocation.y + (widget->allocation.height - height) / 2;
+
+ pix_area.x = x_offset;
+ pix_area.y = y_offset;
+ pix_area.width = width;
+ pix_area.height = height;
+
+ if (!gdk_rectangle_intersect (&event->area, &pix_area, &dest)) {
+ g_object_unref (pixbuf);
+ return FALSE;
+ }
+
+ gdk_pixbuf_render_to_drawable_alpha (
+ pixbuf, widget->window,
+ dest.x - x_offset, dest.y - y_offset,
+ dest.x, dest.y,
+ dest.width, dest.height,
+ GDK_PIXBUF_ALPHA_BILEVEL, 128,
+ GDK_RGB_DITHER_MAX,
+ 0, 0);
+
+ g_object_unref (pixbuf);
+
+ return FALSE;
+}
+
+static void
+ephy_spinner_map (GtkWidget *widget)
+{
+ EphySpinner *spinner;
+
+ spinner = EPHY_SPINNER (widget);
+
+ GTK_WIDGET_CLASS (parent_class)->map (widget);
+
+ spinner->details->ready = TRUE;
+}
+
+/* here's the actual timeout task to bump the frame and schedule a redraw */
+
+static gboolean
+bump_spinner_frame (gpointer callback_data)
+{
+ EphySpinner *spinner;
+
+ spinner = EPHY_SPINNER (callback_data);
+ if (!spinner->details->ready) {
+ return TRUE;
+ }
+
+ spinner->details->current_frame += 1;
+ if (spinner->details->current_frame > spinner->details->max_frame - 1) {
+ spinner->details->current_frame = 0;
+ }
+
+ gtk_widget_queue_draw (GTK_WIDGET (spinner));
+ return TRUE;
+}
+
+/**
+ * ephy_spinner_start:
+ * @spinner: a #EphySpinner
+ *
+ * Start the spinner animation.
+ **/
+void
+ephy_spinner_start (EphySpinner *spinner)
+{
+ if (is_throbbing (spinner)) {
+ return;
+ }
+
+ if (spinner->details->timer_task != 0) {
+ gtk_timeout_remove (spinner->details->timer_task);
+ }
+
+ /* reset the frame count */
+ spinner->details->current_frame = 0;
+ spinner->details->timer_task = gtk_timeout_add (spinner->details->delay,
+ bump_spinner_frame,
+ spinner);
+}
+
+static void
+ephy_spinner_remove_update_callback (EphySpinner *spinner)
+{
+ if (spinner->details->timer_task != 0) {
+ gtk_timeout_remove (spinner->details->timer_task);
+ }
+
+ spinner->details->timer_task = 0;
+}
+
+/**
+ * ephy_spinner_stop:
+ * @spinner: a #EphySpinner
+ *
+ * Stop the spinner animation.
+ **/
+void
+ephy_spinner_stop (EphySpinner *spinner)
+{
+ if (!is_throbbing (spinner)) {
+ return;
+ }
+
+ ephy_spinner_remove_update_callback (spinner);
+ gtk_widget_queue_draw (GTK_WIDGET (spinner));
+
+}
+
+/* routines to load the images used to draw the spinner */
+
+/* unload all the images, and the list itself */
+
+static void
+ephy_spinner_unload_images (EphySpinner *spinner)
+{
+ GList *current_entry;
+
+ if (spinner->details->quiescent_pixbuf != NULL) {
+ g_object_unref (spinner->details->quiescent_pixbuf);
+ spinner->details->quiescent_pixbuf = NULL;
+ }
+
+ /* unref all the images in the list, and then let go of the list itself */
+ current_entry = spinner->details->image_list;
+ while (current_entry != NULL) {
+ g_object_unref (current_entry->data);
+ current_entry = current_entry->next;
+ }
+
+ g_list_free (spinner->details->image_list);
+ spinner->details->image_list = NULL;
+}
+
+static GdkPixbuf*
+load_themed_image (const char *path, const char *file_name,
+ gboolean small_mode)
+{
+ GdkPixbuf *pixbuf, *temp_pixbuf;
+ char *image_path;
+
+ image_path = g_build_filename (path, file_name, NULL);
+
+ if (!g_file_test(image_path, G_FILE_TEST_EXISTS))
+ {
+ g_free (image_path);
+ return NULL;
+ }
+
+ if (image_path) {
+ pixbuf = gdk_pixbuf_new_from_file (image_path, NULL);
+
+ if (small_mode && pixbuf) {
+ temp_pixbuf = gdk_pixbuf_scale_simple (pixbuf,
+ gdk_pixbuf_get_width (pixbuf) * 2 / 3,
+ gdk_pixbuf_get_height (pixbuf) * 2 / 3,
+ GDK_INTERP_BILINEAR);
+ g_object_unref (pixbuf);
+ pixbuf = temp_pixbuf;
+ }
+
+ g_free (image_path);
+
+ return pixbuf;
+ }
+ return NULL;
+}
+
+/* utility to make the spinner frame name from the index */
+
+static char *
+make_spinner_frame_name (int index)
+{
+ return g_strdup_printf ("%03d.png", index);
+}
+
+/* load all of the images of the spinner sequentially */
+static void
+ephy_spinner_load_images (EphySpinner *spinner)
+{
+ int index;
+ char *spinner_frame_name;
+ GdkPixbuf *pixbuf, *qpixbuf;
+ GList *image_list;
+ char *image_theme;
+ char *path;
+
+ ephy_spinner_unload_images (spinner);
+
+ image_theme = eel_gconf_get_string (CONF_TOOLBAR_SPINNER_THEME);
+
+ path = ephy_spinner_get_theme_path (image_theme);
+ g_return_if_fail (path != NULL);
+
+ qpixbuf = load_themed_image (path, "rest.png",
+ spinner->details->small_mode);
+
+ g_return_if_fail (qpixbuf != NULL);
+ spinner->details->quiescent_pixbuf = qpixbuf;
+
+ spinner->details->max_frame = 50;
+
+ image_list = NULL;
+ for (index = 1; index <= spinner->details->max_frame; index++) {
+ spinner_frame_name = make_spinner_frame_name (index);
+ pixbuf = load_themed_image (path, spinner_frame_name,
+ spinner->details->small_mode);
+ g_free (spinner_frame_name);
+ if (pixbuf == NULL) {
+ spinner->details->max_frame = index - 1;
+ break;
+ }
+ image_list = g_list_prepend (image_list, pixbuf);
+ }
+ spinner->details->image_list = g_list_reverse (image_list);
+
+ g_free (image_theme);
+}
+
+static gboolean
+ephy_spinner_enter_notify_event (GtkWidget *widget, GdkEventCrossing *event)
+{
+ EphySpinner *spinner;
+
+ spinner = EPHY_SPINNER (widget);
+
+ if (!spinner->details->button_in) {
+ spinner->details->button_in = TRUE;
+ gtk_widget_queue_draw (widget);
+ }
+
+ return FALSE;
+}
+
+static gboolean
+ephy_spinner_leave_notify_event (GtkWidget *widget, GdkEventCrossing *event)
+{
+ EphySpinner *spinner;
+
+ spinner = EPHY_SPINNER (widget);
+
+ if (spinner->details->button_in) {
+ spinner->details->button_in = FALSE;
+ gtk_widget_queue_draw (widget);
+ }
+
+ return FALSE;
+}
+
+/* handle button presses by posting a change on the "location" property */
+
+static gboolean
+ephy_spinner_button_press_event (GtkWidget *widget, GdkEventButton *event)
+{
+ EphySpinner *spinner;
+
+ spinner = EPHY_SPINNER (widget);
+
+ if (event->button == 1) {
+ spinner->details->button_down = TRUE;
+ spinner->details->button_in = TRUE;
+ gtk_widget_queue_draw (widget);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+ephy_spinner_set_location (EphySpinner *spinner)
+{
+}
+
+static gboolean
+ephy_spinner_button_release_event (GtkWidget *widget, GdkEventButton *event)
+{
+ EphySpinner *spinner;
+
+ spinner = EPHY_SPINNER (widget);
+
+ if (event->button == 1) {
+ if (spinner->details->button_in) {
+ ephy_spinner_set_location (spinner);
+ }
+ spinner->details->button_down = FALSE;
+ gtk_widget_queue_draw (widget);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/*
+ * ephy_spinner_set_small_mode:
+ * @spinner: a #EphySpinner
+ * @new_mode: pass true to enable the small mode, false to disable
+ *
+ * Set the size mode of the spinner. We need a small mode to deal
+ * with only icons toolbars.
+ **/
+void
+ephy_spinner_set_small_mode (EphySpinner *spinner, gboolean new_mode)
+{
+ if (new_mode != spinner->details->small_mode) {
+ spinner->details->small_mode = new_mode;
+ ephy_spinner_load_images (spinner);
+
+ gtk_widget_queue_resize (GTK_WIDGET (spinner));
+ }
+}
+
+/* handle setting the size */
+
+static void
+ephy_spinner_size_request (GtkWidget *widget, GtkRequisition *requisition)
+{
+ int spinner_width, spinner_height;
+ EphySpinner *spinner = EPHY_SPINNER (widget);
+
+ get_spinner_dimensions (spinner, &spinner_width, &spinner_height);
+
+ /* allocate some extra margin so we don't butt up against toolbar edges */
+ requisition->width = spinner_width + 8;
+ requisition->height = spinner_height;
+}
+
+static void
+ephy_spinner_finalize (GObject *object)
+{
+ EphySpinner *spinner;
+
+ spinner = EPHY_SPINNER (object);
+
+ ephy_spinner_remove_update_callback (spinner);
+ ephy_spinner_unload_images (spinner);
+
+ eel_gconf_notification_remove (spinner->details->theme_notif);
+
+ g_free (spinner->details);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+ephy_spinner_class_init (EphySpinnerClass *class)
+{
+ GtkWidgetClass *widget_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ widget_class = GTK_WIDGET_CLASS (class);
+
+ G_OBJECT_CLASS (class)->finalize = ephy_spinner_finalize;
+
+ widget_class->expose_event = ephy_spinner_expose;
+ widget_class->button_press_event = ephy_spinner_button_press_event;
+ widget_class->button_release_event = ephy_spinner_button_release_event;
+ widget_class->enter_notify_event = ephy_spinner_enter_notify_event;
+ widget_class->leave_notify_event = ephy_spinner_leave_notify_event;
+ widget_class->size_request = ephy_spinner_size_request;
+ widget_class->map = ephy_spinner_map;
+}
+
+static void
+ephy_spinner_search_directory (const gchar *base, GList **spinner_list)
+{
+ GnomeVFSResult rc;
+ GList *list, *node;
+
+ rc = gnome_vfs_directory_list_load
+ (&list, base, (GNOME_VFS_FILE_INFO_GET_MIME_TYPE |
+ GNOME_VFS_FILE_INFO_FORCE_FAST_MIME_TYPE |
+ GNOME_VFS_FILE_INFO_FOLLOW_LINKS));
+ if (rc != GNOME_VFS_OK) return;
+
+ for (node = list; node != NULL; node = g_list_next (node))
+ {
+ GnomeVFSFileInfo *file_info = node->data;
+ EphySpinnerInfo *info;
+
+ if (file_info->name[0] == '.')
+ continue;
+ if (file_info->type != GNOME_VFS_FILE_TYPE_DIRECTORY)
+ continue;
+
+ info = ephy_spinner_get_theme_info (base, file_info->name);
+ if (info != NULL)
+ {
+ *spinner_list = g_list_append (*spinner_list, info);
+ }
+ }
+
+ gnome_vfs_file_info_list_free (list);
+}
+
+static EphySpinnerInfo *
+ephy_spinner_get_theme_info (const gchar *base, const gchar *theme_name)
+{
+ EphySpinnerInfo *info;
+ gchar *path;
+ gchar *icon;
+
+ path = g_build_filename (base, theme_name, NULL);
+ icon = g_build_filename (path, "rest.png", NULL);
+
+ if (!g_file_test (icon, G_FILE_TEST_EXISTS))
+ {
+ g_free (path);
+ g_free (icon);
+
+ /* handle nautilus throbbers as well */
+
+ path = g_build_filename (base, theme_name, "throbber", NULL);
+ icon = g_build_filename (path, "rest.png", NULL);
+ }
+
+ if (!g_file_test (icon, G_FILE_TEST_EXISTS))
+ {
+ g_free (path);
+ g_free (icon);
+
+ return NULL;
+ }
+
+ info = g_new(EphySpinnerInfo, 1);
+ info->name = g_strdup (theme_name);
+ info->directory = path;
+ info->filename = icon;
+
+ return info;
+}
+
+static void
+ephy_spinner_init_directory_list (void)
+{
+ gchar *path;
+
+ path = g_build_filename (g_get_home_dir (), ephy_dot_dir (), "spinners", NULL);
+ spinner_directories = g_list_append (spinner_directories, path);
+
+ path = g_build_filename (SHARE_DIR, "spinners", NULL);
+ spinner_directories = g_list_append (spinner_directories, path);
+
+ path = g_build_filename (SHARE_DIR, "..", "pixmaps", "nautilus", NULL);
+ spinner_directories = g_list_append (spinner_directories, path);
+
+#ifdef NAUTILUS_PREFIX
+ path = g_build_filename (NAUTILUS_PREFIX, "share", "pixmaps", "nautilus", NULL);
+ spinner_directories = g_list_append (spinner_directories, path);
+#endif
+}
+
+GList *
+ephy_spinner_list_spinners (void)
+{
+ GList *spinner_list = NULL;
+ GList *tmp;
+
+ for (tmp = spinner_directories; tmp != NULL; tmp = g_list_next (tmp))
+ {
+ gchar *path = tmp->data;
+ ephy_spinner_search_directory (path, &spinner_list);
+ }
+
+ return spinner_list;
+}
+
+static gchar *
+ephy_spinner_get_theme_path (const gchar *theme_name)
+{
+ EphySpinnerInfo *info;
+ GList *tmp;
+
+ for (tmp = spinner_directories; tmp != NULL; tmp = g_list_next (tmp))
+ {
+ gchar *path = tmp->data;
+
+ info = ephy_spinner_get_theme_info (path, theme_name);
+ if (info != NULL)
+ {
+ path = g_strdup (info->directory);
+ ephy_spinner_info_free (info);
+ return path;
+ }
+ }
+
+ return NULL;
+}
+
+void
+ephy_spinner_info_free (EphySpinnerInfo *info)
+{
+ g_free (info->name);
+ g_free (info->directory);
+ g_free (info->filename);
+ g_free (info);
+}
diff --git a/lib/widgets/ephy-spinner.h b/lib/widgets/ephy-spinner.h
new file mode 100644
index 000000000..c72bee8c1
--- /dev/null
+++ b/lib/widgets/ephy-spinner.h
@@ -0,0 +1,78 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+
+/*
+ * Nautilus
+ *
+ * Copyright (C) 2000 Eazel, Inc.
+ *
+ * Nautilus is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Nautilus 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Andy Hertzfeld <andy@eazel.com>
+ *
+ * This is the header file for the throbber on the location bar
+ *
+ */
+
+#ifndef EPHY_SPINNER_H
+#define EPHY_SPINNER_H
+
+#include <gtk/gtkeventbox.h>
+#include <bonobo.h>
+
+G_BEGIN_DECLS
+
+#define EPHY_SPINNER_TYPE (ephy_spinner_get_type ())
+#define EPHY_SPINNER(obj) (GTK_CHECK_CAST ((obj), EPHY_SPINNER_TYPE, EphySpinner))
+#define EPHY_SPINNER_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), EPHY_SPINNER_TYPE, EphySpinnerClass))
+#define IS_EPHY_SPINNER(obj) (GTK_CHECK_TYPE ((obj), EPHY_SPINNER_TYPE))
+#define IS_EPHY_SPINNER_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), EPHY_SPINNER_TYPE))
+
+typedef struct EphySpinnerInfo EphySpinnerInfo;
+
+struct EphySpinnerInfo
+{
+ gchar *name;
+ gchar *filename;
+ gchar *directory;
+};
+
+typedef struct EphySpinner EphySpinner;
+typedef struct EphySpinnerClass EphySpinnerClass;
+typedef struct EphySpinnerDetails EphySpinnerDetails;
+
+struct EphySpinner {
+ GtkEventBox parent;
+ EphySpinnerDetails *details;
+};
+
+struct EphySpinnerClass {
+ GtkEventBoxClass parent_class;
+};
+
+GtkType ephy_spinner_get_type (void);
+GtkWidget *ephy_spinner_new (void);
+void ephy_spinner_start (EphySpinner *throbber);
+void ephy_spinner_stop (EphySpinner *throbber);
+void ephy_spinner_set_small_mode (EphySpinner *throbber,
+ gboolean new_mode);
+
+GList *ephy_spinner_list_spinners (void);
+void ephy_spinner_info_free (EphySpinnerInfo *info);
+
+G_END_DECLS
+
+#endif /* EPHY_SPINNER_H */
+
+
diff --git a/lib/widgets/ephy-tree-model-sort.c b/lib/widgets/ephy-tree-model-sort.c
new file mode 100644
index 000000000..3c2377cf0
--- /dev/null
+++ b/lib/widgets/ephy-tree-model-sort.c
@@ -0,0 +1,240 @@
+/* Rhythmbox.
+ * Copyright (C) 2002 Olivier Martin <omartin@ifrance.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Id$
+ */
+
+#include <gtk/gtkmarshal.h>
+#include <string.h>
+
+#include "ephy-node.h"
+#include "ephy-tree-model-sort.h"
+#include "eggtreemultidnd.h"
+#include "ephy-dnd.h"
+#include "ephy-marshal.h"
+
+static void ephy_tree_model_sort_class_init (EphyTreeModelSortClass *klass);
+static void ephy_tree_model_sort_init (EphyTreeModelSort *ma);
+static void ephy_tree_model_sort_finalize (GObject *object);
+static void ephy_tree_model_sort_multi_drag_source_init (EggTreeMultiDragSourceIface *iface);
+static gboolean ephy_tree_model_sort_multi_row_draggable (EggTreeMultiDragSource *drag_source,
+ GList *path_list);
+static gboolean ephy_tree_model_sort_multi_drag_data_get (EggTreeMultiDragSource *drag_source,
+ GList *path_list,
+ guint info,
+ GtkSelectionData *selection_data);
+static gboolean ephy_tree_model_sort_multi_drag_data_delete (EggTreeMultiDragSource *drag_source,
+ GList *path_list);
+
+struct EphyTreeModelSortPrivate
+{
+ char *str_list;
+};
+
+enum
+{
+ NODE_FROM_ITER,
+ LAST_SIGNAL
+};
+
+static GObjectClass *parent_class = NULL;
+
+static guint ephy_tree_model_sort_signals[LAST_SIGNAL] = { 0 };
+
+GType
+ephy_tree_model_sort_get_type (void)
+{
+ static GType ephy_tree_model_sort_type = 0;
+
+ if (ephy_tree_model_sort_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (EphyTreeModelSortClass),
+ NULL, /* base init */
+ NULL, /* base finalize */
+ (GClassInitFunc) ephy_tree_model_sort_class_init,
+ NULL, /* class finalize */
+ NULL, /* class data */
+ sizeof (EphyTreeModelSort),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) ephy_tree_model_sort_init
+ };
+ static const GInterfaceInfo multi_drag_source_info =
+ {
+ (GInterfaceInitFunc) ephy_tree_model_sort_multi_drag_source_init,
+ NULL,
+ NULL
+ };
+
+ ephy_tree_model_sort_type = g_type_register_static (GTK_TYPE_TREE_MODEL_SORT,
+ "EphyTreeModelSort",
+ &our_info, 0);
+
+ g_type_add_interface_static (ephy_tree_model_sort_type,
+ EGG_TYPE_TREE_MULTI_DRAG_SOURCE,
+ &multi_drag_source_info);
+ }
+
+ return ephy_tree_model_sort_type;
+}
+
+static void
+ephy_tree_model_sort_class_init (EphyTreeModelSortClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = ephy_tree_model_sort_finalize;
+
+ ephy_tree_model_sort_signals[NODE_FROM_ITER] =
+ g_signal_new ("node_from_iter",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EphyTreeModelSortClass, node_from_iter),
+ NULL, NULL,
+ ephy_marshal_VOID__POINTER_POINTER,
+ G_TYPE_NONE,
+ 2,
+ G_TYPE_POINTER,
+ G_TYPE_POINTER);
+}
+
+static void
+ephy_tree_model_sort_init (EphyTreeModelSort *ma)
+{
+ ma->priv = g_new0 (EphyTreeModelSortPrivate, 1);
+}
+
+static void
+ephy_tree_model_sort_finalize (GObject *object)
+{
+ EphyTreeModelSort *model;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (EPHY_IS_TREE_MODEL_SORT (object));
+
+ model = EPHY_TREE_MODEL_SORT (object);
+
+ g_free (model->priv->str_list);
+ g_free (model->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+GtkTreeModel*
+ephy_tree_model_sort_new (GtkTreeModel *child_model)
+{
+ GtkTreeModel *model;
+
+ g_return_val_if_fail (child_model != NULL, NULL);
+
+ model = GTK_TREE_MODEL (g_object_new (EPHY_TYPE_TREE_MODEL_SORT,
+ "model", child_model,
+ NULL));
+
+ return model;
+}
+
+static void
+ephy_tree_model_sort_multi_drag_source_init (EggTreeMultiDragSourceIface *iface)
+{
+ iface->row_draggable = ephy_tree_model_sort_multi_row_draggable;
+ iface->drag_data_get = ephy_tree_model_sort_multi_drag_data_get;
+ iface->drag_data_delete = ephy_tree_model_sort_multi_drag_data_delete;
+}
+
+static gboolean
+ephy_tree_model_sort_multi_row_draggable (EggTreeMultiDragSource *drag_source, GList *path_list)
+{
+ GList *l;
+
+ for (l = path_list; l != NULL; l = g_list_next (l))
+ {
+ GtkTreeIter iter;
+ GtkTreePath *path;
+ EphyNode *node = NULL;
+
+ path = gtk_tree_row_reference_get_path (l->data);
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (drag_source), &iter, path);
+ g_signal_emit (G_OBJECT (drag_source),
+ ephy_tree_model_sort_signals[NODE_FROM_ITER],
+ 0, &iter, &node);
+
+ if (node == NULL)
+ {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+static gboolean
+ephy_tree_model_sort_multi_drag_data_delete (EggTreeMultiDragSource *drag_source,
+ GList *path_list)
+{
+ return TRUE;
+}
+
+static void
+each_url_get_data_binder (EphyDragEachSelectedItemDataGet iteratee,
+ gpointer iterator_context, gpointer data)
+{
+ gpointer *context = (gpointer *) iterator_context;
+ GList *path_list = (GList *) (context[0]);
+ GList *i;
+ GtkTreeModel *model = GTK_TREE_MODEL (context[1]);
+
+ for (i = path_list; i != NULL; i = i->next)
+ {
+ GtkTreeIter iter;
+ GtkTreePath *path = gtk_tree_row_reference_get_path (i->data);
+ EphyNode *node = NULL;
+ const char *value;
+
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path);
+ g_signal_emit (G_OBJECT (model),
+ ephy_tree_model_sort_signals[NODE_FROM_ITER],
+ 0, &iter, &node);
+
+ if (node == NULL)
+ return;
+
+ value = ephy_node_get_property_string (node,
+ EPHY_DND_NODE_PROPERTY);
+
+ iteratee (value, -1, -1, -1, -1, data);
+ }
+}
+
+static gboolean
+ephy_tree_model_sort_multi_drag_data_get (EggTreeMultiDragSource *drag_source,
+ GList *path_list,
+ guint info,
+ GtkSelectionData *selection_data)
+{ gpointer icontext[2];
+
+ icontext[0] = path_list;
+ icontext[1] = drag_source;
+
+ ephy_dnd_drag_data_get (NULL, NULL, selection_data,
+ info, 0, &icontext, each_url_get_data_binder);
+
+ return TRUE;
+}
diff --git a/lib/widgets/ephy-tree-model-sort.h b/lib/widgets/ephy-tree-model-sort.h
new file mode 100644
index 000000000..f8cb9fb68
--- /dev/null
+++ b/lib/widgets/ephy-tree-model-sort.h
@@ -0,0 +1,59 @@
+/* Copyright (C) 2002 Olivier Martin <omartin@ifrance.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Id$
+ */
+
+#ifndef EPHY_TREE_MODEL_SORT_H
+#define EPHY_TREE_MODEL_SORT_H
+
+#include <glib-object.h>
+
+#include <gtk/gtktreemodelsort.h>
+
+G_BEGIN_DECLS
+
+#define EPHY_TYPE_TREE_MODEL_SORT (ephy_tree_model_sort_get_type ())
+#define EPHY_TREE_MODEL_SORT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EPHY_TYPE_TREE_MODEL_SORT, EphyTreeModelSort))
+#define EPHY_TREE_MODEL_SORT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EPHY_TYPE_TREE_MODEL_SORT, EphyTreeModelSortClass))
+#define EPHY_IS_TREE_MODEL_SORT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EPHY_TYPE_TREE_MODEL_SORT))
+#define EPHY_IS_TREE_MODEL_SORT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EPHY_TYPE_TREE_MODEL_SORT))
+#define EPHY_TREE_MODEL_SORT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EPHY_TYPE_TREE_MODEL_SORT, EphyTreeModelSortClass))
+
+typedef struct EphyTreeModelSortPrivate EphyTreeModelSortPrivate;
+
+typedef struct
+{
+ GtkTreeModelSort parent;
+
+ EphyTreeModelSortPrivate *priv;
+} EphyTreeModelSort;
+
+typedef struct
+{
+ GtkTreeModelSortClass parent_class;
+
+ void (*node_from_iter) (EphyTreeModelSort *model, GtkTreeIter *iter, void **node);
+} EphyTreeModelSortClass;
+
+GType ephy_tree_model_sort_get_type (void);
+
+GtkTreeModel *ephy_tree_model_sort_new (GtkTreeModel *child_model);
+
+
+G_END_DECLS
+
+#endif /* EPHY_TREE_MODEL_SORT_H */
diff --git a/po/.cvsignore b/po/.cvsignore
new file mode 100644
index 000000000..69ef08425
--- /dev/null
+++ b/po/.cvsignore
@@ -0,0 +1,6 @@
+Makefile
+Makefile.in
+Makefile.in.in
+POTFILES
+.intltool-merge-cache
+epiphany-2.0.pot
diff --git a/po/ChangeLog b/po/ChangeLog
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/po/ChangeLog
diff --git a/po/POTFILES.in b/po/POTFILES.in
new file mode 100644
index 000000000..769ba1a42
--- /dev/null
+++ b/po/POTFILES.in
@@ -0,0 +1,45 @@
+data/GNOME_Epiphany_Automation.server.in
+data/GNOME_Epiphany_NautilusView.server.in
+data/epiphany.schemas.in
+data/glade/epiphany.glade
+data/glade/prefs-dialog.glade
+data/glade/print.glade
+data/glade/prompts.glade
+data/glade/toolbar-editor.glade
+data/ui/epiphany-ui.xml
+data/ui/epiphany-ui.xml.in
+data/ui/nautilus-epiphany-view.xml
+data/ui/nautilus-epiphany-view.xml.in
+embed/downloader-view.c
+embed/ephy-embed-utils.c
+embed/ephy-history.c
+embed/mozilla/ContentHandler.cpp
+embed/mozilla/ExternalProtocolService.cpp
+embed/mozilla/FilePicker.cpp
+embed/mozilla/PromptService.cpp
+embed/mozilla/mozilla-embed-shell.cpp
+embed/mozilla/mozilla-i18n.c
+embed/mozilla/mozilla-notifiers.cpp
+lib/eel-gconf-extensions.c
+lib/ephy-file-helpers.c
+lib/ephy-gui.c
+lib/ephy-string.c
+lib/toolbar/ephy-tbi-favicon.c
+lib/toolbar/ephy-tbi-location.c
+lib/toolbar/ephy-tbi-navigation-history.c
+lib/toolbar/ephy-tbi-separator.c
+lib/toolbar/ephy-tbi-spinner.c
+lib/toolbar/ephy-tbi-std-toolitem.c
+lib/toolbar/ephy-tbi-zoom.c
+lib/widgets/ephy-notebook.c
+src/bookmarks/ephy-bookmarks-editor.c
+src/ephy-main.c
+src/ephy-nautilus-view.c
+src/ephy-tab.c
+src/ephy-window.c
+src/general-prefs.c
+src/history-dialog.c
+src/pdm-dialog.c
+src/prefs-dialog.c
+src/toolbar.c
+src/window-commands.c
diff --git a/src/.cvsignore b/src/.cvsignore
new file mode 100644
index 000000000..27d9d0cd0
--- /dev/null
+++ b/src/.cvsignore
@@ -0,0 +1,6 @@
+*.o
+Makefile
+Makefile.in
+.deps
+.libs
+epiphany
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 000000000..5ec49453d
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,101 @@
+SUBDIRS = bookmarks
+
+INCLUDES = \
+ -I$(top_srcdir)/embed \
+ -I$(top_srcdir)/lib \
+ -I$(top_srcdir)/lib/widgets \
+ -I$(top_srcdir)/lib/toolbar \
+ -I$(top_srcdir)/src/bookmarks \
+ $(WARN_CFLAGS) \
+ $(EPIPHANY_DEPENDENCY_CFLAGS) \
+ -DSHARE_DIR=\"$(pkgdatadir)\" \
+ -DDATADIR=\""$(datadir)"\" \
+ -DPIXMAP_DIR=\""$(datadir)/pixmaps"\" \
+ -DGNOMELOCALEDIR=\""$(datadir)/locale"\" \
+ -DG_DISABLE_DEPRECATED \
+ -DGDK_DISABLE_DEPRECATED \
+ -DGTK_DISABLE_DEPRECATED \
+ -DGDK_PIXBUF_DISABLE_DEPRECATED \
+ -DGNOME_DISABLE_DEPRECATED
+
+bin_PROGRAMS = epiphany
+
+CXXLD = $(CXX)
+LINK = $(LIBTOOL) --mode=link $(CXXLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
+
+
+ephy_automation_interface_idl_sources = \
+ EphyAutomation-common.c \
+ EphyAutomation-stubs.c \
+ EphyAutomation-skels.c \
+ EphyAutomation.h
+
+if ENABLE_NAUTILUS_VIEW
+nautilus_view_sources = \
+ ephy-nautilus-view.c \
+ ephy-nautilus-view.h
+else
+nautilus_view_sources =
+endif
+
+epiphany_SOURCES = \
+ $(ephy_automation_interface_idl_sources) \
+ $(nautilus_view_sources) \
+ ui-prefs.c \
+ ui-prefs.h \
+ prefs-dialog.c \
+ prefs-dialog.h \
+ toolbar.c \
+ toolbar.h \
+ statusbar.c \
+ statusbar.h \
+ ephy-main.c \
+ ephy-automation.c \
+ ephy-automation.h \
+ ephy-shell.c \
+ ephy-shell.h \
+ ephy-tab.c \
+ ephy-tab.h \
+ ephy-window.c \
+ ephy-window.h \
+ window-commands.c \
+ window-commands.h \
+ popup-commands.c \
+ popup-commands.h \
+ history-dialog.c \
+ history-dialog.h \
+ ppview-toolbar.c \
+ ppview-toolbar.h \
+ session.c \
+ session.h \
+ general-prefs.c \
+ general-prefs.h \
+ language-editor.c \
+ language-editor.h \
+ appearance-prefs.c \
+ appearance-prefs.h \
+ pdm-dialog.c \
+ pdm-dialog.h \
+ ephy-favorites-menu.c \
+ ephy-favorites-menu.h \
+ ephy-history-model.c \
+ ephy-history-model.h
+
+epiphany_LDADD = \
+ $(top_builddir)/embed/libephyembed.la \
+ $(top_builddir)/lib/libephy.la \
+ $(top_builddir)/src/bookmarks/libephybookmarks.la \
+ $(MOZILLA_COMPONENT_LIBS) \
+ $(EPIPHANY_DEPENDENCY_LIBS) \
+ $(INTLLIBS)
+
+
+BUILT_SOURCES= \
+ EphyAutomation.h EphyAutomation-common.c EphyAutomation-stubs.c EphyAutomation-skels.c
+
+CLEAN_FILES = $(BUILT_SOURCES)
+
+EphyAutomation-common.c EphyAutomation-stubs.c EphyAutomation-skels.c EphyAutomation.h: $(top_srcdir)/idl/EphyAutomation.idl
+ $(ORBIT_IDL) -I $(LIBBONOBO_IDL) -I $(BONOBO_ACTIVATION_IDL) $(top_srcdir)/idl/EphyAutomation.idl
+
+EXTRA_DIST = $(top_srcdir)/idl/EphyAutomation.idl
diff --git a/src/appearance-prefs.c b/src/appearance-prefs.c
new file mode 100755
index 000000000..da1056f3f
--- /dev/null
+++ b/src/appearance-prefs.c
@@ -0,0 +1,458 @@
+/*
+ * Copyright (C) 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "appearance-prefs.h"
+#include "ephy-shell.h"
+#include "ephy-prefs.h"
+#include "ephy-embed-prefs.h"
+#include "eel-gconf-extensions.h"
+
+#include <string.h>
+#include <gtk/gtkcombo.h>
+#include <gtk/gtkspinbutton.h>
+#include <gtk/gtkeditable.h>
+#include <gtk/gtkoptionmenu.h>
+
+static void appearance_prefs_class_init (AppearancePrefsClass *klass);
+static void appearance_prefs_init (AppearancePrefs *dialog);
+static void appearance_prefs_finalize (GObject *object);
+
+/* Glade callbacks */
+void
+fonts_language_optionmenu_changed_cb (GtkWidget *optionmenu, EphyDialog *dialog);
+
+static GObjectClass *parent_class = NULL;
+
+struct AppearancePrefsPrivate
+{
+ int language;
+ gboolean switching;
+};
+
+enum
+{
+ SERIF_PROP,
+ SANSSERIF_PROP,
+ MONOSPACE_PROP,
+ FIXED_SIZE_PROP,
+ VARIABLE_SIZE_PROP,
+ MIN_SIZE_PROP,
+ PROPORTIONAL_PROP,
+ BACKGROUND_PROP,
+ TEXT_PROP,
+ UNVISITED_PROP,
+ VISITED_PROP,
+ USE_SYSCOLORS_PROP,
+ USE_COLORS_PROP,
+ USE_FONTS_PROP,
+};
+
+static const
+EphyDialogProperty properties [] =
+{
+ { SERIF_PROP, "serif_combo", NULL, PT_NORMAL, NULL },
+ { SANSSERIF_PROP, "sansserif_combo", NULL, PT_NORMAL, NULL },
+ { MONOSPACE_PROP, "monospace_combo", NULL, PT_NORMAL, NULL },
+ { FIXED_SIZE_PROP, "fixed_size_spinbutton", NULL, PT_NORMAL, NULL },
+ { VARIABLE_SIZE_PROP, "variable_size_spinbutton", NULL, PT_NORMAL, NULL },
+ { MIN_SIZE_PROP, "min_size_spinbutton", NULL, PT_NORMAL, NULL },
+ { PROPORTIONAL_PROP, "proportional_optionmenu", CONF_RENDERING_DEFAULT_FONT, PT_AUTOAPPLY, NULL },
+ { BACKGROUND_PROP, "background_cpick", CONF_RENDERING_BG_COLOR, PT_AUTOAPPLY, NULL },
+ { TEXT_PROP, "text_cpick", CONF_RENDERING_TEXT_COLOR, PT_AUTOAPPLY, NULL },
+ { UNVISITED_PROP, "unvisited_cpick", CONF_RENDERING_UNVISITED_LINKS, PT_AUTOAPPLY, NULL },
+ { VISITED_PROP, "visited_cpick", CONF_RENDERING_VISITED_LINKS, PT_AUTOAPPLY, NULL },
+ { USE_SYSCOLORS_PROP, "use_syscolors_checkbutton", CONF_RENDERING_USE_SYSTEM_COLORS, PT_AUTOAPPLY, NULL },
+ { USE_COLORS_PROP, "use_colors_checkbutton", CONF_RENDERING_USE_OWN_COLORS, PT_AUTOAPPLY, NULL },
+ { USE_FONTS_PROP, "use_fonts_checkbutton", CONF_RENDERING_USE_OWN_FONTS, PT_AUTOAPPLY, NULL },
+
+ { -1, NULL, NULL }
+};
+
+/* FIXME duped in mozilla/ */
+const
+char *lang_encode[] =
+{
+ "x-western",
+ "x-central-euro",
+ "ja",
+ "zh-TW",
+ "zh-CN",
+ "ko",
+ "x-cyrillic",
+ "x-baltic",
+ "el",
+ "tr",
+ "x-unicode",
+ "th",
+ "he",
+ "ar"
+};
+
+enum
+{
+ FONT_TYPE_SERIF,
+ FONT_TYPE_SANSSERIF,
+ FONT_TYPE_MONOSPACE
+};
+
+const
+char *fonts_types[] =
+{
+ "serif",
+ "sans-serif",
+ "monospace"
+};
+
+enum
+{
+ FONT_SIZE_FIXED,
+ FONT_SIZE_VAR,
+ FONT_SIZE_MIN
+};
+
+const
+char *size_prefs[] =
+{
+ CONF_RENDERING_FONT_FIXED_SIZE,
+ CONF_RENDERING_FONT_VAR_SIZE,
+ CONF_RENDERING_FONT_MIN_SIZE
+};
+
+GType
+appearance_prefs_get_type (void)
+{
+ static GType appearance_prefs_type = 0;
+
+ if (appearance_prefs_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (AppearancePrefsClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) appearance_prefs_class_init,
+ NULL,
+ NULL, /* class_data */
+ sizeof (AppearancePrefs),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) appearance_prefs_init
+ };
+
+ appearance_prefs_type = g_type_register_static (EPHY_DIALOG_TYPE,
+ "AppearancePrefs",
+ &our_info, 0);
+ }
+
+ return appearance_prefs_type;
+
+}
+
+static void
+appearance_prefs_class_init (AppearancePrefsClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = appearance_prefs_finalize;
+}
+
+static void
+setup_font_menu (AppearancePrefs *dialog,
+ const char *type,
+ GtkWidget *combo)
+{
+ char *default_font;
+ GList *fonts;
+ EphyEmbedShell *shell;
+ const char *name;
+ char key[255];
+ int pos;
+ GtkWidget *entry = GTK_COMBO(combo)->entry;
+
+ shell = ephy_shell_get_embed_shell (ephy_shell);
+
+ ephy_embed_shell_get_font_list (shell,
+ lang_encode[dialog->priv->language],
+ type, &fonts, &default_font);
+
+ /* Get the default font */
+ sprintf (key, "%s_%s_%s", CONF_RENDERING_FONT, type,
+ lang_encode[dialog->priv->language]);
+ name = eel_gconf_get_string (key);
+ if (name == NULL)
+ {
+ name = default_font;
+ }
+
+ /* put the default font at the top in the list */
+ if (name != NULL)
+ {
+ fonts = g_list_prepend (fonts,
+ (gpointer)g_strdup(name));
+ }
+
+ /* set popdown doesnt like NULL */
+ if (fonts == NULL)
+ {
+ fonts = g_list_alloc ();
+ }
+
+ gtk_combo_set_popdown_strings (GTK_COMBO(combo), fonts);
+
+ /* set the default value */
+ if (name != NULL)
+ {
+ gtk_editable_delete_text (GTK_EDITABLE(entry), 0, -1);
+ gtk_editable_insert_text (GTK_EDITABLE(entry),
+ name, g_utf8_strlen (name, -1),
+ &pos);
+ }
+
+ g_free (default_font);
+
+ /* FIXME free the list */
+}
+
+static void
+save_font_menu (AppearancePrefs *dialog,
+ int type,
+ GtkWidget *entry)
+{
+ char *name;
+ char key[255];
+
+ name = gtk_editable_get_chars
+ (GTK_EDITABLE(entry), 0, -1);
+
+ /* do not save empty fonts */
+ if (!name || *name == '\0')
+ {
+ g_free (name);
+ return;
+ }
+
+ sprintf (key, "%s_%s_%s", CONF_RENDERING_FONT,
+ fonts_types[type],
+ lang_encode[dialog->priv->language]);
+ eel_gconf_set_string (key, name);
+ g_free (name);
+}
+
+static void
+font_entry_changed_cb (GtkWidget *entry, AppearancePrefs *dialog)
+{
+ int type;
+
+ if (dialog->priv->switching) return;
+
+ type = GPOINTER_TO_INT (g_object_get_data (G_OBJECT(entry),
+ "type"));
+ save_font_menu (dialog, type, entry);
+}
+
+static void
+attach_font_signal (AppearancePrefs *dialog, int prop,
+ gpointer type)
+{
+ GtkWidget *combo;
+ GtkWidget *entry;
+
+ combo = ephy_dialog_get_control (EPHY_DIALOG(dialog),
+ prop);
+ entry = GTK_COMBO(combo)->entry;
+ g_object_set_data (G_OBJECT(entry), "type", type);
+ g_signal_connect (entry, "changed",
+ G_CALLBACK(font_entry_changed_cb),
+ dialog);
+}
+
+static void
+attach_fonts_signals (AppearancePrefs *dialog)
+{
+ attach_font_signal (dialog, SERIF_PROP,
+ GINT_TO_POINTER(FONT_TYPE_SERIF));
+ attach_font_signal (dialog, SANSSERIF_PROP,
+ GINT_TO_POINTER(FONT_TYPE_SANSSERIF));
+ attach_font_signal (dialog, MONOSPACE_PROP,
+ GINT_TO_POINTER(FONT_TYPE_MONOSPACE));
+}
+
+static void
+size_spinbutton_changed_cb (GtkWidget *spin, AppearancePrefs *dialog)
+{
+ int type;
+ char key[255];
+
+ if (dialog->priv->switching) return;
+
+ type = GPOINTER_TO_INT(g_object_get_data (G_OBJECT(spin), "type"));
+
+ sprintf (key, "%s_%s",
+ size_prefs[type],
+ lang_encode[dialog->priv->language]);
+ eel_gconf_set_integer (key, gtk_spin_button_get_value (GTK_SPIN_BUTTON (spin)));
+}
+
+static void
+attach_size_controls_signals (AppearancePrefs *dialog)
+{
+ GtkWidget *spin;
+
+ spin = ephy_dialog_get_control (EPHY_DIALOG(dialog),
+ FIXED_SIZE_PROP);
+ g_object_set_data (G_OBJECT(spin), "type",
+ GINT_TO_POINTER(FONT_SIZE_FIXED));
+ g_signal_connect (spin, "value_changed",
+ G_CALLBACK(size_spinbutton_changed_cb),
+ dialog);
+
+ spin = ephy_dialog_get_control (EPHY_DIALOG(dialog),
+ VARIABLE_SIZE_PROP);
+ g_object_set_data (G_OBJECT(spin), "type",
+ GINT_TO_POINTER(FONT_SIZE_VAR));
+ g_signal_connect (spin, "value_changed",
+ G_CALLBACK(size_spinbutton_changed_cb),
+ dialog);
+
+ spin = ephy_dialog_get_control (EPHY_DIALOG(dialog),
+ MIN_SIZE_PROP);
+ g_object_set_data (G_OBJECT(spin), "type",
+ GINT_TO_POINTER(FONT_SIZE_MIN));
+ g_signal_connect (spin, "value_changed",
+ G_CALLBACK(size_spinbutton_changed_cb),
+ dialog);
+}
+
+static void
+setup_size_control (AppearancePrefs *dialog,
+ const char *pref,
+ int default_size,
+ GtkWidget *spin)
+{
+ char key[255];
+ int size;
+
+ sprintf (key, "%s_%s", pref,
+ lang_encode[dialog->priv->language]);
+ size = eel_gconf_get_integer (key);
+
+ if (size == 0) size = default_size;
+
+ gtk_spin_button_set_value (GTK_SPIN_BUTTON(spin), size);
+}
+
+static void
+setup_size_controls (AppearancePrefs *dialog)
+{
+ GtkWidget *spin;
+
+ spin = ephy_dialog_get_control (EPHY_DIALOG(dialog),
+ FIXED_SIZE_PROP);
+ setup_size_control (dialog, CONF_RENDERING_FONT_FIXED_SIZE, 12, spin);
+
+ spin = ephy_dialog_get_control (EPHY_DIALOG(dialog),
+ VARIABLE_SIZE_PROP);
+ setup_size_control (dialog, CONF_RENDERING_FONT_VAR_SIZE, 16, spin);
+
+ spin = ephy_dialog_get_control (EPHY_DIALOG(dialog),
+ MIN_SIZE_PROP);
+ setup_size_control (dialog, CONF_RENDERING_FONT_MIN_SIZE, 0, spin);
+}
+
+static void
+setup_fonts (AppearancePrefs *dialog)
+{
+ GtkWidget *combo;
+
+ dialog->priv->switching = TRUE;
+
+ combo = ephy_dialog_get_control (EPHY_DIALOG(dialog),
+ SERIF_PROP);
+ setup_font_menu (dialog, "serif", combo);
+
+ combo = ephy_dialog_get_control (EPHY_DIALOG(dialog),
+ SANSSERIF_PROP);
+ setup_font_menu (dialog, "sans-serif", combo);
+
+ combo = ephy_dialog_get_control (EPHY_DIALOG(dialog),
+ MONOSPACE_PROP);
+ setup_font_menu (dialog, "monospace", combo);
+
+ dialog->priv->switching = FALSE;
+}
+
+static void
+appearance_prefs_init (AppearancePrefs *dialog)
+{
+ dialog->priv = g_new0 (AppearancePrefsPrivate, 1);
+ dialog->priv->switching = FALSE;
+
+ ephy_dialog_construct (EPHY_DIALOG(dialog),
+ properties,
+ "prefs-dialog.glade",
+ "appearance_page_box");
+
+ setup_fonts (dialog);
+ setup_size_controls (dialog);
+ attach_fonts_signals (dialog);
+ attach_size_controls_signals (dialog);
+}
+
+static void
+appearance_prefs_finalize (GObject *object)
+{
+ AppearancePrefs *dialog;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (IS_appearance_PREFS (object));
+
+ dialog = appearance_PREFS (object);
+
+ g_return_if_fail (dialog->priv != NULL);
+
+ g_free (dialog->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+EphyDialog *
+appearance_prefs_new (void)
+{
+ AppearancePrefs *dialog;
+
+ dialog = appearance_PREFS (g_object_new (appearance_PREFS_TYPE,
+ NULL));
+
+ return EPHY_DIALOG(dialog);
+}
+
+void
+fonts_language_optionmenu_changed_cb (GtkWidget *optionmenu,
+ EphyDialog *dialog)
+{
+ int i;
+
+ i = gtk_option_menu_get_history
+ (GTK_OPTION_MENU (optionmenu));
+
+ appearance_PREFS(dialog)->priv->language = i;
+
+ setup_fonts (appearance_PREFS(dialog));
+ setup_size_controls (appearance_PREFS(dialog));
+}
diff --git a/src/appearance-prefs.h b/src/appearance-prefs.h
new file mode 100644
index 000000000..17067b7e9
--- /dev/null
+++ b/src/appearance-prefs.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef APPEARANCE_PREFS_H
+#define APPEARANCE_PREFS_H
+
+#include "ephy-dialog.h"
+
+#include <glib-object.h>
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef struct AppearancePrefs AppearancePrefs;
+typedef struct AppearancePrefsClass AppearancePrefsClass;
+
+#define appearance_PREFS_TYPE (appearance_prefs_get_type ())
+#define appearance_PREFS(obj) (GTK_CHECK_CAST ((obj), appearance_PREFS_TYPE, AppearancePrefs))
+#define appearance_PREFS_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), appearance_PREFS, AppearancePrefsClass))
+#define IS_appearance_PREFS(obj) (GTK_CHECK_TYPE ((obj), appearance_PREFS_TYPE))
+#define IS_appearance_PREFS_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), appearance_PREFS))
+
+typedef struct AppearancePrefsPrivate AppearancePrefsPrivate;
+
+struct AppearancePrefs
+{
+ EphyDialog parent;
+ AppearancePrefsPrivate *priv;
+};
+
+struct AppearancePrefsClass
+{
+ EphyDialogClass parent_class;
+};
+
+GType appearance_prefs_get_type (void);
+
+EphyDialog *appearance_prefs_new (void);
+
+G_END_DECLS
+
+#endif
+
diff --git a/src/bookmarks/.cvsignore b/src/bookmarks/.cvsignore
new file mode 100644
index 000000000..6e5ca7ed4
--- /dev/null
+++ b/src/bookmarks/.cvsignore
@@ -0,0 +1,6 @@
+Makefile
+Makefile.in
+.deps
+.libs
+*.lo
+*.la
diff --git a/src/bookmarks/Makefile.am b/src/bookmarks/Makefile.am
new file mode 100644
index 000000000..4dd24c1bd
--- /dev/null
+++ b/src/bookmarks/Makefile.am
@@ -0,0 +1,31 @@
+INCLUDES = \
+ -I$(top_srcdir)/lib \
+ -I$(top_srcdir)/src \
+ -I$(top_srcdir)/embed \
+ -I$(top_srcdir)/lib/widgets \
+ $(WARN_CFLAGS) \
+ $(EPIPHANY_DEPENDENCY_CFLAGS) \
+ -DSHARE_DIR=\"$(pkgdatadir)\" \
+ -DDATADIR=\""$(datadir)"\" \
+ -DGNOMELOCALEDIR=\""$(datadir)/locale"\" \
+ -DG_DISABLE_DEPRECATED \
+ -DGDK_DISABLE_DEPRECATED \
+ -DGTK_DISABLE_DEPRECATED \
+ -DGDK_PIXBUF_DISABLE_DEPRECATED \
+ -DGNOME_DISABLE_DEPRECATED
+
+noinst_LTLIBRARIES = libephybookmarks.la
+
+libephybookmarks_la_SOURCES = \
+ ephy-bookmarks.c \
+ ephy-bookmarks.h \
+ ephy-tree-model-node.c \
+ ephy-tree-model-node.h \
+ ephy-node-view.c \
+ ephy-node-view.h \
+ ephy-bookmarks-editor.c \
+ ephy-bookmarks-editor.h \
+ ephy-keywords-entry.c \
+ ephy-keywords-entry.h \
+ ephy-new-bookmark.c \
+ ephy-new-bookmark.h
diff --git a/src/bookmarks/ephy-bookmarks-editor.c b/src/bookmarks/ephy-bookmarks-editor.c
new file mode 100644
index 000000000..2888950df
--- /dev/null
+++ b/src/bookmarks/ephy-bookmarks-editor.c
@@ -0,0 +1,534 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen <jorn@nl.linux.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include <gtk/gtktable.h>
+#include <gtk/gtklabel.h>
+#include <gtk/gtkentry.h>
+#include <gtk/gtkstock.h>
+#include <gtk/gtkhbox.h>
+#include <gtk/gtkvbox.h>
+#include <libgnome/gnome-i18n.h>
+#include <string.h>
+
+#include "ephy-bookmarks-editor.h"
+#include "ephy-node-view.h"
+#include "ephy-window.h"
+#include "ephy-keywords-entry.h"
+#include "ephy-dnd.h"
+
+//#define DEBUG_MSG(x) g_print x
+#define DEBUG_MSG(x)
+
+static void ephy_bookmarks_editor_class_init (EphyBookmarksEditorClass *klass);
+static void ephy_bookmarks_editor_init (EphyBookmarksEditor *editor);
+static void ephy_bookmarks_editor_finalize (GObject *object);
+static void ephy_bookmarks_editor_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void ephy_bookmarks_editor_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+struct EphyBookmarksEditorPrivate
+{
+ EphyBookmarks *bookmarks;
+ EphyNodeView *bm_view;
+ EphyNodeView *key_view;
+ EphyNodeFilter *bookmarks_filter;
+ GtkWidget *title_entry;
+ GtkWidget *keywords_entry;
+ GtkWidget *search_entry;
+};
+
+enum
+{
+ PROP_0,
+ PROP_BOOKMARKS
+};
+
+enum
+{
+ RESPONSE_REMOVE
+};
+
+static GObjectClass *parent_class = NULL;
+
+GType
+ephy_bookmarks_editor_get_type (void)
+{
+ static GType ephy_bookmarks_editor_type = 0;
+
+ if (ephy_bookmarks_editor_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (EphyBookmarksEditorClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) ephy_bookmarks_editor_class_init,
+ NULL,
+ NULL,
+ sizeof (EphyBookmarksEditor),
+ 0,
+ (GInstanceInitFunc) ephy_bookmarks_editor_init
+ };
+
+ ephy_bookmarks_editor_type = g_type_register_static (GTK_TYPE_DIALOG,
+ "EphyBookmarksEditor",
+ &our_info, 0);
+ }
+
+ return ephy_bookmarks_editor_type;
+}
+
+static void
+ephy_bookmarks_editor_class_init (EphyBookmarksEditorClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = ephy_bookmarks_editor_finalize;
+
+ object_class->set_property = ephy_bookmarks_editor_set_property;
+ object_class->get_property = ephy_bookmarks_editor_get_property;
+
+ g_object_class_install_property (object_class,
+ PROP_BOOKMARKS,
+ g_param_spec_object ("bookmarks",
+ "Bookmarks set",
+ "Bookmarks set",
+ EPHY_BOOKMARKS_TYPE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+ephy_bookmarks_editor_finalize (GObject *object)
+{
+ EphyBookmarksEditor *editor;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (EPHY_IS_BOOKMARKS_EDITOR (object));
+
+ editor = EPHY_BOOKMARKS_EDITOR (object);
+
+ g_return_if_fail (editor->priv != NULL);
+
+ g_object_unref (G_OBJECT (editor->priv->bookmarks_filter));
+
+ g_free (editor->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+ephy_bookmarks_editor_node_selected_cb (GtkWidget *view,
+ EphyNode *node,
+ EphyBookmarksEditor *editor)
+{
+ const char *title;
+ const char *keywords;
+
+ if (node != NULL)
+ {
+ g_assert (EPHY_IS_NODE (node));
+
+ title = ephy_node_get_property_string
+ (node, EPHY_NODE_BMK_PROP_TITLE);
+ keywords = ephy_node_get_property_string
+ (node, EPHY_NODE_BMK_PROP_KEYWORDS);
+ gtk_entry_set_text (GTK_ENTRY (editor->priv->title_entry),
+ title ? g_strdup (title) : "");
+ gtk_entry_set_text (GTK_ENTRY (editor->priv->keywords_entry),
+ keywords ? g_strdup (keywords) : "");
+ gtk_widget_set_sensitive (GTK_WIDGET (editor->priv->title_entry), TRUE);
+ gtk_widget_set_sensitive (GTK_WIDGET (editor->priv->keywords_entry), TRUE);
+ }
+ else
+ {
+ gtk_entry_set_text (GTK_ENTRY (editor->priv->title_entry), "");
+ gtk_entry_set_text (GTK_ENTRY (editor->priv->keywords_entry), "");
+ gtk_widget_set_sensitive (GTK_WIDGET (editor->priv->title_entry), FALSE);
+ gtk_widget_set_sensitive (GTK_WIDGET (editor->priv->keywords_entry), FALSE);
+ }
+}
+
+static void
+ephy_bookmarks_editor_node_activated_cb (GtkWidget *view,
+ EphyNode *node,
+ EphyBookmarksEditor *editor)
+{
+ const char *location;
+ GtkWindow *window;
+
+ g_return_if_fail (EPHY_IS_NODE (node));
+ location = ephy_node_get_property_string
+ (node, EPHY_NODE_BMK_PROP_LOCATION);
+ g_return_if_fail (location != NULL);
+
+ window = gtk_window_get_transient_for (GTK_WINDOW (editor));
+ g_return_if_fail (IS_EPHY_WINDOW (window));
+ ephy_window_load_url (EPHY_WINDOW (window), location);
+}
+
+static void
+ephy_bookmarks_editor_response_cb (GtkDialog *dialog,
+ int response_id,
+ EphyBookmarksEditor *editor)
+{
+ switch (response_id)
+ {
+ case GTK_RESPONSE_CLOSE:
+ gtk_widget_destroy (GTK_WIDGET (dialog));
+ break;
+ case RESPONSE_REMOVE:
+ ephy_node_view_remove (editor->priv->bm_view);
+ break;
+ }
+}
+
+static void
+update_prop_from_entry (EphyBookmarksEditor *editor,
+ GtkWidget *entry,
+ guint id)
+{
+ GList *selection;
+ GValue value = { 0, };
+
+ selection = ephy_node_view_get_selection (editor->priv->bm_view);
+ if (selection)
+ {
+ EphyNode *bm = EPHY_NODE (selection->data);
+ char *tmp;
+
+ tmp = gtk_editable_get_chars
+ (GTK_EDITABLE (entry), 0, -1);
+ g_value_init (&value, G_TYPE_STRING);
+ g_value_set_string (&value, tmp);
+ ephy_node_set_property (bm, id, &value);
+ g_value_unset (&value);
+ g_free (tmp);
+ }
+ g_list_free (selection);
+}
+
+static void
+title_entry_changed_cb (GtkWidget *entry, EphyBookmarksEditor *editor)
+{
+ update_prop_from_entry (editor, editor->priv->title_entry,
+ EPHY_NODE_BMK_PROP_TITLE);
+}
+
+static void
+keywords_changed_cb (GtkWidget *entry,
+ EphyBookmarksEditor *editor)
+{
+ EphyNode *node;
+ GList *selection;
+ char *keywords;
+
+ selection = ephy_node_view_get_selection (editor->priv->bm_view);
+ if (selection == NULL) return;
+ node = EPHY_NODE (selection->data);
+ g_list_free (selection);
+
+ keywords = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1);
+ ephy_bookmarks_update_keywords (editor->priv->bookmarks,
+ keywords, node);
+ g_free (keywords);
+
+ update_prop_from_entry (editor, editor->priv->keywords_entry,
+ EPHY_NODE_BMK_PROP_KEYWORDS);
+}
+
+static GtkWidget *
+build_editing_table (EphyBookmarksEditor *editor)
+{
+ GtkWidget *table, *label, *entry;
+
+ table = gtk_table_new (2, 2, FALSE);
+ gtk_table_set_row_spacings (GTK_TABLE (table), 6);
+ gtk_table_set_col_spacings (GTK_TABLE (table), 6);
+ gtk_widget_show (table);
+
+ label = gtk_label_new (NULL);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+ gtk_label_set_markup (GTK_LABEL (label), _("<b>Title:</b>"));
+ gtk_widget_show (label);
+ entry = gtk_entry_new ();
+ editor->priv->title_entry = entry;
+ gtk_widget_set_sensitive (GTK_WIDGET (entry), FALSE);
+ gtk_widget_show (entry);
+ gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, GTK_FILL, 0, 0, 0);
+ gtk_table_attach_defaults (GTK_TABLE (table), entry, 1, 2, 0, 1);
+ g_signal_connect (G_OBJECT (entry), "changed",
+ G_CALLBACK (title_entry_changed_cb),
+ editor);
+
+ label = gtk_label_new (NULL);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+ gtk_label_set_markup (GTK_LABEL (label), _("<b>Keywords:</b>"));
+ gtk_widget_show (label);
+ entry = ephy_keywords_entry_new ();
+ ephy_keywords_entry_set_bookmarks (EPHY_KEYWORDS_ENTRY (entry),
+ editor->priv->bookmarks);
+ editor->priv->keywords_entry = entry;
+ gtk_widget_set_sensitive (GTK_WIDGET (entry), FALSE);
+ gtk_widget_show (entry);
+ gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, GTK_FILL, 0, 0, 0);
+ gtk_table_attach_defaults (GTK_TABLE (table), entry, 1, 2, 1, 2);
+ g_signal_connect (G_OBJECT (entry), "keywords_changed",
+ G_CALLBACK (keywords_changed_cb),
+ editor);
+
+ return table;
+}
+
+static void
+bookmarks_filter (EphyBookmarksEditor *editor,
+ EphyNode *keyword)
+{
+ ephy_node_filter_empty (editor->priv->bookmarks_filter);
+ ephy_node_filter_add_expression (editor->priv->bookmarks_filter,
+ ephy_node_filter_expression_new (EPHY_NODE_FILTER_EXPRESSION_HAS_PARENT,
+ keyword),
+ 0);
+ ephy_node_filter_done_changing (editor->priv->bookmarks_filter);
+}
+
+static void
+keyword_node_selected_cb (EphyNodeView *view,
+ EphyNode *node,
+ EphyBookmarksEditor *editor)
+{
+ if (node == NULL)
+ {
+ ephy_node_view_select_node
+ (editor->priv->key_view,
+ ephy_bookmarks_get_bookmarks
+ (editor->priv->bookmarks));
+ }
+ else
+ {
+ bookmarks_filter (editor, node);
+ }
+}
+
+static void
+search_entry_changed_cb (GtkWidget *entry, EphyBookmarksEditor *editor)
+{
+ char *search_text;
+
+ search_text = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1);
+
+ GDK_THREADS_ENTER ();
+
+ ephy_node_filter_empty (editor->priv->bookmarks_filter);
+ ephy_node_filter_add_expression (editor->priv->bookmarks_filter,
+ ephy_node_filter_expression_new (EPHY_NODE_FILTER_EXPRESSION_STRING_PROP_CONTAINS,
+ EPHY_NODE_BMK_PROP_TITLE,
+ search_text),
+ 0);
+ ephy_node_filter_add_expression (editor->priv->bookmarks_filter,
+ ephy_node_filter_expression_new (EPHY_NODE_FILTER_EXPRESSION_STRING_PROP_CONTAINS,
+ EPHY_NODE_BMK_PROP_KEYWORDS,
+ search_text),
+ 0);
+ ephy_node_filter_done_changing (editor->priv->bookmarks_filter);
+
+ GDK_THREADS_LEAVE ();
+
+ g_free (search_text);
+}
+
+static GtkWidget *
+build_search_box (EphyBookmarksEditor *editor)
+{
+ GtkWidget *box;
+ GtkWidget *label;
+ GtkWidget *entry;
+
+ box = gtk_hbox_new (FALSE, 6);
+ gtk_widget_show (box);
+
+ label = gtk_label_new (NULL);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+ gtk_label_set_markup (GTK_LABEL (label), _("<b>Search:</b>"));
+ gtk_widget_show (label);
+ gtk_box_pack_start (GTK_BOX (box),
+ label, FALSE, TRUE, 0);
+
+ entry = gtk_entry_new ();
+ editor->priv->search_entry = entry;
+ gtk_widget_show (entry);
+ gtk_box_pack_start (GTK_BOX (box),
+ entry, TRUE, TRUE, 0);
+ g_signal_connect (G_OBJECT (entry), "changed",
+ G_CALLBACK (search_entry_changed_cb),
+ editor);
+ return box;
+}
+
+static void
+ephy_bookmarks_editor_construct (EphyBookmarksEditor *editor)
+{
+ GtkWidget *hbox, *vbox;
+ EphyNodeView *bm_view, *key_view;
+ EphyNode *node;
+
+ gtk_dialog_set_has_separator (GTK_DIALOG (editor), FALSE);
+ gtk_container_set_border_width (GTK_CONTAINER (editor), 6);
+ gtk_widget_set_size_request (GTK_WIDGET (editor), 500, 400);
+ g_signal_connect (G_OBJECT (editor),
+ "response",
+ G_CALLBACK (ephy_bookmarks_editor_response_cb),
+ editor);
+
+ hbox = gtk_hbox_new (FALSE, 6);
+ gtk_container_set_border_width (GTK_CONTAINER (hbox), 6);
+ gtk_box_pack_start (GTK_BOX (GTK_DIALOG (editor)->vbox),
+ hbox, TRUE, TRUE, 0);
+ gtk_widget_show (hbox);
+
+ g_assert (editor->priv->bookmarks);
+
+ node = ephy_bookmarks_get_keywords (editor->priv->bookmarks);
+ key_view = ephy_node_view_new (node, NULL);
+ ephy_node_view_set_browse_mode (key_view);
+ ephy_node_view_add_column (key_view, _("Keywords"),
+ EPHY_TREE_MODEL_NODE_COL_KEYWORD, FALSE);
+ gtk_box_pack_start (GTK_BOX (hbox), GTK_WIDGET (key_view), FALSE, TRUE, 0);
+ gtk_widget_set_size_request (GTK_WIDGET (key_view), 120, -1);
+ gtk_widget_show (GTK_WIDGET (key_view));
+ editor->priv->key_view = key_view;
+ g_signal_connect (G_OBJECT (key_view),
+ "node_selected",
+ G_CALLBACK (keyword_node_selected_cb),
+ editor);
+
+ vbox = gtk_vbox_new (FALSE, 6);
+ gtk_box_pack_start (GTK_BOX (hbox),
+ vbox, TRUE, TRUE, 0);
+ gtk_widget_show (vbox);
+
+ gtk_box_pack_start (GTK_BOX (vbox),
+ build_search_box (editor),
+ FALSE, FALSE, 0);
+
+ node = ephy_bookmarks_get_bookmarks (editor->priv->bookmarks);
+ editor->priv->bookmarks_filter = ephy_node_filter_new ();
+ bm_view = ephy_node_view_new (node, editor->priv->bookmarks_filter);
+ ephy_node_view_enable_drag_source (bm_view);
+ ephy_node_view_add_column (bm_view, _("Title"),
+ EPHY_TREE_MODEL_NODE_COL_BOOKMARK, TRUE);
+ ephy_node_view_add_column (bm_view, _("Location"),
+ EPHY_TREE_MODEL_NODE_COL_LOCATION, TRUE);
+ gtk_box_pack_start (GTK_BOX (vbox), GTK_WIDGET (bm_view), TRUE, TRUE, 0);
+ gtk_widget_show (GTK_WIDGET (bm_view));
+ editor->priv->bm_view = bm_view;
+ g_signal_connect (G_OBJECT (bm_view),
+ "node_activated",
+ G_CALLBACK (ephy_bookmarks_editor_node_activated_cb),
+ editor);
+ g_signal_connect (G_OBJECT (bm_view),
+ "node_selected",
+ G_CALLBACK (ephy_bookmarks_editor_node_selected_cb),
+ editor);
+
+ gtk_box_pack_start (GTK_BOX (vbox),
+ build_editing_table (editor),
+ FALSE, FALSE, 0);
+
+ gtk_dialog_add_button (GTK_DIALOG (editor),
+ GTK_STOCK_REMOVE,
+ RESPONSE_REMOVE);
+ gtk_dialog_add_button (GTK_DIALOG (editor),
+ GTK_STOCK_CLOSE,
+ GTK_RESPONSE_CLOSE);
+ gtk_dialog_set_default_response (GTK_DIALOG (editor), GTK_RESPONSE_CLOSE);
+}
+
+GtkWidget *
+ephy_bookmarks_editor_new (EphyBookmarks *bookmarks,
+ GtkWindow *parent)
+{
+ EphyBookmarksEditor *editor;
+
+ g_assert (bookmarks != NULL);
+
+ editor = EPHY_BOOKMARKS_EDITOR (g_object_new
+ (EPHY_TYPE_BOOKMARKS_EDITOR,
+ "bookmarks", bookmarks,
+ NULL));
+
+ if (parent)
+ {
+ gtk_window_set_transient_for (GTK_WINDOW (editor), parent);
+ }
+
+ ephy_bookmarks_editor_construct (editor);
+
+ return GTK_WIDGET (editor);
+}
+
+static void
+ephy_bookmarks_editor_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EphyBookmarksEditor *editor = EPHY_BOOKMARKS_EDITOR (object);
+
+ switch (prop_id)
+ {
+ case PROP_BOOKMARKS:
+ editor->priv->bookmarks = g_value_get_object (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+ephy_bookmarks_editor_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ EphyBookmarksEditor *editor = EPHY_BOOKMARKS_EDITOR (object);
+
+ switch (prop_id)
+ {
+ case PROP_BOOKMARKS:
+ g_value_set_object (value, editor->priv->bookmarks);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+ephy_bookmarks_editor_init (EphyBookmarksEditor *editor)
+{
+ editor->priv = g_new0 (EphyBookmarksEditorPrivate, 1);
+}
diff --git a/src/bookmarks/ephy-bookmarks-editor.h b/src/bookmarks/ephy-bookmarks-editor.h
new file mode 100644
index 000000000..f79dfa673
--- /dev/null
+++ b/src/bookmarks/ephy-bookmarks-editor.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen <jorn@nl.linux.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Id$
+ */
+
+#ifndef EPHY_BOOKMARKS_EDITOR_H
+#define EPHY_BOOKMARKS_EDITOR_H
+
+#include <gtk/gtkdialog.h>
+
+#include "ephy-node-view.h"
+#include "ephy-bookmarks.h"
+
+G_BEGIN_DECLS
+
+#define EPHY_TYPE_BOOKMARKS_EDITOR (ephy_bookmarks_editor_get_type ())
+#define EPHY_BOOKMARKS_EDITOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EPHY_TYPE_BOOKMARKS_EDITOR, EphyBookmarksEditor))
+#define EPHY_BOOKMARKS_EDITOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EPHY_TYPE_BOOKMARKS_EDITOR, EphyBookmarksEditorClass))
+#define EPHY_IS_BOOKMARKS_EDITOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EPHY_TYPE_BOOKMARKS_EDITOR))
+#define EPHY_IS_BOOKMARKS_EDITOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EPHY_TYPE_BOOKMARKS_EDITOR))
+#define EPHY_BOOKMARKS_EDITOR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EPHY_TYPE_BOOKMARKS_EDITOR, EphyBookmarksEditorClass))
+
+typedef struct EphyBookmarksEditorPrivate EphyBookmarksEditorPrivate;
+
+typedef struct
+{
+ GtkDialog parent;
+
+ EphyBookmarksEditorPrivate *priv;
+} EphyBookmarksEditor;
+
+typedef struct
+{
+ GtkDialogClass parent;
+} EphyBookmarksEditorClass;
+
+GType ephy_bookmarks_editor_get_type (void);
+
+GtkWidget *ephy_bookmarks_editor_new (EphyBookmarks *bookmarks,
+ GtkWindow *parent);
+
+G_END_DECLS
+
+#endif /* EPHY_BOOKMARKS_EDITOR_H */
diff --git a/src/bookmarks/ephy-bookmarks.c b/src/bookmarks/ephy-bookmarks.c
new file mode 100644
index 000000000..e27a30496
--- /dev/null
+++ b/src/bookmarks/ephy-bookmarks.c
@@ -0,0 +1,988 @@
+/*
+ * Copyright (C) 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "ephy-bookmarks.h"
+#include "ephy-file-helpers.h"
+#include "ephy-shell.h"
+#include "ephy-history.h"
+
+#include <string.h>
+#include <libgnome/gnome-i18n.h>
+
+//#define DEBUG_MSG(x) g_print x
+#define DEBUG_MSG(x)
+
+#define EPHY_BOOKMARKS_XML_VERSION "0.1"
+
+#define MAX_FAVORITES_NUM 10
+
+struct EphyBookmarksPrivate
+{
+ char *xml_file;
+ EphyNode *bookmarks;
+ EphyNode *keywords;
+ EphyNode *favorites;
+ EphyNode *lower_fav;
+ double lower_score;
+ GHashTable *bookmarks_hash;
+ GStaticRWLock *bookmarks_hash_lock;
+ GHashTable *favorites_hash;
+ GStaticRWLock *favorites_hash_lock;
+ GHashTable *keywords_hash;
+ GStaticRWLock *keywords_hash_lock;
+};
+
+static void
+ephy_bookmarks_class_init (EphyBookmarksClass *klass);
+static void
+ephy_bookmarks_init (EphyBookmarks *tab);
+static void
+ephy_bookmarks_finalize (GObject *object);
+static void
+ephy_bookmarks_autocompletion_source_init (EphyAutocompletionSourceIface *iface);
+
+static GObjectClass *parent_class = NULL;
+
+GType
+ephy_bookmarks_get_type (void)
+{
+ static GType ephy_bookmarks_type = 0;
+
+ if (ephy_bookmarks_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (EphyBookmarksClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) ephy_bookmarks_class_init,
+ NULL,
+ NULL, /* class_data */
+ sizeof (EphyBookmarks),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) ephy_bookmarks_init
+ };
+
+ static const GInterfaceInfo autocompletion_source_info =
+ {
+ (GInterfaceInitFunc) ephy_bookmarks_autocompletion_source_init,
+ NULL,
+ NULL
+ };
+
+ ephy_bookmarks_type = g_type_register_static (G_TYPE_OBJECT,
+ "EphyBookmarks",
+ &our_info, 0);
+
+ g_type_add_interface_static (ephy_bookmarks_type,
+ EPHY_TYPE_AUTOCOMPLETION_SOURCE,
+ &autocompletion_source_info);
+ }
+
+ return ephy_bookmarks_type;
+}
+
+static void
+ephy_bookmarks_autocompletion_source_set_basic_key (EphyAutocompletionSource *source,
+ const gchar *basic_key)
+{
+ /* nothing to do here */
+}
+
+static void
+ephy_bookmarks_autocompletion_source_foreach (EphyAutocompletionSource *source,
+ const gchar *current_text,
+ EphyAutocompletionSourceForeachFunc func,
+ gpointer data)
+{
+ GPtrArray *children;
+ int i;
+ EphyBookmarks *eb = EPHY_BOOKMARKS (source);
+
+ children = ephy_node_get_children (eb->priv->bookmarks);
+ for (i = 0; i < children->len; i++)
+ {
+ EphyNode *kid;
+ const char *url, *smart_url, *title, *keywords;
+ char *item;
+
+ kid = g_ptr_array_index (children, i);
+ url = ephy_node_get_property_string
+ (kid, EPHY_NODE_BMK_PROP_LOCATION);
+ smart_url = ephy_node_get_property_string
+ (kid, EPHY_NODE_BMK_PROP_SMART_LOCATION);
+ title = ephy_node_get_property_string
+ (kid, EPHY_NODE_BMK_PROP_TITLE);
+ keywords = ephy_node_get_property_string
+ (kid, EPHY_NODE_BMK_PROP_KEYWORDS);
+ item = g_strconcat (title, keywords, NULL);
+
+ if (smart_url == NULL ||
+ g_utf8_strlen (smart_url, -1) == 0)
+ {
+ smart_url = NULL;
+ }
+
+ func (source,
+ smart_url ? NULL : item,
+ title,
+ smart_url ? smart_url : url,
+ (smart_url != NULL),
+ TRUE, 0, data);
+
+ g_free (item);
+ }
+ ephy_node_thaw (eb->priv->bookmarks);
+}
+
+static void
+ephy_bookmarks_emit_data_changed (EphyBookmarks *eb)
+{
+ g_signal_emit_by_name (eb, "data-changed");
+}
+
+static void
+ephy_bookmarks_autocompletion_source_init (EphyAutocompletionSourceIface *iface)
+{
+ iface->foreach = ephy_bookmarks_autocompletion_source_foreach;
+ iface->set_basic_key = ephy_bookmarks_autocompletion_source_set_basic_key;
+}
+
+static void
+ephy_bookmarks_class_init (EphyBookmarksClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = ephy_bookmarks_finalize;
+}
+
+static gboolean
+ephy_bookmarks_clean_empty_keywords (EphyBookmarks *eb)
+{
+ GPtrArray *children;
+ int i;
+
+ children = ephy_node_get_children (eb->priv->keywords);
+ ephy_node_thaw (eb->priv->keywords);
+ for (i = 0; i < children->len; i++)
+ {
+ EphyNode *kid;
+
+ kid = g_ptr_array_index (children, i);
+
+ if (ephy_node_get_n_children (kid) == 0)
+ {
+ DEBUG_MSG (("Remove empty keyword: %s\n",
+ ephy_node_get_property_string (kid,
+ EPHY_NODE_KEYWORD_PROP_NAME)));
+ ephy_node_unref (kid);
+ }
+ }
+
+ return FALSE;
+}
+
+static void
+ephy_bookmarks_load (EphyBookmarks *eb)
+{
+ xmlDocPtr doc;
+ xmlNodePtr root, child;
+ char *tmp;
+
+ if (g_file_test (eb->priv->xml_file, G_FILE_TEST_EXISTS) == FALSE)
+ return;
+
+ doc = xmlParseFile (eb->priv->xml_file);
+ g_assert (doc != NULL);
+
+ root = xmlDocGetRootElement (doc);
+
+ tmp = xmlGetProp (root, "version");
+ g_assert (tmp != NULL && strcmp (tmp, EPHY_BOOKMARKS_XML_VERSION) == 0);
+ g_free (tmp);
+
+ for (child = root->children; child != NULL; child = child->next)
+ {
+ EphyNode *node;
+
+ node = ephy_node_new_from_xml (child);
+ }
+
+ xmlFreeDoc (doc);
+}
+
+static void
+ephy_bookmarks_save (EphyBookmarks *eb)
+{
+ xmlDocPtr doc;
+ xmlNodePtr root;
+ GPtrArray *children;
+ int i;
+
+ DEBUG_MSG (("Saving bookmarks\n"));
+
+ /* save nodes to xml */
+ xmlIndentTreeOutput = TRUE;
+ doc = xmlNewDoc ("1.0");
+
+ root = xmlNewDocNode (doc, NULL, "ephy_bookmarks", NULL);
+ xmlSetProp (root, "version", EPHY_BOOKMARKS_XML_VERSION);
+ xmlDocSetRootElement (doc, root);
+
+ children = ephy_node_get_children (eb->priv->keywords);
+ for (i = 0; i < children->len; i++)
+ {
+ EphyNode *kid;
+
+ kid = g_ptr_array_index (children, i);
+
+ if (kid != eb->priv->bookmarks)
+ {
+ ephy_node_save_to_xml (kid, root);
+ }
+ }
+ ephy_node_thaw (eb->priv->keywords);
+
+ children = ephy_node_get_children (eb->priv->bookmarks);
+ for (i = 0; i < children->len; i++)
+ {
+ EphyNode *kid;
+
+ kid = g_ptr_array_index (children, i);
+
+ ephy_node_save_to_xml (kid, root);
+ }
+ ephy_node_thaw (eb->priv->bookmarks);
+
+ xmlSaveFormatFile (eb->priv->xml_file, doc, 1);
+}
+
+static double
+get_history_item_score (EphyHistory *eh, const char *page)
+{
+ return ephy_history_get_page_visits (eh, page);
+}
+
+static EphyNode *
+compute_lower_fav (EphyNode *favorites, double *score)
+{
+ GPtrArray *children;
+ int i;
+ EphyEmbedShell *embed_shell;
+ EphyHistory *history;
+ EphyNode *result = NULL;
+
+ embed_shell = ephy_shell_get_embed_shell (ephy_shell);
+ history = ephy_embed_shell_get_global_history (embed_shell);
+
+ *score = DBL_MAX;
+ children = ephy_node_get_children (favorites);
+ for (i = 0; i < children->len; i++)
+ {
+ const char *url;
+ EphyNode *child;
+ double item_score;
+
+ child = g_ptr_array_index (children, i);
+ url = ephy_node_get_property_string
+ (child, EPHY_NODE_BMK_PROP_LOCATION);
+ item_score = get_history_item_score (history, url);
+ if (*score > item_score)
+ {
+ *score = item_score;
+ result = child;
+ }
+ }
+ ephy_node_thaw (favorites);
+
+ if (result == NULL) *score = 0;
+
+ return result;
+}
+
+static void
+ephy_bookmarks_update_favorites (EphyBookmarks *eb)
+{
+ eb->priv->lower_fav = compute_lower_fav (eb->priv->favorites,
+ &eb->priv->lower_score);
+}
+
+static gboolean
+add_to_favorites (EphyBookmarks *eb, EphyNode *node, EphyHistory *eh)
+{
+ const char *url;
+ EphyNode *fav_node;
+ gboolean full_menu;
+ double score;
+
+ url = ephy_node_get_property_string (node, EPHY_NODE_BMK_PROP_LOCATION);
+ g_static_rw_lock_reader_lock (eb->priv->favorites_hash_lock);
+ fav_node = g_hash_table_lookup (eb->priv->favorites_hash, url);
+ g_static_rw_lock_reader_unlock (eb->priv->favorites_hash_lock);
+ if (fav_node) return FALSE;
+
+ score = get_history_item_score (eh, url);
+ full_menu = ephy_node_get_n_children (eb->priv->favorites)
+ > MAX_FAVORITES_NUM;
+ if (full_menu && score < eb->priv->lower_score) return FALSE;
+
+ if (eb->priv->lower_fav && full_menu)
+ {
+ ephy_node_remove_child (eb->priv->favorites,
+ eb->priv->lower_fav);
+ }
+
+ ephy_node_add_child (eb->priv->favorites, node);
+ ephy_bookmarks_update_favorites (eb);
+
+ return TRUE;
+}
+
+static void
+update_favorites_menus ()
+{
+ Session *session;
+ GList *l;
+
+ session = ephy_shell_get_session (ephy_shell);
+ l = session_get_windows (session);
+
+ for (; l != NULL; l = l->next)
+ {
+ EphyWindow *window = EPHY_WINDOW (l->data);
+
+ ephy_window_update_control (window, FavoritesControl);
+ }
+}
+
+static void
+history_site_visited_cb (EphyHistory *gh, const char *url, EphyBookmarks *eb)
+{
+ EphyNode *node;
+
+ g_static_rw_lock_reader_lock (eb->priv->bookmarks_hash_lock);
+ node = g_hash_table_lookup (eb->priv->bookmarks_hash, url);
+ g_static_rw_lock_reader_unlock (eb->priv->bookmarks_hash_lock);
+ if (!node) return;
+
+ if (add_to_favorites (eb, node, gh))
+ {
+ update_favorites_menus ();
+ }
+}
+
+static void
+ephy_setup_history_notifiers (EphyBookmarks *eb)
+{
+ EphyEmbedShell *embed_shell;
+ EphyHistory *history;
+
+ embed_shell = ephy_shell_get_embed_shell (ephy_shell);
+ history = ephy_embed_shell_get_global_history (embed_shell);
+
+ g_signal_connect (history, "visited",
+ G_CALLBACK (history_site_visited_cb), eb);
+}
+
+static void
+keywords_added_cb (EphyNode *node,
+ EphyNode *child,
+ EphyBookmarks *eb)
+{
+ g_static_rw_lock_writer_lock (eb->priv->keywords_hash_lock);
+
+ g_hash_table_insert (eb->priv->keywords_hash,
+ (char *) ephy_node_get_property_string (child, EPHY_NODE_KEYWORD_PROP_NAME),
+ child);
+
+ g_static_rw_lock_writer_unlock (eb->priv->keywords_hash_lock);
+}
+
+static void
+keywords_removed_cb (EphyNode *node,
+ EphyNode *child,
+ EphyBookmarks *eb)
+{
+ g_static_rw_lock_writer_lock (eb->priv->keywords_hash_lock);
+
+ g_hash_table_remove (eb->priv->keywords_hash,
+ ephy_node_get_property_string (child, EPHY_NODE_KEYWORD_PROP_NAME));
+
+ g_static_rw_lock_writer_unlock (eb->priv->keywords_hash_lock);
+}
+
+static void
+favorites_added_cb (EphyNode *node,
+ EphyNode *child,
+ EphyBookmarks *eb)
+{
+ g_static_rw_lock_writer_lock (eb->priv->favorites_hash_lock);
+
+ g_hash_table_insert (eb->priv->favorites_hash,
+ (char *) ephy_node_get_property_string (child, EPHY_NODE_BMK_PROP_LOCATION),
+ child);
+
+ g_static_rw_lock_writer_unlock (eb->priv->favorites_hash_lock);
+}
+
+static void
+favorites_removed_cb (EphyNode *node,
+ EphyNode *child,
+ EphyBookmarks *eb)
+{
+ g_static_rw_lock_writer_lock (eb->priv->favorites_hash_lock);
+
+ g_hash_table_remove (eb->priv->favorites_hash,
+ ephy_node_get_property_string (child, EPHY_NODE_BMK_PROP_LOCATION));
+
+ g_static_rw_lock_writer_unlock (eb->priv->favorites_hash_lock);
+}
+
+static void
+bookmarks_added_cb (EphyNode *node,
+ EphyNode *child,
+ EphyBookmarks *eb)
+{
+ g_static_rw_lock_writer_lock (eb->priv->bookmarks_hash_lock);
+
+ g_hash_table_insert (eb->priv->bookmarks_hash,
+ (char *) ephy_node_get_property_string (child, EPHY_NODE_BMK_PROP_LOCATION),
+ child);
+
+ g_static_rw_lock_writer_unlock (eb->priv->bookmarks_hash_lock);
+}
+
+static void
+bookmarks_removed_cb (EphyNode *node,
+ EphyNode *child,
+ EphyBookmarks *eb)
+{
+ ephy_bookmarks_emit_data_changed (eb);
+ g_idle_add ((GSourceFunc)ephy_bookmarks_clean_empty_keywords, eb);
+
+ g_static_rw_lock_writer_lock (eb->priv->bookmarks_hash_lock);
+
+ g_hash_table_remove (eb->priv->bookmarks_hash,
+ ephy_node_get_property_string (child, EPHY_NODE_BMK_PROP_LOCATION));
+
+ g_static_rw_lock_writer_unlock (eb->priv->bookmarks_hash_lock);
+}
+
+static void
+ephy_bookmarks_init (EphyBookmarks *eb)
+{
+ GValue value = { 0, };
+
+ eb->priv = g_new0 (EphyBookmarksPrivate, 1);
+
+ eb->priv->xml_file = g_build_filename (ephy_dot_dir (),
+ "bookmarks.xml",
+ NULL);
+
+ eb->priv->bookmarks_hash = g_hash_table_new (g_str_hash,
+ g_str_equal);
+ eb->priv->bookmarks_hash_lock = g_new0 (GStaticRWLock, 1);
+ g_static_rw_lock_init (eb->priv->bookmarks_hash_lock);
+
+ eb->priv->keywords_hash = g_hash_table_new (g_str_hash,
+ g_str_equal);
+ eb->priv->keywords_hash_lock = g_new0 (GStaticRWLock, 1);
+ g_static_rw_lock_init (eb->priv->keywords_hash_lock);
+
+ eb->priv->favorites_hash = g_hash_table_new (g_str_hash,
+ g_str_equal);
+ eb->priv->favorites_hash_lock = g_new0 (GStaticRWLock, 1);
+ g_static_rw_lock_init (eb->priv->favorites_hash_lock);
+
+ /* Bookmarks */
+ eb->priv->bookmarks = ephy_node_new ();
+ ephy_node_ref (eb->priv->bookmarks);
+ g_value_init (&value, G_TYPE_STRING);
+ g_value_set_string (&value, _("All"));
+ ephy_node_set_property (eb->priv->bookmarks,
+ EPHY_NODE_KEYWORD_PROP_NAME,
+ &value);
+ g_value_unset (&value);
+ g_signal_connect_object (G_OBJECT (eb->priv->bookmarks),
+ "child_added",
+ G_CALLBACK (bookmarks_added_cb),
+ G_OBJECT (eb),
+ 0);
+ g_signal_connect_object (G_OBJECT (eb->priv->bookmarks),
+ "child_removed",
+ G_CALLBACK (bookmarks_removed_cb),
+ G_OBJECT (eb),
+ 0);
+
+ /* Keywords */
+ eb->priv->keywords = ephy_node_new ();
+ ephy_node_ref (eb->priv->keywords);
+
+ ephy_node_add_child (eb->priv->keywords,
+ eb->priv->bookmarks);
+ g_signal_connect_object (G_OBJECT (eb->priv->keywords),
+ "child_added",
+ G_CALLBACK (keywords_added_cb),
+ G_OBJECT (eb),
+ 0);
+ g_signal_connect_object (G_OBJECT (eb->priv->keywords),
+ "child_removed",
+ G_CALLBACK (keywords_removed_cb),
+ G_OBJECT (eb),
+ 0);
+
+ eb->priv->favorites = ephy_node_new ();
+ ephy_node_ref (eb->priv->favorites);
+ g_signal_connect_object (G_OBJECT (eb->priv->favorites),
+ "child_added",
+ G_CALLBACK (favorites_added_cb),
+ G_OBJECT (eb),
+ 0);
+ g_signal_connect_object (G_OBJECT (eb->priv->favorites),
+ "child_removed",
+ G_CALLBACK (favorites_removed_cb),
+ G_OBJECT (eb),
+ 0);
+
+ ephy_bookmarks_load (eb);
+ ephy_bookmarks_emit_data_changed (eb);
+
+ ephy_setup_history_notifiers (eb);
+ ephy_bookmarks_update_favorites (eb);
+}
+
+static void
+ephy_bookmarks_finalize (GObject *object)
+{
+ EphyBookmarks *eb;
+
+ g_return_if_fail (IS_EPHY_BOOKMARKS (object));
+
+ eb = EPHY_BOOKMARKS (object);
+
+ g_return_if_fail (eb->priv != NULL);
+
+ ephy_bookmarks_save (eb);
+
+ ephy_node_unref (eb->priv->bookmarks);
+ ephy_node_unref (eb->priv->keywords);
+ ephy_node_unref (eb->priv->favorites);
+
+ g_hash_table_destroy (eb->priv->bookmarks_hash);
+ g_static_rw_lock_free (eb->priv->bookmarks_hash_lock);
+ g_hash_table_destroy (eb->priv->favorites_hash);
+ g_static_rw_lock_free (eb->priv->favorites_hash_lock);
+ g_hash_table_destroy (eb->priv->keywords_hash);
+ g_static_rw_lock_free (eb->priv->keywords_hash_lock);
+
+ g_free (eb->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+EphyBookmarks *
+ephy_bookmarks_new ()
+{
+ EphyBookmarks *tab;
+
+ tab = EPHY_BOOKMARKS (g_object_new (EPHY_BOOKMARKS_TYPE, NULL));
+
+ return tab;
+}
+
+EphyNode *
+ephy_bookmarks_add (EphyBookmarks *eb,
+ const char *title,
+ const char *url,
+ const char *smart_url,
+ const char *keywords)
+{
+ EphyNode *bm;
+ GValue value = { 0, };
+
+ bm = ephy_node_new ();
+
+ g_value_init (&value, G_TYPE_STRING);
+ g_value_set_string (&value, title);
+ ephy_node_set_property (bm, EPHY_NODE_BMK_PROP_TITLE,
+ &value);
+ g_value_unset (&value);
+
+ g_value_init (&value, G_TYPE_STRING);
+ g_value_set_string (&value, url);
+ ephy_node_set_property (bm, EPHY_NODE_BMK_PROP_LOCATION,
+ &value);
+ g_value_unset (&value);
+
+ g_value_init (&value, G_TYPE_STRING);
+ g_value_set_string (&value, smart_url);
+ ephy_node_set_property (bm, EPHY_NODE_BMK_PROP_SMART_LOCATION,
+ &value);
+ g_value_unset (&value);
+
+ ephy_bookmarks_update_keywords (eb, keywords, bm);
+
+ g_value_init (&value, G_TYPE_STRING);
+ g_value_set_string (&value, keywords);
+ ephy_node_set_property (bm, EPHY_NODE_BMK_PROP_KEYWORDS,
+ &value);
+ g_value_unset (&value);
+
+ ephy_node_add_child (eb->priv->bookmarks, bm);
+
+ ephy_bookmarks_emit_data_changed (eb);
+
+ return bm;
+}
+
+static gchar *
+options_skip_spaces (const gchar *str)
+{
+ const gchar *ret = str;
+ while (*ret && g_ascii_isspace (*ret))
+ {
+ ++ret;
+ }
+ return (gchar *) ret;
+}
+
+static char *
+options_find_value_end (const gchar *value_start)
+{
+ const gchar *value_end;
+ if (*value_start == '"')
+ {
+ for (value_end = value_start + 1;
+ *value_end && (*value_end != '"' || *(value_end - 1) == '\\');
+ ++value_end) ;
+ }
+ else
+ {
+ for (value_end = value_start;
+ *value_end && ! (g_ascii_isspace (*value_end)
+ || *value_end == ','
+ || *value_end == ';');
+ ++value_end) ;
+ }
+ return (gchar *) value_end;
+}
+
+static char *
+options_find_next_option (const char *current)
+{
+ const gchar *value_start;
+ const gchar *value_end;
+ const gchar *ret;
+ value_start = strchr (current, '=');
+ if (!value_start) return NULL;
+ value_start = options_skip_spaces (value_start + 1);
+ value_end = options_find_value_end (value_start);
+ if (! (*value_end)) return NULL;
+ for (ret = value_end + 1;
+ *ret && (g_ascii_isspace (*ret)
+ || *ret == ','
+ || *ret == ';');
+ ++ret);
+ return (char *) ret;
+}
+
+/**
+ * Very simple parser for option strings in the
+ * form a=b,c=d,e="f g",...
+ */
+static gchar *
+smart_url_options_get (const gchar *options, const gchar *option)
+{
+ gchar *ret = NULL;
+ gsize optionlen = strlen (option);
+ const gchar *current = options_skip_spaces (options);
+
+ while (current)
+ {
+ if (!strncmp (option, current, optionlen))
+ {
+ if (g_ascii_isspace (*(current + optionlen)) || *(current + optionlen) == '=')
+ {
+ const gchar *value_start;
+ const gchar *value_end;
+ value_start = strchr (current + optionlen, '=');
+ if (!value_start) continue;
+ value_start = options_skip_spaces (value_start + 1);
+ value_end = options_find_value_end (value_start);
+ if (*value_start == '"') value_start++;
+ if (value_end >= value_start)
+ {
+ ret = g_strndup (value_start, value_end - value_start);
+ break;
+ }
+ }
+ }
+ current = options_find_next_option (current);
+ }
+
+ return ret;
+}
+
+static char *
+get_smarturl_only (const char *smarturl)
+{
+ const gchar *openbrace;
+ const gchar *closebrace;
+ const gchar *c;
+
+ openbrace = strchr (smarturl, '{');
+ if (!openbrace) return g_strdup (smarturl);
+ for (c = smarturl; c < openbrace; ++c)
+ {
+ if (!strchr (" \t\n", *c)) return g_strdup (smarturl);
+ }
+
+ closebrace = strchr (openbrace + 1, '}');
+ if (!closebrace) return g_strdup (smarturl);
+
+ return g_strdup (closebrace + 1);
+}
+
+char *
+ephy_bookmarks_solve_smart_url (EphyBookmarks *eb,
+ const char *smart_url,
+ const char *content)
+{
+ gchar *ret;
+ GString *s;
+ gchar *t1;
+ gchar *t2;
+ gchar *encoding;
+ gchar *smarturl_only;
+ gchar *arg;
+
+ g_return_val_if_fail (content != NULL, NULL);
+
+ smarturl_only = get_smarturl_only (smart_url);
+
+ s = g_string_new ("");
+
+ encoding = smart_url_options_get (smart_url, "encoding");
+ if (!encoding)
+ {
+ encoding = g_strdup ("UTF-8");
+ }
+
+ arg = g_convert (content, strlen (content),
+ encoding, "UTF-8", NULL, NULL, NULL);
+
+ t1 = smarturl_only;
+ t2 = strstr (t1, "%s");
+ g_return_val_if_fail (t2 != NULL, NULL);
+ g_string_append_len (s, t1, t2 - t1);
+ g_string_append (s, arg);
+ t1 = t2 + 2;
+ g_string_append (s, t1);
+ ret = s->str;
+ g_string_free (s, FALSE);
+
+ g_free (arg);
+ g_free (encoding);
+ g_free (smarturl_only);
+
+ return ret;
+}
+
+EphyNode *
+ephy_bookmarks_add_keyword (EphyBookmarks *eb,
+ const char *name)
+{
+ EphyNode *key;
+ GValue value = { 0, };
+
+ key = ephy_node_new ();
+
+ g_value_init (&value, G_TYPE_STRING);
+ g_value_set_string (&value, name);
+ ephy_node_set_property (key, EPHY_NODE_KEYWORD_PROP_NAME,
+ &value);
+ g_value_unset (&value);
+
+ ephy_node_add_child (eb->priv->keywords, key);
+
+ return key;
+}
+
+EphyNode *
+ephy_bookmarks_find_keyword (EphyBookmarks *eb,
+ const char *name,
+ gboolean partial_match)
+{
+ EphyNode *node;
+
+ g_return_val_if_fail (name != NULL, NULL);
+
+ if (!partial_match)
+ {
+ g_static_rw_lock_reader_lock (eb->priv->keywords_hash_lock);
+ node = g_hash_table_lookup (eb->priv->keywords_hash, name);
+ g_static_rw_lock_reader_unlock (eb->priv->keywords_hash_lock);
+ }
+ else
+ {
+ GPtrArray *children;
+ int i;
+
+ if (g_utf8_strlen (name, -1) == 0)
+ {
+ DEBUG_MSG (("Empty name, no keyword matches.\n"));
+ return NULL;
+ }
+
+ children = ephy_node_get_children (eb->priv->keywords);
+ node = NULL;
+ for (i = 0; i < children->len; i++)
+ {
+ EphyNode *kid;
+ const char *key;
+
+ kid = g_ptr_array_index (children, i);
+ key = ephy_node_get_property_string (kid, EPHY_NODE_KEYWORD_PROP_NAME);
+
+ if (g_str_has_prefix (key, name) > 0)
+ {
+ node = kid;
+ }
+ }
+ ephy_node_thaw (eb->priv->keywords);
+ }
+
+ return node;
+}
+
+void
+ephy_bookmarks_set_keyword (EphyBookmarks *eb,
+ EphyNode *keyword,
+ EphyNode *bookmark)
+{
+ ephy_node_add_child (keyword, bookmark);
+}
+
+void
+ephy_bookmarks_unset_keyword (EphyBookmarks *eb,
+ EphyNode *keyword,
+ EphyNode *bookmark)
+{
+ ephy_node_remove_child (keyword, bookmark);
+ ephy_bookmarks_clean_empty_keywords (eb);
+}
+
+static GList *
+diff_keywords (char **ks1, char **ks2)
+{
+ GList *result = NULL;
+ int i, j;
+
+ for (i = 0; ks1 != NULL && ks1[i] != NULL; i++)
+ {
+ gboolean found = FALSE;
+
+ DEBUG_MSG (("Diff keywords, keyword:\"%s\"\n", ks1[i]));
+
+ for (j = 0; ks2 != NULL && ks2[j] != NULL; j++)
+ {
+ if (strcmp (ks1[i], ks2[j]) == 0)
+ {
+ found = TRUE;
+ }
+ }
+
+ if (!found && g_utf8_strlen (ks1[i], -1) > 0)
+ {
+ result = g_list_append (result, ks1[i]);
+ }
+ }
+
+ return result;
+}
+
+void
+ephy_bookmarks_update_keywords (EphyBookmarks *eb,
+ const char *keywords,
+ EphyNode *node)
+{
+ const char *prop;
+ char **ks, **old_ks = NULL;
+ GList *diffs, *l;
+ EphyNode *keyword;
+
+ prop = ephy_node_get_property_string (node, EPHY_NODE_BMK_PROP_KEYWORDS);
+ ks = g_strsplit (keywords, " ", 10);
+ if (prop != NULL)
+ {
+ old_ks = g_strsplit (prop, " ", 10);
+ }
+
+ diffs = diff_keywords (ks, old_ks);
+ for (l = diffs; l != NULL; l = l->next)
+ {
+ char *word = (char *)l->data;
+
+ keyword = ephy_bookmarks_find_keyword
+ (eb, word, FALSE);
+
+ if (!keyword)
+ {
+ keyword = ephy_bookmarks_add_keyword
+ (eb, word);
+ }
+
+ ephy_bookmarks_set_keyword (eb, keyword, node);
+ }
+ g_list_free (diffs);
+
+ diffs = diff_keywords (old_ks, ks);
+ for (l = diffs; l != NULL; l = l->next)
+ {
+ keyword = ephy_bookmarks_find_keyword (eb,
+ (char *)l->data, FALSE);
+ g_return_if_fail (keyword != NULL);
+
+ ephy_bookmarks_unset_keyword (eb, keyword, node);
+ }
+ g_list_free (diffs);
+
+ g_strfreev (ks);
+ g_strfreev (old_ks);
+}
+
+EphyNode *
+ephy_bookmarks_get_keywords (EphyBookmarks *eb)
+{
+ return eb->priv->keywords;
+}
+
+EphyNode *
+ephy_bookmarks_get_bookmarks (EphyBookmarks *eb)
+{
+ return eb->priv->bookmarks;
+}
+
+EphyNode *
+ephy_bookmarks_get_favorites (EphyBookmarks *eb)
+{
+ return eb->priv->favorites;
+}
+
diff --git a/src/bookmarks/ephy-bookmarks.h b/src/bookmarks/ephy-bookmarks.h
new file mode 100644
index 000000000..e355950c4
--- /dev/null
+++ b/src/bookmarks/ephy-bookmarks.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EPHY_BOOKMARKS_H
+#define EPHY_BOOKMARKS_H
+
+#include <glib-object.h>
+
+#include "ephy-node.h"
+
+G_BEGIN_DECLS
+
+typedef struct EphyBookmarksClass EphyBookmarksClass;
+
+#define EPHY_BOOKMARKS_TYPE (ephy_bookmarks_get_type ())
+#define EPHY_BOOKMARKS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EPHY_BOOKMARKS_TYPE, EphyBookmarks))
+#define EPHY_BOOKMARKS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EPHY_BOOKMARKS_TYPE, EphyBookmarksClass))
+#define IS_EPHY_BOOKMARKS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EPHY_BOOKMARKS_TYPE))
+#define IS_EPHY_BOOKMARKS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EPHY_BOOKMARKS_TYPE))
+
+typedef struct EphyBookmarks EphyBookmarks;
+typedef struct EphyBookmarksPrivate EphyBookmarksPrivate;
+
+enum
+{
+ EPHY_NODE_BMK_PROP_TITLE = 2,
+ EPHY_NODE_BMK_PROP_LOCATION = 3,
+ EPHY_NODE_BMK_PROP_KEYWORDS = 4,
+ EPHY_NODE_KEYWORD_PROP_NAME = 5,
+ EPHY_NODE_BMK_PROP_SMART_LOCATION = 6
+};
+
+struct EphyBookmarks
+{
+ GObject parent;
+ EphyBookmarksPrivate *priv;
+};
+
+struct EphyBookmarksClass
+{
+ GObjectClass parent_class;
+};
+
+GType ephy_bookmarks_get_type (void);
+
+EphyBookmarks *ephy_bookmarks_new (void);
+
+/* Bookmarks */
+
+EphyNode *ephy_bookmarks_add (EphyBookmarks *eb,
+ const char *title,
+ const char *url,
+ const char *smart_url,
+ const char *keywords);
+
+char *ephy_bookmarks_solve_smart_url (EphyBookmarks *eb,
+ const char *smart_url,
+ const char *content);
+
+/* Keywords */
+
+EphyNode *ephy_bookmarks_add_keyword (EphyBookmarks *eb,
+ const char *name);
+
+EphyNode *ephy_bookmarks_find_keyword (EphyBookmarks *eb,
+ const char *name,
+ gboolean partial_match);
+
+void ephy_bookmarks_set_keyword (EphyBookmarks *eb,
+ EphyNode *keyword,
+ EphyNode *bookmark);
+
+void ephy_bookmarks_unset_keyword (EphyBookmarks *eb,
+ EphyNode *keyword,
+ EphyNode *bookmark);
+
+void ephy_bookmarks_update_keywords (EphyBookmarks *eb,
+ const char *keywords,
+ EphyNode *bookmark_node);
+
+/* Favorites */
+
+EphyNode *ephy_bookmarks_get_favorites (EphyBookmarks *eb);
+
+/* Root */
+
+EphyNode *ephy_bookmarks_get_keywords (EphyBookmarks *eb);
+
+EphyNode *ephy_bookmarks_get_bookmarks (EphyBookmarks *eb);
+
+G_END_DECLS
+
+#endif
diff --git a/src/bookmarks/ephy-keywords-entry.c b/src/bookmarks/ephy-keywords-entry.c
new file mode 100644
index 000000000..94d6c93a9
--- /dev/null
+++ b/src/bookmarks/ephy-keywords-entry.c
@@ -0,0 +1,286 @@
+/*
+ * Copyright (C) 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "ephy-keywords-entry.h"
+#include "ephy-marshal.h"
+#include "ephy-gobject-misc.h"
+
+#include <gdk/gdkkeysyms.h>
+
+//#define DEBUG_MSG(x) g_print x
+#define DEBUG_MSG(x)
+
+#define NOT_IMPLEMENTED g_warning ("not implemented: " G_STRLOC);
+
+/**
+ * Private data
+ */
+struct _EphyKeywordsEntryPrivate
+{
+ EphyBookmarks *bookmarks;
+};
+
+/**
+ * Private functions, only availble from this file
+ */
+static void ephy_keywords_entry_class_init (EphyKeywordsEntryClass *klass);
+static void ephy_keywords_entry_init (EphyKeywordsEntry *w);
+static void ephy_keywords_entry_finalize_impl (GObject *o);
+static gint ephy_keywords_entry_key_press (GtkWidget *widget,
+ GdkEventKey *event);
+
+enum
+{
+ KEYWORDS_CHANGED,
+ LAST_SIGNAL
+};
+
+static GObjectClass *parent_class = NULL;
+
+static guint keywords_entry_signals[LAST_SIGNAL] = { 0 };
+
+MAKE_GET_TYPE (ephy_keywords_entry, "EphyKeywordsEntry", EphyKeywordsEntry,
+ ephy_keywords_entry_class_init,
+ ephy_keywords_entry_init, GTK_TYPE_ENTRY);
+
+static void
+ephy_keywords_entry_class_init (EphyKeywordsEntryClass *class)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (class);
+ GtkWidgetClass *widget_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ widget_class = (GtkWidgetClass*) class;
+
+ gobject_class->finalize = ephy_keywords_entry_finalize_impl;
+
+ widget_class->key_press_event = ephy_keywords_entry_key_press;
+
+ keywords_entry_signals[KEYWORDS_CHANGED] =
+ g_signal_new ("keywords_changed",
+ G_OBJECT_CLASS_TYPE (gobject_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (EphyKeywordsEntryClass, keywords_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+}
+
+static void
+try_to_expand_keyword (GtkEditable *editable)
+{
+ char *entry_text;
+ char *user_text;
+ const char *expand_text;
+ char *insert_text;
+ int user_text_length;
+ int expand_text_length;
+ int keyword_offset = 0;
+ int tmp;
+ EphyKeywordsEntry *entry = EPHY_KEYWORDS_ENTRY (editable);
+ EphyNode *node;
+
+ entry_text = gtk_editable_get_chars (editable, 0, -1);
+ g_return_if_fail (entry_text != NULL);
+
+ DEBUG_MSG (("Entry text \"%s\"\n", entry_text));
+
+ user_text = g_utf8_strrchr (entry_text, -1, ' ');
+
+ if (user_text)
+ {
+ user_text = g_utf8_find_next_char (user_text, NULL);
+ keyword_offset = g_utf8_pointer_to_offset
+ (entry_text, user_text);
+ }
+ else
+ {
+ user_text = entry_text;
+ }
+
+ DEBUG_MSG (("User text \"%s\"\n", user_text));
+
+ node = ephy_bookmarks_find_keyword (entry->priv->bookmarks,
+ user_text, TRUE);
+ if (node)
+ {
+ expand_text = ephy_node_get_property_string
+ (node, EPHY_NODE_KEYWORD_PROP_NAME);
+
+ DEBUG_MSG (("Expand text %s\n", expand_text));
+
+ expand_text_length = g_utf8_strlen (expand_text, -1);
+ user_text_length = g_utf8_strlen (user_text, -1);
+
+ insert_text = g_utf8_offset_to_pointer (expand_text, user_text_length);
+ gtk_editable_insert_text (editable,
+ insert_text,
+ g_utf8_strlen (insert_text, -1),
+ &tmp);
+ gtk_editable_select_region (editable, user_text_length + keyword_offset, -1);
+ }
+ else
+ {
+ DEBUG_MSG (("No expansion.\n"));
+ }
+
+ g_free (entry_text);
+}
+
+/* Until we have a more elegant solution, this is how we figure out if
+ * the GtkEntry inserted characters, assuming that the return value is
+ * TRUE indicating that the GtkEntry consumed the key event for some
+ * reason. This is a clone of code from GtkEntry.
+ */
+static gboolean
+entry_would_have_inserted_characters (const GdkEventKey *event)
+{
+ switch (event->keyval) {
+ case GDK_BackSpace:
+ case GDK_Clear:
+ case GDK_Insert:
+ case GDK_Delete:
+ case GDK_Home:
+ case GDK_End:
+ case GDK_Left:
+ case GDK_Right:
+ case GDK_Return:
+ return FALSE;
+ default:
+ if (event->keyval >= 0x20 && event->keyval <= 0xFF) {
+ if ((event->state & GDK_CONTROL_MASK) != 0) {
+ return FALSE;
+ }
+ if ((event->state & GDK_MOD1_MASK) != 0) {
+ return FALSE;
+ }
+ }
+ return event->length > 0;
+ }
+}
+
+static int
+get_editable_number_of_chars (GtkEditable *editable)
+{
+ char *text;
+ int length;
+
+ text = gtk_editable_get_chars (editable, 0, -1);
+ length = g_utf8_strlen (text, -1);
+ g_free (text);
+ return length;
+}
+
+static void
+set_position_and_selection_to_end (GtkEditable *editable)
+{
+ int end;
+
+ end = get_editable_number_of_chars (editable);
+ gtk_editable_select_region (editable, end, end);
+ gtk_editable_set_position (editable, end);
+}
+
+static gboolean
+position_and_selection_are_at_end (GtkEditable *editable)
+{
+ int end;
+ int start_sel, end_sel;
+
+ end = get_editable_number_of_chars (editable);
+ if (gtk_editable_get_selection_bounds (editable, &start_sel, &end_sel))
+ {
+ if (start_sel != end || end_sel != end)
+ {
+ return FALSE;
+ }
+ }
+ return gtk_editable_get_position (editable) == end;
+}
+
+static gint
+ephy_keywords_entry_key_press (GtkWidget *widget,
+ GdkEventKey *event)
+{
+ GtkEditable *editable;
+ GdkEventKey *keyevent;
+ EphyKeywordsEntry *entry;
+ gboolean result;
+
+ entry = EPHY_KEYWORDS_ENTRY (widget);
+ editable = GTK_EDITABLE (entry);
+ keyevent = (GdkEventKey *)event;
+
+ /* After typing the right arrow key we move the selection to
+ * the end, if we have a valid selection - since this is most
+ * likely an auto-completion. We ignore shift / control since
+ * they can validly be used to extend the selection.
+ */
+ if ((keyevent->keyval == GDK_Right || keyevent->keyval == GDK_End) &&
+ !(keyevent->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) &&
+ gtk_editable_get_selection_bounds (editable, NULL, NULL))
+ {
+ set_position_and_selection_to_end (editable);
+ }
+
+ result = GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event);
+
+ /* Only do expanding when we are typing at the end of the
+ * text.
+ */
+ if (entry_would_have_inserted_characters (event)
+ && position_and_selection_are_at_end (editable))
+ {
+ try_to_expand_keyword (editable);
+ }
+
+ g_signal_emit (G_OBJECT (entry), keywords_entry_signals[KEYWORDS_CHANGED], 0);
+
+ return result;
+}
+
+static void
+ephy_keywords_entry_init (EphyKeywordsEntry *w)
+{
+ w->priv = g_new0 (EphyKeywordsEntryPrivate, 1);
+ w->priv->bookmarks = NULL;
+}
+
+static void
+ephy_keywords_entry_finalize_impl (GObject *o)
+{
+ EphyKeywordsEntry *w = EPHY_KEYWORDS_ENTRY (o);
+ EphyKeywordsEntryPrivate *p = w->priv;
+
+ g_free (p);
+ G_OBJECT_CLASS (parent_class)->finalize (o);
+}
+
+GtkWidget *
+ephy_keywords_entry_new (void)
+{
+ return GTK_WIDGET (g_object_new (EPHY_TYPE_LOCATION_ENTRY, NULL));
+}
+
+void
+ephy_keywords_entry_set_bookmarks (EphyKeywordsEntry *w,
+ EphyBookmarks *bookmarks)
+{
+ w->priv->bookmarks = bookmarks;
+}
diff --git a/src/bookmarks/ephy-keywords-entry.h b/src/bookmarks/ephy-keywords-entry.h
new file mode 100644
index 000000000..5ab5df257
--- /dev/null
+++ b/src/bookmarks/ephy-keywords-entry.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2002 Ricardo Fernández Pascual
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EPHY_KEYWORDS_ENTRY_H
+#define EPHY_KEYWORDS_ENTRY_H
+
+#include "ephy-bookmarks.h"
+
+#include <glib-object.h>
+#include <gtk/gtkentry.h>
+
+/* object forward declarations */
+
+typedef struct _EphyKeywordsEntry EphyKeywordsEntry;
+typedef struct _EphyKeywordsEntryClass EphyKeywordsEntryClass;
+typedef struct _EphyKeywordsEntryPrivate EphyKeywordsEntryPrivate;
+
+/**
+ * EphyFolderTbWidget object
+ */
+
+#define EPHY_TYPE_LOCATION_ENTRY (ephy_keywords_entry_get_type())
+#define EPHY_KEYWORDS_ENTRY(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EPHY_TYPE_LOCATION_ENTRY,\
+ EphyKeywordsEntry))
+#define EPHY_KEYWORDS_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EPHY_TYPE_LOCATION_ENTRY,\
+ EphyKeywordsEntryClass))
+#define EPHY_IS_LOCATION_ENTRY(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EPHY_TYPE_LOCATION_ENTRY))
+#define EPHY_IS_LOCATION_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), EPHY_TYPE_LOCATION_ENTRY))
+#define EPHY_KEYWORDS_ENTRY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EPHY_TYPE_LOCATION_ENTRY,\
+ EphyKeywordsEntryClass))
+
+struct _EphyKeywordsEntryClass
+{
+ GtkEntryClass parent_class;
+
+ void (* keywords_changed) (EphyKeywordsEntry *entry);
+};
+
+struct _EphyKeywordsEntry
+{
+ GtkEntry parent_object;
+
+ EphyKeywordsEntryPrivate *priv;
+};
+
+GType ephy_keywords_entry_get_type (void);
+
+GtkWidget *ephy_keywords_entry_new (void);
+
+void ephy_keywords_entry_set_bookmarks (EphyKeywordsEntry *w,
+ EphyBookmarks *bookmarks);
+
+#endif
diff --git a/src/bookmarks/ephy-new-bookmark.c b/src/bookmarks/ephy-new-bookmark.c
new file mode 100644
index 000000000..ee0d4b983
--- /dev/null
+++ b/src/bookmarks/ephy-new-bookmark.c
@@ -0,0 +1,340 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen <jorn@nl.linux.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include <gtk/gtktable.h>
+#include <gtk/gtklabel.h>
+#include <gtk/gtkentry.h>
+#include <gtk/gtkhbox.h>
+#include <gtk/gtkvbox.h>
+#include <gtk/gtkstock.h>
+#include <gtk/gtkeditable.h>
+#include <libgnome/gnome-i18n.h>
+
+#include "ephy-new-bookmark.h"
+#include "ephy-keywords-entry.h"
+
+//#define DEBUG_MSG(x) g_print x
+#define DEBUG_MSG(x)
+
+static void ephy_new_bookmark_class_init (EphyNewBookmarkClass *klass);
+static void ephy_new_bookmark_init (EphyNewBookmark *editor);
+static void ephy_new_bookmark_finalize (GObject *object);
+static void ephy_new_bookmark_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void ephy_new_bookmark_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+struct EphyNewBookmarkPrivate
+{
+ EphyBookmarks *bookmarks;
+ char *location;
+ char *smarturl;
+
+ GtkWidget *title_entry;
+ GtkWidget *keywords_entry;
+};
+
+enum
+{
+ PROP_0,
+ PROP_BOOKMARKS,
+ PROP_LOCATION
+};
+
+static GObjectClass *parent_class = NULL;
+
+GType
+ephy_new_bookmark_get_type (void)
+{
+ static GType ephy_new_bookmark_type = 0;
+
+ if (ephy_new_bookmark_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (EphyNewBookmarkClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) ephy_new_bookmark_class_init,
+ NULL,
+ NULL,
+ sizeof (EphyNewBookmark),
+ 0,
+ (GInstanceInitFunc) ephy_new_bookmark_init
+ };
+
+ ephy_new_bookmark_type = g_type_register_static (GTK_TYPE_DIALOG,
+ "EphyNewBookmark",
+ &our_info, 0);
+ }
+
+ return ephy_new_bookmark_type;
+}
+
+static void
+ephy_new_bookmark_class_init (EphyNewBookmarkClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = ephy_new_bookmark_finalize;
+
+ object_class->set_property = ephy_new_bookmark_set_property;
+ object_class->get_property = ephy_new_bookmark_get_property;
+
+ g_object_class_install_property (object_class,
+ PROP_BOOKMARKS,
+ g_param_spec_object ("bookmarks",
+ "Bookmarks set",
+ "Bookmarks set",
+ EPHY_BOOKMARKS_TYPE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (object_class,
+ PROP_LOCATION,
+ g_param_spec_string ("location",
+ "Bookmark location",
+ "Bookmark location",
+ "",
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+ephy_new_bookmark_finalize (GObject *object)
+{
+ EphyNewBookmark *editor;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (EPHY_IS_NEW_BOOKMARK (object));
+
+ editor = EPHY_NEW_BOOKMARK (object);
+
+ g_return_if_fail (editor->priv != NULL);
+
+ g_free (editor->priv->location);
+ g_free (editor->priv->smarturl);
+
+ g_free (editor->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+ephy_new_bookmark_add (EphyNewBookmark *new_bookmark)
+{
+ char *title;
+ char *keywords;
+
+ title = gtk_editable_get_chars
+ (GTK_EDITABLE (new_bookmark->priv->title_entry), 0, -1);
+ keywords = gtk_editable_get_chars
+ (GTK_EDITABLE (new_bookmark->priv->keywords_entry), 0, -1);
+ ephy_bookmarks_add (new_bookmark->priv->bookmarks, title,
+ new_bookmark->priv->location,
+ new_bookmark->priv->smarturl, keywords);
+}
+
+static void
+ephy_new_bookmark_response_cb (GtkDialog *dialog,
+ int response_id,
+ EphyNewBookmark *new_bookmark)
+{
+ switch (response_id)
+ {
+ case GTK_RESPONSE_CANCEL:
+ break;
+ case GTK_RESPONSE_OK:
+ ephy_new_bookmark_add (new_bookmark);
+ break;
+ }
+
+ gtk_widget_destroy (GTK_WIDGET (dialog));
+}
+
+static GtkWidget *
+build_editing_table (EphyNewBookmark *editor)
+{
+ GtkWidget *table, *label, *entry;
+
+ table = gtk_table_new (2, 2, FALSE);
+ gtk_table_set_row_spacings (GTK_TABLE (table), 6);
+ gtk_table_set_col_spacings (GTK_TABLE (table), 6);
+ gtk_widget_show (table);
+
+ label = gtk_label_new (NULL);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+ gtk_label_set_markup (GTK_LABEL (label), _("<b>Title:</b>"));
+ gtk_widget_show (label);
+ entry = gtk_entry_new ();
+ editor->priv->title_entry = entry;
+ gtk_widget_set_size_request (entry, 200, -1);
+ gtk_widget_show (entry);
+ gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, GTK_FILL, 0, 0, 0);
+ gtk_table_attach_defaults (GTK_TABLE (table), entry, 1, 2, 0, 1);
+
+ label = gtk_label_new (NULL);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+ gtk_label_set_markup (GTK_LABEL (label), _("<b>Keywords:</b>"));
+ gtk_widget_show (label);
+ entry = ephy_keywords_entry_new ();
+ ephy_keywords_entry_set_bookmarks (EPHY_KEYWORDS_ENTRY (entry),
+ editor->priv->bookmarks);
+ editor->priv->keywords_entry = entry;
+ gtk_widget_show (entry);
+ gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, GTK_FILL, 0, 0, 0);
+ gtk_table_attach_defaults (GTK_TABLE (table), entry, 1, 2, 1, 2);
+
+ return table;
+}
+
+static void
+ephy_new_bookmark_construct (EphyNewBookmark *editor)
+{
+ GtkWidget *hbox, *vbox;
+
+ gtk_window_set_title (GTK_WINDOW (editor),
+ _("Add bookmark"));
+
+ gtk_dialog_set_has_separator (GTK_DIALOG (editor), FALSE);
+ gtk_container_set_border_width (GTK_CONTAINER (editor), 6);
+ g_signal_connect (G_OBJECT (editor),
+ "response",
+ G_CALLBACK (ephy_new_bookmark_response_cb),
+ editor);
+
+ hbox = gtk_hbox_new (FALSE, 6);
+ gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (editor)->vbox), 12);
+ gtk_box_pack_start (GTK_BOX (GTK_DIALOG (editor)->vbox),
+ hbox, TRUE, TRUE, 0);
+ gtk_widget_show (hbox);
+
+ vbox = gtk_vbox_new (FALSE, 6);
+ gtk_box_pack_start (GTK_BOX (hbox),
+ vbox, TRUE, TRUE, 0);
+ gtk_widget_show (vbox);
+
+ gtk_box_pack_start (GTK_BOX (vbox),
+ build_editing_table (editor),
+ FALSE, FALSE, 0);
+
+ gtk_dialog_add_button (GTK_DIALOG (editor),
+ GTK_STOCK_CANCEL,
+ GTK_RESPONSE_CANCEL);
+ gtk_dialog_add_button (GTK_DIALOG (editor),
+ GTK_STOCK_OK,
+ GTK_RESPONSE_OK);
+ gtk_dialog_set_default_response (GTK_DIALOG (editor), GTK_RESPONSE_OK);
+}
+
+GtkWidget *
+ephy_new_bookmark_new (EphyBookmarks *bookmarks,
+ GtkWindow *parent,
+ const char *location)
+{
+ EphyNewBookmark *editor;
+
+ g_assert (bookmarks != NULL);
+
+ editor = EPHY_NEW_BOOKMARK (g_object_new
+ (EPHY_TYPE_NEW_BOOKMARK,
+ "bookmarks", bookmarks,
+ "location", location,
+ NULL));
+
+ if (parent)
+ {
+ gtk_window_set_transient_for (GTK_WINDOW (editor), parent);
+ }
+
+ ephy_new_bookmark_construct (editor);
+
+ return GTK_WIDGET (editor);
+}
+
+static void
+ephy_new_bookmark_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EphyNewBookmark *editor = EPHY_NEW_BOOKMARK (object);
+
+ switch (prop_id)
+ {
+ case PROP_BOOKMARKS:
+ editor->priv->bookmarks = g_value_get_object (value);
+ break;
+ case PROP_LOCATION:
+ g_free (editor->priv->location);
+ editor->priv->location = g_strdup (g_value_get_string (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+ephy_new_bookmark_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ EphyNewBookmark *editor = EPHY_NEW_BOOKMARK (object);
+
+ switch (prop_id)
+ {
+ case PROP_LOCATION:
+ g_value_set_string (value, editor->priv->location);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+ephy_new_bookmark_init (EphyNewBookmark *editor)
+{
+ editor->priv = g_new0 (EphyNewBookmarkPrivate, 1);
+ editor->priv->location = NULL;
+ editor->priv->smarturl = NULL;
+}
+
+void
+ephy_new_bookmark_set_title (EphyNewBookmark *bookmark,
+ const char *title)
+{
+ DEBUG_MSG (("Setting new bookmark title to: \"%s\"", title));
+ gtk_entry_set_text (GTK_ENTRY (bookmark->priv->title_entry),
+ g_strdup (title));
+}
+
+void
+ephy_new_bookmark_set_smarturl (EphyNewBookmark *bookmark,
+ const char *url)
+{
+ g_free (bookmark->priv->smarturl);
+ bookmark->priv->smarturl = g_strdup (url);
+}
+
diff --git a/src/bookmarks/ephy-new-bookmark.h b/src/bookmarks/ephy-new-bookmark.h
new file mode 100644
index 000000000..7e1091f50
--- /dev/null
+++ b/src/bookmarks/ephy-new-bookmark.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen <jorn@nl.linux.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Id$
+ */
+
+#ifndef EPHY_NEW_BOOKMARK_H
+#define EPHY_NEW_BOOKMARK_H
+
+#include <gtk/gtkdialog.h>
+
+#include "ephy-bookmarks.h"
+
+G_BEGIN_DECLS
+
+#define EPHY_TYPE_NEW_BOOKMARK (ephy_new_bookmark_get_type ())
+#define EPHY_NEW_BOOKMARK(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EPHY_TYPE_NEW_BOOKMARK, EphyNewBookmark))
+#define EPHY_NEW_BOOKMARK_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EPHY_TYPE_NEW_BOOKMARK, EphyNewBookmarkClass))
+#define EPHY_IS_NEW_BOOKMARK(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EPHY_TYPE_NEW_BOOKMARK))
+#define EPHY_IS_NEW_BOOKMARK_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EPHY_TYPE_NEW_BOOKMARK))
+#define EPHY_NEW_BOOKMARK_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EPHY_TYPE_NEW_BOOKMARK, EphyNewBookmarkClass))
+
+typedef struct EphyNewBookmarkPrivate EphyNewBookmarkPrivate;
+
+typedef struct
+{
+ GtkDialog parent;
+
+ EphyNewBookmarkPrivate *priv;
+} EphyNewBookmark;
+
+typedef struct
+{
+ GtkDialogClass parent;
+} EphyNewBookmarkClass;
+
+GType ephy_new_bookmark_get_type (void);
+
+GtkWidget *ephy_new_bookmark_new (EphyBookmarks *bookmarks,
+ GtkWindow *parent,
+ const char *location);
+
+void ephy_new_bookmark_set_title (EphyNewBookmark *bookmark,
+ const char *title);
+
+void ephy_new_bookmark_set_smarturl (EphyNewBookmark *bookmark,
+ const char *url);
+
+G_END_DECLS
+
+#endif /* EPHY_NEW_BOOKMARK_H */
diff --git a/src/bookmarks/ephy-node-view.c b/src/bookmarks/ephy-node-view.c
new file mode 100644
index 000000000..f537855d8
--- /dev/null
+++ b/src/bookmarks/ephy-node-view.c
@@ -0,0 +1,531 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen <jorn@nl.linux.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include <gtk/gtktreeview.h>
+#include <gtk/gtktreeselection.h>
+#include <gtk/gtktreeviewcolumn.h>
+#include <gtk/gtkcellrenderertext.h>
+#include <libgnome/gnome-i18n.h>
+
+#include "eggtreemodelfilter.h"
+#include "ephy-tree-model-node.h"
+#include "ephy-node-view.h"
+#include "ephy-tree-model-sort.h"
+#include "eggtreemultidnd.h"
+#include "ephy-dnd.h"
+
+static void ephy_node_view_class_init (EphyNodeViewClass *klass);
+static void ephy_node_view_init (EphyNodeView *view);
+static void ephy_node_view_finalize (GObject *object);
+static void ephy_node_view_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void ephy_node_view_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+struct EphyNodeViewPrivate
+{
+ EphyNode *root;
+
+ EphyTreeModelNode *nodemodel;
+ GtkTreeModel *filtermodel;
+ GtkTreeModel *sortmodel;
+
+ EphyNodeFilter *filter;
+
+ GtkWidget *treeview;
+};
+
+enum
+{
+ NODE_ACTIVATED,
+ NODE_SELECTED,
+ SHOW_POPUP,
+ LAST_SIGNAL
+};
+
+enum
+{
+ PROP_0,
+ PROP_ROOT,
+ PROP_FILTER
+};
+
+static GObjectClass *parent_class = NULL;
+
+static guint ephy_node_view_signals[LAST_SIGNAL] = { 0 };
+
+GType
+ephy_node_view_get_type (void)
+{
+ static GType ephy_node_view_type = 0;
+
+ if (ephy_node_view_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (EphyNodeViewClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) ephy_node_view_class_init,
+ NULL,
+ NULL,
+ sizeof (EphyNodeView),
+ 0,
+ (GInstanceInitFunc) ephy_node_view_init
+ };
+
+ ephy_node_view_type = g_type_register_static (GTK_TYPE_SCROLLED_WINDOW,
+ "EphyNodeView",
+ &our_info, 0);
+ }
+
+ return ephy_node_view_type;
+}
+
+static void
+ephy_node_view_class_init (EphyNodeViewClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = ephy_node_view_finalize;
+
+ object_class->set_property = ephy_node_view_set_property;
+ object_class->get_property = ephy_node_view_get_property;
+
+ g_object_class_install_property (object_class,
+ PROP_ROOT,
+ g_param_spec_object ("root",
+ "Root node",
+ "Root node",
+ EPHY_TYPE_NODE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (object_class,
+ PROP_FILTER,
+ g_param_spec_object ("filter",
+ "Filter object",
+ "Filter object",
+ EPHY_TYPE_NODE_FILTER,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+ ephy_node_view_signals[NODE_ACTIVATED] =
+ g_signal_new ("node_activated",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EphyNodeViewClass, node_activated),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE,
+ 1,
+ EPHY_TYPE_NODE);
+ ephy_node_view_signals[NODE_SELECTED] =
+ g_signal_new ("node_selected",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EphyNodeViewClass, node_selected),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE,
+ 1,
+ EPHY_TYPE_NODE);
+ ephy_node_view_signals[SHOW_POPUP] =
+ g_signal_new ("show_popup",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EphyNodeViewClass, show_popup),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+}
+
+static void
+ephy_node_view_finalize (GObject *object)
+{
+ EphyNodeView *view;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (EPHY_IS_NODE_VIEW (object));
+
+ view = EPHY_NODE_VIEW (object);
+
+ g_return_if_fail (view->priv != NULL);
+
+ g_object_unref (G_OBJECT (view->priv->sortmodel));
+ g_object_unref (G_OBJECT (view->priv->filtermodel));
+ g_object_unref (G_OBJECT (view->priv->nodemodel));
+
+ g_free (view->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+filter_changed_cb (EphyNodeFilter *filter,
+ EphyNodeView *view)
+{
+ GtkWidget *window;
+
+ g_return_if_fail (EPHY_IS_NODE_VIEW (view));
+
+ window = gtk_widget_get_toplevel (GTK_WIDGET (view));
+
+ if (window != NULL && window->window != NULL)
+ {
+ /* nice busy cursor */
+ GdkCursor *cursor;
+
+ cursor = gdk_cursor_new (GDK_WATCH);
+ gdk_window_set_cursor (window->window, cursor);
+ gdk_cursor_unref (cursor);
+
+ gdk_flush ();
+
+ gdk_window_set_cursor (window->window, NULL);
+
+ /* no flush: this will cause the cursor to be reset
+ * only when the UI is free again */
+ }
+}
+
+static void
+ephy_node_view_selection_changed_cb (GtkTreeSelection *selection,
+ EphyNodeView *view)
+{
+ GList *list;
+ EphyNode *node = NULL;
+
+ list = ephy_node_view_get_selection (view);
+ if (list)
+ {
+ node = EPHY_NODE (list->data);
+ }
+ g_list_free (list);
+
+ g_signal_emit (G_OBJECT (view), ephy_node_view_signals[NODE_SELECTED], 0, node);
+}
+
+static void
+ephy_node_view_row_activated_cb (GtkTreeView *treeview,
+ GtkTreePath *path,
+ GtkTreeViewColumn *column,
+ EphyNodeView *view)
+{
+ GtkTreeIter iter, iter2;
+ EphyNode *node;
+
+ gtk_tree_model_get_iter (view->priv->sortmodel, &iter, path);
+ gtk_tree_model_sort_convert_iter_to_child_iter
+ (GTK_TREE_MODEL_SORT (view->priv->sortmodel), &iter2, &iter);
+ egg_tree_model_filter_convert_iter_to_child_iter
+ (EGG_TREE_MODEL_FILTER (view->priv->filtermodel), &iter, &iter2);
+
+ node = ephy_tree_model_node_node_from_iter (view->priv->nodemodel, &iter);
+
+ g_signal_emit (G_OBJECT (view), ephy_node_view_signals[NODE_ACTIVATED], 0, node);
+}
+
+static gboolean
+ephy_node_view_button_press_cb (GtkTreeView *treeview,
+ GdkEventButton *event,
+ EphyNodeView *view)
+{
+ if (event->button == 3)
+ {
+ g_signal_emit (G_OBJECT (view), ephy_node_view_signals[SHOW_POPUP], 0);
+ }
+
+ return FALSE;
+}
+
+static void
+ephy_node_view_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EphyNodeView *view = EPHY_NODE_VIEW (object);
+
+ switch (prop_id)
+ {
+ case PROP_ROOT:
+ view->priv->root = g_value_get_object (value);
+ break;
+ case PROP_FILTER:
+ view->priv->filter = g_value_get_object (value);
+
+ if (view->priv->filter != NULL)
+ {
+ g_signal_connect_object (G_OBJECT (view->priv->filter),
+ "changed",
+ G_CALLBACK (filter_changed_cb),
+ G_OBJECT (view),
+ 0);
+ }
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+ephy_node_view_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ EphyNodeView *view = EPHY_NODE_VIEW (object);
+
+ switch (prop_id)
+ {
+ case PROP_ROOT:
+ g_value_set_object (value, view->priv->root);
+ break;
+ case PROP_FILTER:
+ g_value_set_object (value, view->priv->filter);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+node_from_sort_iter_cb (EphyTreeModelSort *model,
+ GtkTreeIter *iter,
+ void **node,
+ EphyNodeView *view)
+{
+ GtkTreeIter filter_iter, node_iter;
+
+ gtk_tree_model_sort_convert_iter_to_child_iter (GTK_TREE_MODEL_SORT (model),
+ &filter_iter, iter);
+ egg_tree_model_filter_convert_iter_to_child_iter (EGG_TREE_MODEL_FILTER (view->priv->filtermodel),
+ &node_iter, &filter_iter);
+ *node = ephy_tree_model_node_node_from_iter
+ (EPHY_TREE_MODEL_NODE (view->priv->nodemodel), &node_iter);
+}
+
+static void
+ephy_node_view_construct (EphyNodeView *view)
+{
+ GtkTreeSelection *selection;
+
+
+ view->priv->nodemodel = ephy_tree_model_node_new (view->priv->root,
+ view->priv->filter);
+ view->priv->filtermodel = egg_tree_model_filter_new (GTK_TREE_MODEL (view->priv->nodemodel),
+ NULL);
+ egg_tree_model_filter_set_visible_column (EGG_TREE_MODEL_FILTER (view->priv->filtermodel),
+ EPHY_TREE_MODEL_NODE_COL_VISIBLE);
+ view->priv->sortmodel = ephy_tree_model_sort_new (view->priv->filtermodel);
+ g_signal_connect_object (G_OBJECT (view->priv->sortmodel),
+ "node_from_iter",
+ G_CALLBACK (node_from_sort_iter_cb),
+ view,
+ 0);
+ view->priv->treeview = gtk_tree_view_new_with_model
+ (GTK_TREE_MODEL (view->priv->sortmodel));
+ gtk_widget_show (view->priv->treeview);
+ g_signal_connect_object (G_OBJECT (view->priv->treeview),
+ "button_press_event",
+ G_CALLBACK (ephy_node_view_button_press_cb),
+ view,
+ 0);
+ g_signal_connect_object (G_OBJECT (view->priv->treeview),
+ "row_activated",
+ G_CALLBACK (ephy_node_view_row_activated_cb),
+ view,
+ 0);
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view->priv->treeview));
+ gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
+ g_signal_connect_object (G_OBJECT (selection),
+ "changed",
+ G_CALLBACK (ephy_node_view_selection_changed_cb),
+ view,
+ 0);
+
+ gtk_container_add (GTK_CONTAINER (view), view->priv->treeview);
+}
+
+EphyNodeView *
+ephy_node_view_new (EphyNode *root,
+ EphyNodeFilter *filter)
+{
+ EphyNodeView *view;
+
+ view = EPHY_NODE_VIEW (g_object_new (EPHY_TYPE_NODE_VIEW,
+ "filter", filter,
+ "hadjustment", NULL,
+ "vadjustment", NULL,
+ "hscrollbar_policy", GTK_POLICY_AUTOMATIC,
+ "vscrollbar_policy", GTK_POLICY_AUTOMATIC,
+ "shadow_type", GTK_SHADOW_IN,
+ "root", root,
+ NULL));
+
+ ephy_node_view_construct (view);
+
+ g_return_val_if_fail (view->priv != NULL, NULL);
+
+ return view;
+}
+
+void
+ephy_node_view_add_column (EphyNodeView *view,
+ const char *title,
+ EphyTreeModelNodeColumn column,
+ gboolean sortable)
+{
+ GtkTreeViewColumn *gcolumn;
+ GtkCellRenderer *renderer;
+
+ gcolumn = (GtkTreeViewColumn *) gtk_tree_view_column_new ();
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_tree_view_column_pack_start (gcolumn, renderer, TRUE);
+ gtk_tree_view_column_set_attributes (gcolumn, renderer,
+ "text", column,
+ NULL);
+ gtk_tree_view_column_set_sizing (gcolumn,
+ GTK_TREE_VIEW_COLUMN_AUTOSIZE);
+ gtk_tree_view_column_set_title (gcolumn, title);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (view->priv->treeview),
+ gcolumn);
+ if (sortable)
+ {
+ gtk_tree_view_column_set_sort_column_id (gcolumn, column);
+ }
+}
+
+static void
+ephy_node_view_init (EphyNodeView *view)
+{
+ view->priv = g_new0 (EphyNodeViewPrivate, 1);
+}
+
+static void
+get_selection (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ void **data)
+{
+ GtkTreeModelSort *sortmodel = GTK_TREE_MODEL_SORT (model);
+ EggTreeModelFilter *filtermodel = EGG_TREE_MODEL_FILTER (sortmodel->child_model);
+ EphyTreeModelNode *nodemodel = EPHY_TREE_MODEL_NODE (filtermodel->child_model);
+ GList **list = (GList **) data;
+ GtkTreeIter *iter2 = gtk_tree_iter_copy (iter);
+ GtkTreeIter iter3;
+ GtkTreeIter iter4;
+ EphyNode *node;
+
+ gtk_tree_model_sort_convert_iter_to_child_iter (GTK_TREE_MODEL_SORT (model),
+ &iter3, iter2);
+ egg_tree_model_filter_convert_iter_to_child_iter (filtermodel, &iter4, &iter3);
+
+ node = ephy_tree_model_node_node_from_iter (nodemodel, &iter4);
+
+ gtk_tree_iter_free (iter2);
+
+ *list = g_list_prepend (*list, node);
+}
+
+GList *
+ephy_node_view_get_selection (EphyNodeView *view)
+{
+ GList *list = NULL;
+ GtkTreeSelection *selection;
+
+ selection = gtk_tree_view_get_selection
+ (GTK_TREE_VIEW (view->priv->treeview));
+
+ gtk_tree_selection_selected_foreach (selection,
+ (GtkTreeSelectionForeachFunc) get_selection,
+ (void **) &list);
+
+ return list;
+}
+
+void
+ephy_node_view_remove (EphyNodeView *view)
+{
+ GList *list;
+
+ list = ephy_node_view_get_selection (view);
+
+ for (; list != NULL; list = list->next)
+ {
+ ephy_node_unref (EPHY_NODE (list->data));
+ }
+
+ g_list_free (list);
+}
+
+void
+ephy_node_view_set_browse_mode (EphyNodeView *view)
+{
+ GtkTreeSelection *selection;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view->priv->treeview));
+ gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
+}
+
+void
+ephy_node_view_select_node (EphyNodeView *view,
+ EphyNode *node)
+{
+ GtkTreeIter iter, iter2;
+ GValue val = { 0, };
+ gboolean visible;
+ GtkTreeSelection *selection;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view->priv->treeview));
+
+ g_return_if_fail (node != NULL);
+
+ ephy_tree_model_node_iter_from_node (EPHY_TREE_MODEL_NODE (view->priv->nodemodel),
+ node, &iter);
+ gtk_tree_model_get_value (GTK_TREE_MODEL (view->priv->nodemodel), &iter,
+ EPHY_TREE_MODEL_NODE_COL_VISIBLE, &val);
+ visible = g_value_get_boolean (&val);
+ g_value_unset (&val);
+ if (visible == FALSE) return;
+
+ egg_tree_model_filter_convert_child_iter_to_iter (EGG_TREE_MODEL_FILTER (view->priv->filtermodel),
+ &iter2, &iter);
+ gtk_tree_model_sort_convert_child_iter_to_iter (GTK_TREE_MODEL_SORT (view->priv->sortmodel),
+ &iter, &iter2);
+
+ gtk_tree_selection_select_iter (selection, &iter);
+}
+
+void
+ephy_node_view_enable_drag_source (EphyNodeView *view)
+{
+ g_return_if_fail (view != NULL);
+
+ egg_tree_multi_drag_add_drag_support (GTK_TREE_VIEW (view->priv->treeview));
+ ephy_dnd_enable_model_drag_source (GTK_WIDGET (view->priv->treeview));
+}
diff --git a/src/bookmarks/ephy-node-view.h b/src/bookmarks/ephy-node-view.h
new file mode 100644
index 000000000..71f19d7c7
--- /dev/null
+++ b/src/bookmarks/ephy-node-view.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen <jorn@nl.linux.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Id$
+ */
+
+#ifndef __EPHY_NODE_VIEW_H
+#define __EPHY_NODE_VIEW_H
+
+#include <gtk/gtkscrolledwindow.h>
+#include <gtk/gtkdnd.h>
+
+#include "ephy-tree-model-node.h"
+#include "ephy-node-filter.h"
+
+G_BEGIN_DECLS
+
+#define EPHY_TYPE_NODE_VIEW (ephy_node_view_get_type ())
+#define EPHY_NODE_VIEW(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EPHY_TYPE_NODE_VIEW, EphyNodeView))
+#define EPHY_NODE_VIEW_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EPHY_TYPE_NODE_VIEW, EphyNodeViewClass))
+#define EPHY_IS_NODE_VIEW(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EPHY_TYPE_NODE_VIEW))
+#define EPHY_IS_NODE_VIEW_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EPHY_TYPE_NODE_VIEW))
+#define EPHY_NODE_VIEW_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EPHY_TYPE_NODE_VIEW, EphyNodeViewClass))
+
+typedef struct EphyNodeViewPrivate EphyNodeViewPrivate;
+
+typedef struct
+{
+ GtkScrolledWindow parent;
+
+ EphyNodeViewPrivate *priv;
+} EphyNodeView;
+
+typedef struct
+{
+ GtkScrolledWindowClass parent;
+
+ void (*node_activated) (EphyNodeView *view, EphyNode *node);
+ void (*node_selected) (EphyNodeView *view, EphyNode *node);
+ void (*show_popup) (EphyNodeView *view);
+} EphyNodeViewClass;
+
+GType ephy_node_view_get_type (void);
+
+EphyNodeView *ephy_node_view_new (EphyNode *root,
+ EphyNodeFilter *filter);
+
+void ephy_node_view_enable_dnd (EphyNodeView *view);
+
+void ephy_node_view_add_column (EphyNodeView *view,
+ const char *title,
+ EphyTreeModelNodeColumn column,
+ gboolean sortable);
+
+void ephy_node_view_remove (EphyNodeView *view);
+
+GList *ephy_node_view_get_selection (EphyNodeView *view);
+
+void ephy_node_view_set_browse_mode (EphyNodeView *view);
+
+void ephy_node_view_select_node (EphyNodeView *view,
+ EphyNode *node);
+
+void ephy_node_view_enable_drag_source (EphyNodeView *view);
+
+G_END_DECLS
+
+#endif /* EPHY_NODE_VIEW_H */
diff --git a/src/bookmarks/ephy-tree-model-node.c b/src/bookmarks/ephy-tree-model-node.c
new file mode 100644
index 000000000..d1030d5da
--- /dev/null
+++ b/src/bookmarks/ephy-tree-model-node.c
@@ -0,0 +1,702 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen <jorn@nl.linux.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Id$
+ */
+
+#include <config.h>
+#include <gtk/gtktreeview.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <libgnome/gnome-i18n.h>
+#include <time.h>
+#include <string.h>
+
+#include "ephy-node-filter.h"
+#include "ephy-bookmarks.h"
+#include "ephy-tree-model-node.h"
+#include "ephy-stock-icons.h"
+#include "ephy-node.h"
+
+static void ephy_tree_model_node_class_init (EphyTreeModelNodeClass *klass);
+static void ephy_tree_model_node_init (EphyTreeModelNode *model);
+static void ephy_tree_model_node_finalize (GObject *object);
+static void ephy_tree_model_node_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void ephy_tree_model_node_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+static guint ephy_tree_model_node_get_flags (GtkTreeModel *tree_model);
+static int ephy_tree_model_node_get_n_columns (GtkTreeModel *tree_model);
+static GType ephy_tree_model_node_get_column_type (GtkTreeModel *tree_model,
+ int index);
+static gboolean ephy_tree_model_node_get_iter (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreePath *path);
+static GtkTreePath *ephy_tree_model_node_get_path (GtkTreeModel *tree_model,
+ GtkTreeIter *iter);
+static void ephy_tree_model_node_get_value (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ int column,
+ GValue *value);
+static gboolean ephy_tree_model_node_iter_next (GtkTreeModel *tree_model,
+ GtkTreeIter *iter);
+static gboolean ephy_tree_model_node_iter_children (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreeIter *parent);
+static gboolean ephy_tree_model_node_iter_has_child (GtkTreeModel *tree_model,
+ GtkTreeIter *iter);
+static int ephy_tree_model_node_iter_n_children (GtkTreeModel *tree_model,
+ GtkTreeIter *iter);
+static gboolean ephy_tree_model_node_iter_nth_child (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreeIter *parent,
+ int n);
+static gboolean ephy_tree_model_node_iter_parent (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreeIter *child);
+static void ephy_tree_model_node_tree_model_init (GtkTreeModelIface *iface);
+static void root_child_removed_cb (EphyNode *node,
+ EphyNode *child,
+ EphyTreeModelNode *model);
+static void root_child_added_cb (EphyNode *node,
+ EphyNode *child,
+ EphyTreeModelNode *model);
+static void root_child_changed_cb (EphyNode *node,
+ EphyNode *child,
+ EphyTreeModelNode *model);
+static inline void ephy_tree_model_node_update_node (EphyTreeModelNode *model,
+ EphyNode *node,
+ int idx);
+static void root_destroyed_cb (EphyNode *node,
+ EphyTreeModelNode *model);
+static inline GtkTreePath *get_path_real (EphyTreeModelNode *model,
+ EphyNode *node);
+
+struct EphyTreeModelNodePrivate
+{
+ EphyNode *root;
+
+ EphyNodeFilter *filter;
+};
+
+enum
+{
+ PROP_0,
+ PROP_ROOT,
+ PROP_FILTER
+};
+
+static GObjectClass *parent_class = NULL;
+
+GType
+ephy_tree_model_node_get_type (void)
+{
+ static GType ephy_tree_model_node_type = 0;
+
+ if (ephy_tree_model_node_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (EphyTreeModelNodeClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) ephy_tree_model_node_class_init,
+ NULL,
+ NULL,
+ sizeof (EphyTreeModelNode),
+ 0,
+ (GInstanceInitFunc) ephy_tree_model_node_init
+ };
+
+ static const GInterfaceInfo tree_model_info =
+ {
+ (GInterfaceInitFunc) ephy_tree_model_node_tree_model_init,
+ NULL,
+ NULL
+ };
+
+ ephy_tree_model_node_type = g_type_register_static (G_TYPE_OBJECT,
+ "EphyTreeModelNode",
+ &our_info, 0);
+
+ g_type_add_interface_static (ephy_tree_model_node_type,
+ GTK_TYPE_TREE_MODEL,
+ &tree_model_info);
+ }
+
+ return ephy_tree_model_node_type;
+}
+
+static void
+ephy_tree_model_node_class_init (EphyTreeModelNodeClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = ephy_tree_model_node_finalize;
+
+ object_class->set_property = ephy_tree_model_node_set_property;
+ object_class->get_property = ephy_tree_model_node_get_property;
+
+ g_object_class_install_property (object_class,
+ PROP_ROOT,
+ g_param_spec_object ("root",
+ "Root node",
+ "Root node",
+ EPHY_TYPE_NODE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (object_class,
+ PROP_FILTER,
+ g_param_spec_object ("filter",
+ "Filter object",
+ "Filter object",
+ EPHY_TYPE_NODE_FILTER,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+ephy_tree_model_node_init (EphyTreeModelNode *model)
+{
+ GtkWidget *dummy;
+
+ do
+ {
+ model->stamp = g_random_int ();
+ }
+ while (model->stamp == 0);
+
+ model->priv = g_new0 (EphyTreeModelNodePrivate, 1);
+
+ dummy = gtk_tree_view_new ();
+
+ gtk_widget_destroy (dummy);
+}
+
+static void
+ephy_tree_model_node_finalize (GObject *object)
+{
+ EphyTreeModelNode *model;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (EPHY_IS_TREE_MODEL_NODE (object));
+
+ model = EPHY_TREE_MODEL_NODE (object);
+
+ g_return_if_fail (model->priv != NULL);
+
+ g_free (model->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+filter_changed_cb (EphyNodeFilter *filter,
+ EphyTreeModelNode *model)
+{
+ GPtrArray *kids;
+ int i;
+
+ kids = ephy_node_get_children (model->priv->root);
+
+ for (i = 0; i < kids->len; i++)
+ {
+ ephy_tree_model_node_update_node (model,
+ g_ptr_array_index (kids, i),
+ i);
+ }
+
+ ephy_node_thaw (model->priv->root);
+}
+
+static void
+ephy_tree_model_node_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EphyTreeModelNode *model = EPHY_TREE_MODEL_NODE (object);
+
+ switch (prop_id)
+ {
+ case PROP_ROOT:
+ model->priv->root = g_value_get_object (value);
+
+ g_signal_connect_object (G_OBJECT (model->priv->root),
+ "child_added",
+ G_CALLBACK (root_child_added_cb),
+ G_OBJECT (model),
+ 0);
+ g_signal_connect_object (G_OBJECT (model->priv->root),
+ "child_removed",
+ G_CALLBACK (root_child_removed_cb),
+ G_OBJECT (model),
+ 0);
+ g_signal_connect_object (G_OBJECT (model->priv->root),
+ "child_changed",
+ G_CALLBACK (root_child_changed_cb),
+ G_OBJECT (model),
+ 0);
+ g_signal_connect_object (G_OBJECT (model->priv->root),
+ "destroyed",
+ G_CALLBACK (root_destroyed_cb),
+ G_OBJECT (model),
+ 0);
+
+ break;
+ case PROP_FILTER:
+ model->priv->filter = g_value_get_object (value);
+
+ if (model->priv->filter != NULL)
+ {
+ g_signal_connect_object (G_OBJECT (model->priv->filter),
+ "changed",
+ G_CALLBACK (filter_changed_cb),
+ G_OBJECT (model),
+ 0);
+ }
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+ephy_tree_model_node_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ EphyTreeModelNode *model = EPHY_TREE_MODEL_NODE (object);
+
+ switch (prop_id)
+ {
+ case PROP_ROOT:
+ g_value_set_object (value, model->priv->root);
+ break;
+ case PROP_FILTER:
+ g_value_set_object (value, model->priv->filter);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+EphyTreeModelNode *
+ephy_tree_model_node_new (EphyNode *root,
+ EphyNodeFilter *filter)
+{
+ EphyTreeModelNode *model;
+
+ model = EPHY_TREE_MODEL_NODE (g_object_new (EPHY_TYPE_TREE_MODEL_NODE,
+ "filter", filter,
+ "root", root,
+ NULL));
+
+ g_return_val_if_fail (model->priv != NULL, NULL);
+
+ return model;
+}
+
+static void
+ephy_tree_model_node_tree_model_init (GtkTreeModelIface *iface)
+{
+ iface->get_flags = ephy_tree_model_node_get_flags;
+ iface->get_n_columns = ephy_tree_model_node_get_n_columns;
+ iface->get_column_type = ephy_tree_model_node_get_column_type;
+ iface->get_iter = ephy_tree_model_node_get_iter;
+ iface->get_path = ephy_tree_model_node_get_path;
+ iface->get_value = ephy_tree_model_node_get_value;
+ iface->iter_next = ephy_tree_model_node_iter_next;
+ iface->iter_children = ephy_tree_model_node_iter_children;
+ iface->iter_has_child = ephy_tree_model_node_iter_has_child;
+ iface->iter_n_children = ephy_tree_model_node_iter_n_children;
+ iface->iter_nth_child = ephy_tree_model_node_iter_nth_child;
+ iface->iter_parent = ephy_tree_model_node_iter_parent;
+}
+
+static guint
+ephy_tree_model_node_get_flags (GtkTreeModel *tree_model)
+{
+ return 0;
+}
+
+static int
+ephy_tree_model_node_get_n_columns (GtkTreeModel *tree_model)
+{
+ return EPHY_TREE_MODEL_NODE_NUM_COLUMNS;
+}
+
+static GType
+ephy_tree_model_node_get_column_type (GtkTreeModel *tree_model,
+ int index)
+{
+ g_return_val_if_fail (EPHY_IS_TREE_MODEL_NODE (tree_model), G_TYPE_INVALID);
+ g_return_val_if_fail ((index < EPHY_TREE_MODEL_NODE_NUM_COLUMNS) && (index >= 0), G_TYPE_INVALID);
+
+ switch (index)
+ {
+ case EPHY_TREE_MODEL_NODE_COL_BOOKMARK:
+ case EPHY_TREE_MODEL_NODE_COL_LOCATION:
+ case EPHY_TREE_MODEL_NODE_COL_KEYWORD:
+ return G_TYPE_STRING;
+ case EPHY_TREE_MODEL_NODE_COL_VISIBLE:
+ return G_TYPE_BOOLEAN;
+ default:
+ g_assert_not_reached ();
+ return G_TYPE_INVALID;
+ }
+}
+
+static gboolean
+ephy_tree_model_node_get_iter (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreePath *path)
+{
+ EphyTreeModelNode *model = EPHY_TREE_MODEL_NODE (tree_model);
+ int i;
+
+ g_return_val_if_fail (EPHY_IS_TREE_MODEL_NODE (model), FALSE);
+ g_return_val_if_fail (gtk_tree_path_get_depth (path) > 0, FALSE);
+
+ if (model->priv->root == NULL)
+ return FALSE;
+
+ i = gtk_tree_path_get_indices (path)[0];
+
+ iter->stamp = model->stamp;
+ iter->user_data = ephy_node_get_nth_child (model->priv->root, i);
+
+ if (iter->user_data == NULL)
+ {
+ iter->stamp = 0;
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static inline GtkTreePath *
+get_path_real (EphyTreeModelNode *model,
+ EphyNode *node)
+{
+ GtkTreePath *retval;
+
+ retval = gtk_tree_path_new ();
+ gtk_tree_path_append_index (retval, ephy_node_get_child_index (model->priv->root, node));
+
+ return retval;
+}
+
+static GtkTreePath *
+ephy_tree_model_node_get_path (GtkTreeModel *tree_model,
+ GtkTreeIter *iter)
+{
+ EphyTreeModelNode *model = EPHY_TREE_MODEL_NODE (tree_model);
+ EphyNode *node;
+
+ g_return_val_if_fail (EPHY_IS_TREE_MODEL_NODE (tree_model), NULL);
+ g_return_val_if_fail (iter != NULL, NULL);
+ g_return_val_if_fail (iter->user_data != NULL, NULL);
+ g_return_val_if_fail (iter->stamp == model->stamp, NULL);
+
+ if (model->priv->root == NULL)
+ return NULL;
+
+ node = EPHY_NODE (iter->user_data);
+
+ if (node == model->priv->root)
+ return gtk_tree_path_new ();
+
+ return get_path_real (model, node);
+}
+
+static void
+ephy_tree_model_node_get_value (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ int column,
+ GValue *value)
+{
+ EphyTreeModelNode *model = EPHY_TREE_MODEL_NODE (tree_model);
+ EphyNode *node;
+
+ g_return_if_fail (EPHY_IS_TREE_MODEL_NODE (tree_model));
+ g_return_if_fail (iter != NULL);
+ g_return_if_fail (iter->stamp == model->stamp);
+ g_return_if_fail (EPHY_IS_NODE (iter->user_data));
+ g_return_if_fail (column < EPHY_TREE_MODEL_NODE_NUM_COLUMNS);
+
+ if (model->priv->root == NULL)
+ return;
+
+ node = EPHY_NODE (iter->user_data);
+
+ switch (column)
+ {
+ case EPHY_TREE_MODEL_NODE_COL_BOOKMARK:
+ ephy_node_get_property (node,
+ EPHY_NODE_BMK_PROP_TITLE,
+ value);
+ break;
+ case EPHY_TREE_MODEL_NODE_COL_LOCATION:
+ ephy_node_get_property (node,
+ EPHY_NODE_BMK_PROP_LOCATION,
+ value);
+ break;
+ case EPHY_TREE_MODEL_NODE_COL_KEYWORD:
+ ephy_node_get_property (node,
+ EPHY_NODE_KEYWORD_PROP_NAME,
+ value);
+ break;
+ case EPHY_TREE_MODEL_NODE_COL_VISIBLE:
+ g_value_init (value, G_TYPE_BOOLEAN);
+
+ if (model->priv->filter != NULL)
+ {
+ g_value_set_boolean (value,
+ ephy_node_filter_evaluate (model->priv->filter, node));
+ }
+ else
+ {
+ g_value_set_boolean (value, TRUE);
+ }
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+}
+
+static gboolean
+ephy_tree_model_node_iter_next (GtkTreeModel *tree_model,
+ GtkTreeIter *iter)
+{
+ EphyTreeModelNode *model = EPHY_TREE_MODEL_NODE (tree_model);
+ EphyNode *node;
+
+ g_return_val_if_fail (iter != NULL, FALSE);
+ g_return_val_if_fail (iter->user_data != NULL, FALSE);
+ g_return_val_if_fail (iter->stamp == EPHY_TREE_MODEL_NODE (tree_model)->stamp, FALSE);
+
+ if (model->priv->root == NULL)
+ return FALSE;
+
+ node = EPHY_NODE (iter->user_data);
+
+ if (node == model->priv->root)
+ return FALSE;
+
+ iter->user_data = ephy_node_get_next_child (model->priv->root, node);
+
+ return (iter->user_data != NULL);
+}
+
+static gboolean
+ephy_tree_model_node_iter_children (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreeIter *parent)
+{
+ EphyTreeModelNode *model = EPHY_TREE_MODEL_NODE (tree_model);
+
+ if (model->priv->root == NULL)
+ return FALSE;
+
+ if (parent != NULL)
+ return FALSE;
+
+ iter->stamp = model->stamp;
+ iter->user_data = model->priv->root;
+
+ return TRUE;
+}
+
+static gboolean
+ephy_tree_model_node_iter_has_child (GtkTreeModel *tree_model,
+ GtkTreeIter *iter)
+{
+ return FALSE;
+}
+
+static int
+ephy_tree_model_node_iter_n_children (GtkTreeModel *tree_model,
+ GtkTreeIter *iter)
+{
+ EphyTreeModelNode *model = EPHY_TREE_MODEL_NODE (tree_model);
+
+ g_return_val_if_fail (EPHY_IS_TREE_MODEL_NODE (tree_model), -1);
+
+ if (model->priv->root == NULL)
+ return 0;
+
+ if (iter == NULL)
+ return ephy_node_get_n_children (model->priv->root);
+
+ g_return_val_if_fail (model->stamp == iter->stamp, -1);
+
+ return 0;
+}
+
+static gboolean
+ephy_tree_model_node_iter_nth_child (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreeIter *parent,
+ int n)
+{
+ EphyTreeModelNode *model = EPHY_TREE_MODEL_NODE (tree_model);
+ EphyNode *node;
+
+ g_return_val_if_fail (EPHY_IS_TREE_MODEL_NODE (tree_model), FALSE);
+
+ if (model->priv->root == NULL)
+ return FALSE;
+
+ if (parent != NULL)
+ return FALSE;
+
+ node = ephy_node_get_nth_child (model->priv->root, n);
+
+ if (node != NULL)
+ {
+ iter->stamp = model->stamp;
+ iter->user_data = node;
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+static gboolean
+ephy_tree_model_node_iter_parent (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreeIter *child)
+{
+ return FALSE;
+}
+
+EphyNode *
+ephy_tree_model_node_node_from_iter (EphyTreeModelNode *model,
+ GtkTreeIter *iter)
+{
+ return EPHY_NODE (iter->user_data);
+}
+
+void
+ephy_tree_model_node_iter_from_node (EphyTreeModelNode *model,
+ EphyNode *node,
+ GtkTreeIter *iter)
+{
+ iter->stamp = model->stamp;
+ iter->user_data = node;
+}
+
+static void
+root_child_removed_cb (EphyNode *node,
+ EphyNode *child,
+ EphyTreeModelNode *model)
+{
+ GtkTreePath *path;
+
+ path = get_path_real (model, child);
+ gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path);
+ gtk_tree_path_free (path);
+}
+
+static void
+root_child_added_cb (EphyNode *node,
+ EphyNode *child,
+ EphyTreeModelNode *model)
+{
+ GtkTreePath *path;
+ GtkTreeIter iter;
+
+ ephy_tree_model_node_iter_from_node (model, child, &iter);
+
+ path = get_path_real (model, child);
+ gtk_tree_model_row_inserted (GTK_TREE_MODEL (model), path, &iter);
+ gtk_tree_path_free (path);
+}
+
+static inline void
+ephy_tree_model_node_update_node (EphyTreeModelNode *model,
+ EphyNode *node,
+ int idx)
+{
+ GtkTreePath *path;
+ GtkTreeIter iter;
+
+ ephy_tree_model_node_iter_from_node (model, node, &iter);
+
+ if (idx >= 0)
+ {
+ path = gtk_tree_path_new ();
+ gtk_tree_path_append_index (path, idx);
+ }
+ else
+ {
+ path = get_path_real (model, node);
+ }
+
+ gtk_tree_model_row_changed (GTK_TREE_MODEL (model), path, &iter);
+ gtk_tree_path_free (path);
+}
+
+static void
+root_child_changed_cb (EphyNode *node,
+ EphyNode *child,
+ EphyTreeModelNode *model)
+{
+ ephy_tree_model_node_update_node (model, child, -1);
+}
+
+static void
+root_destroyed_cb (EphyNode *node,
+ EphyTreeModelNode *model)
+{
+ model->priv->root = NULL;
+
+ /* no need to do other stuff since we should have had a bunch of child_removed
+ * signals already */
+}
+
+GType
+ephy_tree_model_node_column_get_type (void)
+{
+ static GType etype = 0;
+
+ if (etype == 0)
+ {
+ static const GEnumValue values[] =
+ {
+ { EPHY_TREE_MODEL_NODE_COL_BOOKMARK, "EPHY_TREE_MODEL_NODE_COL_BOOKMARK", "bookmark" },
+ { EPHY_TREE_MODEL_NODE_COL_LOCATION, "EPHY_TREE_MODEL_NODE_COL_LOCATION", "location" },
+ { EPHY_TREE_MODEL_NODE_COL_KEYWORD, "EPHY_TREE_MODEL_NODE_COL_KEYWORD", "keyword" },
+ { EPHY_TREE_MODEL_NODE_COL_VISIBLE, "EPHY_TREE_MODEL_NODE_COL_VISIBLE", "visible" },
+
+ { 0, 0, 0 }
+ };
+
+ etype = g_enum_register_static ("EphyTreeModelNodeColumn", values);
+ }
+
+ return etype;
+}
+
diff --git a/src/bookmarks/ephy-tree-model-node.h b/src/bookmarks/ephy-tree-model-node.h
new file mode 100644
index 000000000..a48bc6ad5
--- /dev/null
+++ b/src/bookmarks/ephy-tree-model-node.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen <jorn@nl.linux.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Id$
+ */
+
+#ifndef __EPHY_TREE_MODEL_NODE_H
+#define __EPHY_TREE_MODEL_NODE_H
+
+#include <gtk/gtktreemodel.h>
+
+#include "ephy-node.h"
+#include "ephy-node-filter.h"
+
+G_BEGIN_DECLS
+
+#define EPHY_TYPE_TREE_MODEL_NODE (ephy_tree_model_node_get_type ())
+#define EPHY_TREE_MODEL_NODE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EPHY_TYPE_TREE_MODEL_NODE, EphyTreeModelNode))
+#define EPHY_TREE_MODEL_NODE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EPHY_TYPE_TREE_MODEL_NODE, EphyTreeModelNodeClass))
+#define EPHY_IS_TREE_MODEL_NODE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EPHY_TYPE_TREE_MODEL_NODE))
+#define EPHY_IS_TREE_MODEL_NODE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EPHY_TYPE_TREE_MODEL_NODE))
+#define EPHY_TREE_MODEL_NODE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EPHY_TYPE_TREE_MODEL_NODE, EphyTreeModelNodeClass))
+
+typedef enum
+{
+ EPHY_TREE_MODEL_NODE_COL_BOOKMARK,
+ EPHY_TREE_MODEL_NODE_COL_LOCATION,
+ EPHY_TREE_MODEL_NODE_COL_KEYWORD,
+ EPHY_TREE_MODEL_NODE_COL_VISIBLE,
+ EPHY_TREE_MODEL_NODE_NUM_COLUMNS
+} EphyTreeModelNodeColumn;
+
+GType ephy_tree_model_node_column_get_type (void);
+
+#define EPHY_TYPE_TREE_MODEL_NODE_COLUMN (ephy_tree_model_node_column_get_type ())
+
+typedef struct EphyTreeModelNodePrivate EphyTreeModelNodePrivate;
+
+typedef struct
+{
+ GObject parent;
+
+ EphyTreeModelNodePrivate *priv;
+
+ int stamp;
+} EphyTreeModelNode;
+
+typedef struct
+{
+ GObjectClass parent;
+} EphyTreeModelNodeClass;
+
+GType ephy_tree_model_node_get_type (void);
+
+EphyTreeModelNode *ephy_tree_model_node_new (EphyNode *root,
+ EphyNodeFilter *filter);
+
+EphyNode *ephy_tree_model_node_node_from_iter (EphyTreeModelNode *model,
+ GtkTreeIter *iter);
+
+void ephy_tree_model_node_iter_from_node (EphyTreeModelNode *model,
+ EphyNode *node,
+ GtkTreeIter *iter);
+
+G_END_DECLS
+
+#endif /* EPHY_TREE_MODEL_NODE_H */
diff --git a/src/ephy-automation.c b/src/ephy-automation.c
new file mode 100644
index 000000000..d7757fe75
--- /dev/null
+++ b/src/ephy-automation.c
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "ephy-automation.h"
+#include "ephy-shell.h"
+#include "EphyAutomation.h"
+#include "ephy-embed.h"
+#include "ephy-window.h"
+
+#include <string.h>
+#include <bonobo/bonobo-generic-factory.h>
+#include <bonobo/bonobo-main.h>
+#include <bonobo/bonobo-context.h>
+
+static CORBA_boolean
+impl_ephy_automation_add_bookmark (PortableServer_Servant _servant,
+ const CORBA_char * url,
+ CORBA_Environment * ev);
+static CORBA_boolean
+impl_ephy_automation_quit (PortableServer_Servant _servant,
+ const CORBA_boolean disableServer,
+ CORBA_Environment * ev);
+static CORBA_boolean
+impl_ephy_automation_load_session (PortableServer_Servant _servant,
+ const CORBA_char * filename,
+ CORBA_Environment * ev);
+static void
+ephy_automation_class_init (EphyAutomationClass *klass);
+static void
+ephy_automation_init (EphyAutomation *a);
+static void
+ephy_automation_object_finalize (GObject *object);
+static BonoboObject *
+ephy_automation_factory (BonoboGenericFactory *this_factory,
+ const char *iid,
+ gpointer user_data);
+
+static GObjectClass *ephy_automation_parent_class;
+
+#define EPHY_FACTORY_OAFIID "OAFIID:GNOME_Epiphany_Automation_Factory"
+
+static BonoboObject *
+ephy_automation_factory (BonoboGenericFactory *this_factory,
+ const char *iid,
+ gpointer user_data)
+{
+ EphyAutomation *a;
+
+ a = g_object_new (EPHY_AUTOMATION_TYPE, NULL);
+
+ return BONOBO_OBJECT(a);
+}
+
+BonoboObject *
+ephy_automation_new (void)
+{
+ BonoboGenericFactory *factory;
+
+ factory = bonobo_generic_factory_new (EPHY_FACTORY_OAFIID,
+ ephy_automation_factory,
+ NULL);
+
+ g_return_val_if_fail (factory != NULL, NULL);
+
+ return BONOBO_OBJECT (factory);
+}
+
+static CORBA_boolean
+impl_ephy_automation_loadurl (PortableServer_Servant _servant,
+ const CORBA_char * url,
+ const CORBA_char * geometry,
+ const CORBA_boolean fullscreen,
+ const CORBA_boolean open_in_existing_tab,
+ const CORBA_boolean open_in_new_window,
+ const CORBA_boolean open_in_new_tab,
+ const CORBA_boolean raise,
+ CORBA_Environment * ev)
+{
+ EphyNewTabFlags flags = 0;
+ const char *load_page = NULL;
+ EphyWindow *window;
+ Session *session;
+
+ session = ephy_shell_get_session (ephy_shell);
+
+ /* no window open, let's try to autoresume */
+ if (session_get_windows (session) == NULL)
+ {
+ gboolean res;
+ res = session_autoresume (session);
+ /* no need to open the homepage,
+ * we did already open session windows */
+ if (res && *url == '\0') return TRUE;
+ }
+
+ window = ephy_shell_get_active_window (ephy_shell);
+
+ if (open_in_existing_tab && window != NULL)
+ {
+ ephy_window_load_url (window, url);
+ return TRUE;
+ }
+
+ if (*url == '\0')
+ {
+ flags = EPHY_NEW_TAB_HOMEPAGE;
+ }
+ else
+ {
+ load_page = url;
+ }
+
+ if (open_in_new_window)
+ {
+ flags |= EPHY_NEW_TAB_IN_NEW_WINDOW;
+ }
+
+ if (open_in_new_tab)
+ {
+ flags |= EPHY_NEW_TAB_IN_EXISTING_WINDOW;
+ }
+
+ ephy_shell_new_tab (ephy_shell, window, NULL, load_page,
+ flags);
+
+ return TRUE;
+}
+
+static CORBA_boolean
+impl_ephy_automation_add_bookmark (PortableServer_Servant _servant,
+ const CORBA_char * url,
+ CORBA_Environment * ev)
+{
+ CORBA_boolean retval = TRUE;
+ return retval;
+}
+
+static CORBA_boolean
+impl_ephy_automation_quit (PortableServer_Servant _servant,
+ const CORBA_boolean disableServer,
+ CORBA_Environment * ev)
+{
+ CORBA_boolean retval = TRUE;
+
+ Session *session;
+
+ session = ephy_shell_get_session (ephy_shell);
+
+ session_close (session);
+
+ return retval;
+}
+
+static CORBA_boolean
+impl_ephy_automation_load_session (PortableServer_Servant _servant,
+ const CORBA_char * filename,
+ CORBA_Environment * ev)
+{
+ CORBA_boolean retval = TRUE;
+ Session *session;
+
+ session = ephy_shell_get_session (ephy_shell);
+ session_load (session, filename);
+
+ return retval;
+}
+
+static void
+ephy_automation_class_init (EphyAutomationClass *klass)
+{
+ GObjectClass *object_class = (GObjectClass *) klass;
+ POA_GNOME_EphyAutomation__epv *epv = &klass->epv;
+
+ ephy_automation_parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = ephy_automation_object_finalize;
+
+ /* connect implementation callbacks */
+ epv->loadurl = impl_ephy_automation_loadurl;
+ epv->addBookmark = impl_ephy_automation_add_bookmark;
+ epv->quit = impl_ephy_automation_quit;
+ epv->loadSession = impl_ephy_automation_load_session;
+}
+
+static void
+ephy_automation_init (EphyAutomation *c)
+{
+}
+
+static void
+ephy_automation_object_finalize (GObject *object)
+{
+ EphyAutomation *a = EPHY_AUTOMATION (object);
+
+ ephy_automation_parent_class->finalize (G_OBJECT (a));
+}
+
+BONOBO_TYPE_FUNC_FULL (
+ EphyAutomation,
+ GNOME_EphyAutomation,
+ BONOBO_TYPE_OBJECT,
+ ephy_automation);
diff --git a/src/ephy-automation.h b/src/ephy-automation.h
new file mode 100644
index 000000000..4b3701605
--- /dev/null
+++ b/src/ephy-automation.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _EPHY_AUTOMATION_H_
+#define _EPHY_AUTOMATION_H_
+
+#include "EphyAutomation.h"
+
+#include <bonobo/bonobo-control.h>
+#include <bonobo/bonobo-object.h>
+
+G_BEGIN_DECLS
+
+#define EPHY_AUTOMATION_TYPE (ephy_automation_get_type ())
+#define EPHY_AUTOMATION(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EPHY_AUTOMATION_TYPE, EphyAutomation))
+#define EPHY_AUTOMATION_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EPHY_AUTOMATION_TYPE, EphyAutomationClass))
+#define EPHY_AUTOMATION_IS_OBJECT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EPHY_AUTOMATION_TYPE))
+#define EPHY_AUTOMATION_IS_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EPHY_AUTOMATION_TYPE))
+#define EPHY_AUTOMATION_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EPHY_AUTOMATION_TYPE, EphyAutomationClass))
+
+typedef struct {
+ BonoboObject parent;
+} EphyAutomation;
+
+typedef struct {
+ BonoboObjectClass parent_class;
+
+ POA_GNOME_EphyAutomation__epv epv;
+} EphyAutomationClass;
+
+GType ephy_automation_get_type (void);
+
+BonoboObject *ephy_automation_new (void);
+
+G_END_DECLS
+
+#endif /* _EPHY_AUTOMATION_H_ */
diff --git a/src/ephy-favorites-menu.c b/src/ephy-favorites-menu.c
new file mode 100644
index 000000000..d8f44f852
--- /dev/null
+++ b/src/ephy-favorites-menu.c
@@ -0,0 +1,275 @@
+/*
+ * Copyright (C) 2002 Ricardo Fernández Pascual
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "ephy-favorites-menu.h"
+#include "ephy-gobject-misc.h"
+#include "ephy-string.h"
+#include "ephy-bonobo-extensions.h"
+#include "ephy-marshal.h"
+#include "ephy-shell.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <libxml/entities.h>
+
+#define NOT_IMPLEMENTED g_warning ("not implemented: " G_STRLOC);
+//#define DEBUG_MSG(x) g_print x
+#define DEBUG_MSG(x)
+
+#define MAX_LABEL_LENGTH 30
+
+/**
+ * Private data
+ */
+struct _EphyFavoritesMenuPrivate
+{
+ gchar *path;
+ EphyWindow *window;
+ EphyBookmarks *bookmarks;
+};
+
+typedef struct
+{
+ EphyWindow *window;
+ const char *url;
+} FavoriteData;
+
+/**
+ * Private functions, only availble from this file
+ */
+static void ephy_favorites_menu_class_init (EphyFavoritesMenuClass *klass);
+static void ephy_favorites_menu_init (EphyFavoritesMenu *wrhm);
+static void ephy_favorites_menu_finalize_impl (GObject *o);
+static void ephy_favorites_menu_rebuild (EphyFavoritesMenu *wrhm);
+static void ephy_favorites_menu_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void ephy_favorites_menu_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+enum
+{
+ PROP_0,
+ PROP_EPHY_WINDOW
+};
+
+static gpointer g_object_class;
+
+/**
+ * EphyFavoritesMenu object
+ */
+MAKE_GET_TYPE (ephy_favorites_menu,
+ "EphyFavoritesMenu", EphyFavoritesMenu,
+ ephy_favorites_menu_class_init, ephy_favorites_menu_init,
+ G_TYPE_OBJECT);
+
+static void
+ephy_favorites_menu_class_init (EphyFavoritesMenuClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ G_OBJECT_CLASS (klass)->finalize = ephy_favorites_menu_finalize_impl;
+ g_object_class = g_type_class_peek_parent (klass);
+
+ object_class->set_property = ephy_favorites_menu_set_property;
+ object_class->get_property = ephy_favorites_menu_get_property;
+
+ g_object_class_install_property (object_class,
+ PROP_EPHY_WINDOW,
+ g_param_spec_object ("EphyWindow",
+ "EphyWindow",
+ "Parent window",
+ EPHY_WINDOW_TYPE,
+ G_PARAM_READWRITE));
+}
+
+static void
+ephy_favorites_menu_init (EphyFavoritesMenu *wrhm)
+{
+ EphyFavoritesMenuPrivate *p = g_new0 (EphyFavoritesMenuPrivate, 1);
+ wrhm->priv = p;
+
+ wrhm->priv->bookmarks = ephy_shell_get_bookmarks (ephy_shell);
+}
+
+static void
+ephy_favorites_menu_finalize_impl (GObject *o)
+{
+ EphyFavoritesMenu *wrhm = EPHY_FAVORITES_MENU (o);
+ EphyFavoritesMenuPrivate *p = wrhm->priv;
+
+ if (p->path)
+ {
+ g_free (p->path);
+ }
+
+ g_free (p);
+
+ G_OBJECT_CLASS (g_object_class)->finalize (o);
+}
+
+static void
+ephy_favorites_menu_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EphyFavoritesMenu *m = EPHY_FAVORITES_MENU (object);
+
+ switch (prop_id)
+ {
+ case PROP_EPHY_WINDOW:
+ m->priv->window = g_value_get_object (value);
+ break;
+ }
+}
+
+static void
+ephy_favorites_menu_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ EphyFavoritesMenu *m = EPHY_FAVORITES_MENU (object);
+
+ switch (prop_id)
+ {
+ case PROP_EPHY_WINDOW:
+ g_value_set_object (value, m->priv->window);
+ break;
+ }
+}
+
+EphyFavoritesMenu *
+ephy_favorites_menu_new (EphyWindow *window)
+{
+ EphyFavoritesMenu *ret = g_object_new (EPHY_TYPE_FAVORITES_MENU,
+ "EphyWindow", window,
+ NULL);
+ return ret;
+}
+
+void
+ephy_favorites_menu_set_path (EphyFavoritesMenu *wrhm,
+ const gchar *path)
+{
+ EphyFavoritesMenuPrivate *p;
+
+ g_return_if_fail (EPHY_IS_FAVORITES_MENU (wrhm));
+ g_return_if_fail (path != NULL);
+
+ p = wrhm->priv;
+
+ if (p->path)
+ {
+ g_free (p->path);
+ }
+ p->path = g_strdup (path);
+
+ ephy_favorites_menu_update (wrhm);
+}
+
+static void
+ephy_favorites_menu_verb_cb (BonoboUIComponent *uic,
+ FavoriteData *data,
+ const char *cname)
+{
+ ephy_window_load_url (data->window, data->url);
+}
+
+static void
+ephy_favorites_menu_rebuild (EphyFavoritesMenu *wrhm)
+{
+ EphyFavoritesMenuPrivate *p = wrhm->priv;
+ GString *xml;
+ gint i;
+ EphyNode *fav;
+ GPtrArray *children;
+ BonoboUIComponent *uic = BONOBO_UI_COMPONENT (p->window->ui_component);
+
+ if (!p->path) return;
+
+ ephy_bonobo_clear_path (uic, p->path);
+
+ DEBUG_MSG (("Rebuilding recent history menu\n"));
+
+ fav = ephy_bookmarks_get_favorites (p->bookmarks);
+ children = ephy_node_get_children (fav);
+
+ xml = g_string_new (NULL);
+ g_string_append_printf (xml, "<placeholder name=\"wrhm%x\">\n", (guint) wrhm);
+
+ for (i = 0; i < children->len; i++)
+ {
+ char *verb = g_strdup_printf ("Wrhm%xn%d", (guint) wrhm, i);
+ char *title_s;
+ const char *title;
+ const char *url;
+ xmlChar *label_x;
+ EphyNode *child;
+ FavoriteData *data;
+
+ child = g_ptr_array_index (children, i);
+ title = ephy_node_get_property_string (child, EPHY_NODE_BMK_PROP_TITLE);
+ url = ephy_node_get_property_string (child, EPHY_NODE_BMK_PROP_LOCATION);
+ title_s = ephy_string_shorten (title, MAX_LABEL_LENGTH);
+ label_x = xmlEncodeSpecialChars (NULL, title_s);
+
+ g_string_append (xml, "<menuitem name=\"");
+ g_string_append (xml, verb);
+ g_string_append (xml, "\" label=\"");
+ g_string_append (xml, label_x);
+ g_string_append (xml, "\" verb=\"");
+ g_string_append (xml, verb);
+ g_string_append (xml, "\"/>\n");
+
+ data = g_new0 (FavoriteData, 1);
+ data->window = wrhm->priv->window;
+ data->url = url;
+ bonobo_ui_component_add_verb_full (uic, verb, g_cclosure_new
+ (G_CALLBACK (ephy_favorites_menu_verb_cb), data,
+ (GClosureNotify)g_free));
+
+ xmlFree (label_x);
+ g_free (title_s);
+ g_free (verb);
+ }
+
+ ephy_node_thaw (fav);
+
+ g_string_append (xml, "</placeholder>\n");
+ DEBUG_MSG (("\n%s\n", xml->str));
+ if (children->len > 0)
+ {
+ bonobo_ui_component_set (uic, p->path,
+ xml->str, NULL);
+ }
+ g_string_free (xml, TRUE);
+}
+
+void ephy_favorites_menu_update (EphyFavoritesMenu *wrhm)
+{
+ ephy_favorites_menu_rebuild (wrhm);
+}
diff --git a/src/ephy-favorites-menu.h b/src/ephy-favorites-menu.h
new file mode 100644
index 000000000..b76e8d2d8
--- /dev/null
+++ b/src/ephy-favorites-menu.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2002 Ricardo Fernández Pascual
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EPHY_FAVORITES_MENU_H
+#define EPHY_FAVORITES_MENU_H
+
+#include "ephy-window.h"
+
+#include <bonobo/bonobo-ui-component.h>
+
+/* object forward declarations */
+
+typedef struct _EphyFavoritesMenu EphyFavoritesMenu;
+typedef struct _EphyFavoritesMenuClass EphyFavoritesMenuClass;
+typedef struct _EphyFavoritesMenuPrivate EphyFavoritesMenuPrivate;
+
+/**
+ * Editor object
+ */
+
+#define EPHY_TYPE_FAVORITES_MENU (ephy_favorites_menu_get_type())
+#define EPHY_FAVORITES_MENU(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EPHY_TYPE_FAVORITES_MENU, EphyFavoritesMenu))
+#define EPHY_FAVORITES_MENU_CLASS(klass)(G_TYPE_CHECK_CLASS_CAST((klass), EPHY_TYPE_FAVORITES_MENU, EphyFavoritesMenuClass))
+#define EPHY_IS_FAVORITES_MENU(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EPHY_TYPE_FAVORITES_MENU))
+#define EPHY_IS_FAVORITES_MENU_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), EPHY_TYPE_FAVORITES_MENU))
+#define EPHY_FAVORITES_MENU_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EPHY_TYPE_FAVORITES_MENU, EphyFavoritesMenuClass))
+
+struct _EphyFavoritesMenuClass
+{
+ GObjectClass parent_class;
+};
+
+/* Remember: fields are public read-only */
+struct _EphyFavoritesMenu
+{
+ GObject parent_object;
+
+ EphyFavoritesMenuPrivate *priv;
+};
+
+GType ephy_favorites_menu_get_type (void);
+
+EphyFavoritesMenu *ephy_favorites_menu_new (EphyWindow *window);
+
+void ephy_favorites_menu_update (EphyFavoritesMenu *wrhm);
+
+void ephy_favorites_menu_set_path (EphyFavoritesMenu *wrhm,
+ const gchar *path);
+
+#endif
+
diff --git a/src/ephy-history-model.c b/src/ephy-history-model.c
new file mode 100644
index 000000000..c4e694bcd
--- /dev/null
+++ b/src/ephy-history-model.c
@@ -0,0 +1,838 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen <jorn@nl.linux.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Id$
+ */
+
+#include <config.h>
+#include <gtk/gtktreeview.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <libgnome/gnome-i18n.h>
+#include <time.h>
+#include <string.h>
+
+#include "ephy-node-filter.h"
+#include "ephy-history-model.h"
+#include "ephy-history.h"
+#include "ephy-tree-model-node.h"
+#include "ephy-stock-icons.h"
+#include "ephy-node.h"
+
+static void ephy_history_model_class_init (EphyHistoryModelClass *klass);
+static void ephy_history_model_init (EphyHistoryModel *model);
+static void ephy_history_model_finalize (GObject *object);
+static void ephy_history_model_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void ephy_history_model_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+static guint ephy_history_model_get_flags (GtkTreeModel *tree_model);
+static int ephy_history_model_get_n_columns (GtkTreeModel *tree_model);
+static GType ephy_history_model_get_column_type (GtkTreeModel *tree_model,
+ int index);
+static gboolean ephy_history_model_get_iter (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreePath *path);
+static GtkTreePath *ephy_history_model_get_path (GtkTreeModel *tree_model,
+ GtkTreeIter *iter);
+static void ephy_history_model_get_value (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ int column,
+ GValue *value);
+static gboolean ephy_history_model_iter_next (GtkTreeModel *tree_model,
+ GtkTreeIter *iter);
+static gboolean ephy_history_model_iter_children (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreeIter *parent);
+static gboolean ephy_history_model_iter_has_child (GtkTreeModel *tree_model,
+ GtkTreeIter *iter);
+static int ephy_history_model_iter_n_children (GtkTreeModel *tree_model,
+ GtkTreeIter *iter);
+static gboolean ephy_history_model_iter_nth_child (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreeIter *parent,
+ int n);
+static gboolean ephy_history_model_iter_parent (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreeIter *child);
+static void ephy_history_model_tree_model_init (GtkTreeModelIface *iface);
+static void root_child_removed_cb (EphyNode *node,
+ EphyNode *child,
+ EphyHistoryModel *model);
+static void root_child_added_cb (EphyNode *node,
+ EphyNode *child,
+ EphyHistoryModel *model);
+static void root_child_changed_cb (EphyNode *node,
+ EphyNode *child,
+ EphyHistoryModel *model);
+static inline void ephy_history_model_update_node (EphyHistoryModel *model,
+ EphyNode *node,
+ int idx);
+
+struct EphyHistoryModelPrivate
+{
+ EphyNode *root;
+ EphyNode *pages;
+
+ EphyNodeFilter *filter;
+};
+
+enum
+{
+ PROP_0,
+ PROP_ROOT,
+ PROP_PAGES,
+ PROP_FILTER
+};
+
+static GObjectClass *parent_class = NULL;
+
+GType
+ephy_history_model_get_type (void)
+{
+ static GType ephy_history_model_type = 0;
+
+ if (ephy_history_model_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (EphyHistoryModelClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) ephy_history_model_class_init,
+ NULL,
+ NULL,
+ sizeof (EphyHistoryModel),
+ 0,
+ (GInstanceInitFunc) ephy_history_model_init
+ };
+
+ static const GInterfaceInfo tree_model_info =
+ {
+ (GInterfaceInitFunc) ephy_history_model_tree_model_init,
+ NULL,
+ NULL
+ };
+
+ ephy_history_model_type = g_type_register_static (G_TYPE_OBJECT,
+ "EphyHistoryModel",
+ &our_info, 0);
+
+ g_type_add_interface_static (ephy_history_model_type,
+ GTK_TYPE_TREE_MODEL,
+ &tree_model_info);
+ }
+
+ return ephy_history_model_type;
+}
+
+static void
+ephy_history_model_class_init (EphyHistoryModelClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = ephy_history_model_finalize;
+
+ object_class->set_property = ephy_history_model_set_property;
+ object_class->get_property = ephy_history_model_get_property;
+
+ g_object_class_install_property (object_class,
+ PROP_ROOT,
+ g_param_spec_object ("root",
+ "Root node",
+ "Root node",
+ EPHY_TYPE_NODE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (object_class,
+ PROP_PAGES,
+ g_param_spec_object ("pages",
+ "Pages node",
+ "Pages node",
+ EPHY_TYPE_NODE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+ g_object_class_install_property (object_class,
+ PROP_FILTER,
+ g_param_spec_object ("filter",
+ "Filter object",
+ "Filter object",
+ EPHY_TYPE_NODE_FILTER,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+ephy_history_model_init (EphyHistoryModel *model)
+{
+ GtkWidget *dummy;
+
+ do
+ {
+ model->stamp = g_random_int ();
+ }
+ while (model->stamp == 0);
+
+ model->priv = g_new0 (EphyHistoryModelPrivate, 1);
+
+ dummy = gtk_tree_view_new ();
+
+ gtk_widget_destroy (dummy);
+}
+
+static void
+ephy_history_model_finalize (GObject *object)
+{
+ EphyHistoryModel *model;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (EPHY_IS_HISTORY_MODEL (object));
+
+ model = EPHY_HISTORY_MODEL (object);
+
+ g_return_if_fail (model->priv != NULL);
+
+ g_free (model->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+filter_changed_cb (EphyNodeFilter *filter,
+ EphyHistoryModel *model)
+{
+ GPtrArray *kids;
+ int i;
+
+ kids = ephy_node_get_children (model->priv->root);
+
+ for (i = 0; i < kids->len; i++)
+ {
+ ephy_history_model_update_node (model,
+ g_ptr_array_index (kids, i),
+ i);
+ }
+
+ ephy_node_thaw (model->priv->root);
+}
+
+static void
+ephy_history_model_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EphyHistoryModel *model = EPHY_HISTORY_MODEL (object);
+
+ switch (prop_id)
+ {
+ case PROP_ROOT:
+ model->priv->root = g_value_get_object (value);
+ g_signal_connect_object (G_OBJECT (model->priv->root),
+ "child_added",
+ G_CALLBACK (root_child_added_cb),
+ G_OBJECT (model),
+ 0);
+ g_signal_connect_object (G_OBJECT (model->priv->root),
+ "child_removed",
+ G_CALLBACK (root_child_removed_cb),
+ G_OBJECT (model),
+ 0);
+ g_signal_connect_object (G_OBJECT (model->priv->root),
+ "child_changed",
+ G_CALLBACK (root_child_changed_cb),
+ G_OBJECT (model),
+ 0);
+ break;
+ case PROP_PAGES:
+ model->priv->pages = g_value_get_object (value);
+ g_signal_connect_object (G_OBJECT (model->priv->pages),
+ "child_added",
+ G_CALLBACK (root_child_added_cb),
+ G_OBJECT (model),
+ 0);
+ g_signal_connect_object (G_OBJECT (model->priv->pages),
+ "child_removed",
+ G_CALLBACK (root_child_removed_cb),
+ G_OBJECT (model),
+ 0);
+ g_signal_connect_object (G_OBJECT (model->priv->pages),
+ "child_changed",
+ G_CALLBACK (root_child_changed_cb),
+ G_OBJECT (model),
+ 0);
+ break;
+ case PROP_FILTER:
+ model->priv->filter = g_value_get_object (value);
+
+ if (model->priv->filter != NULL)
+ {
+ g_signal_connect_object (G_OBJECT (model->priv->filter),
+ "changed",
+ G_CALLBACK (filter_changed_cb),
+ G_OBJECT (model),
+ 0);
+ }
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+ephy_history_model_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ EphyHistoryModel *model = EPHY_HISTORY_MODEL (object);
+
+ switch (prop_id)
+ {
+ case PROP_ROOT:
+ g_value_set_object (value, model->priv->root);
+ break;
+ case PROP_PAGES:
+ g_value_set_object (value, model->priv->root);
+ break;
+ case PROP_FILTER:
+ g_value_set_object (value, model->priv->filter);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+EphyHistoryModel *
+ephy_history_model_new (EphyNode *root,
+ EphyNode *pages,
+ EphyNodeFilter *filter)
+{
+ EphyHistoryModel *model;
+
+ model = EPHY_HISTORY_MODEL (g_object_new (EPHY_TYPE_HISTORY_MODEL,
+ "filter", filter,
+ "root", root,
+ "pages", pages,
+ NULL));
+
+ g_return_val_if_fail (model->priv != NULL, NULL);
+
+ return model;
+}
+
+static void
+ephy_history_model_tree_model_init (GtkTreeModelIface *iface)
+{
+ iface->get_flags = ephy_history_model_get_flags;
+ iface->get_n_columns = ephy_history_model_get_n_columns;
+ iface->get_column_type = ephy_history_model_get_column_type;
+ iface->get_iter = ephy_history_model_get_iter;
+ iface->get_path = ephy_history_model_get_path;
+ iface->get_value = ephy_history_model_get_value;
+ iface->iter_next = ephy_history_model_iter_next;
+ iface->iter_children = ephy_history_model_iter_children;
+ iface->iter_has_child = ephy_history_model_iter_has_child;
+ iface->iter_n_children = ephy_history_model_iter_n_children;
+ iface->iter_nth_child = ephy_history_model_iter_nth_child;
+ iface->iter_parent = ephy_history_model_iter_parent;
+}
+
+static guint
+ephy_history_model_get_flags (GtkTreeModel *tree_model)
+{
+ return 0;
+}
+
+static int
+ephy_history_model_get_n_columns (GtkTreeModel *tree_model)
+{
+ return EPHY_HISTORY_MODEL_NUM_COLUMNS;
+}
+
+static GType
+ephy_history_model_get_column_type (GtkTreeModel *tree_model,
+ int index)
+{
+ g_return_val_if_fail (EPHY_IS_HISTORY_MODEL (tree_model), G_TYPE_INVALID);
+ g_return_val_if_fail ((index < EPHY_HISTORY_MODEL_NUM_COLUMNS) && (index >= 0), G_TYPE_INVALID);
+
+ switch (index)
+ {
+ case EPHY_HISTORY_MODEL_COL_TITLE:
+ case EPHY_HISTORY_MODEL_COL_LOCATION:
+ case EPHY_HISTORY_MODEL_COL_VISITS:
+ case EPHY_HISTORY_MODEL_COL_LAST_VISIT:
+ case EPHY_HISTORY_MODEL_COL_FIRST_VISIT:
+ return G_TYPE_STRING;
+ case EPHY_HISTORY_MODEL_COL_VISIBLE:
+ return G_TYPE_BOOLEAN;
+ default:
+ g_assert_not_reached ();
+ return G_TYPE_INVALID;
+ }
+}
+
+static gboolean
+ephy_history_model_get_iter (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreePath *path)
+{
+ EphyHistoryModel *model = EPHY_HISTORY_MODEL (tree_model);
+ gint *indices;
+ gint depth;
+ EphyNode *host;
+
+ g_return_val_if_fail (EPHY_IS_HISTORY_MODEL (model), FALSE);
+
+ indices = gtk_tree_path_get_indices (path);
+ depth = gtk_tree_path_get_depth (path);
+
+ g_return_val_if_fail (depth > 0, FALSE);
+
+ iter->stamp = model->stamp;
+ host = ephy_node_get_nth_child (model->priv->root, indices [0]);
+
+ if (depth == 2 && host != NULL)
+ {
+ iter->user_data = ephy_node_get_nth_child (host, indices [1]);
+ }
+ else
+ {
+ iter->user_data = host;
+ }
+
+ if (iter->user_data == NULL)
+ {
+ iter->stamp = 0;
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static EphyNode *
+ensure_iter (EphyHistoryModel *model, GtkTreeIter *parent)
+{
+ EphyNode *node;
+
+ if (parent)
+ {
+ node = EPHY_NODE (parent->user_data);
+ }
+ else
+ {
+ node = model->priv->root;
+ }
+
+ return node;
+}
+
+static EphyNode *
+get_parent_node (EphyHistoryModel *model, EphyNode *node)
+{
+ int host_id;
+
+ host_id = ephy_node_get_property_int (node, EPHY_NODE_PAGE_PROP_HOST_ID);
+
+ if (host_id < 0)
+ {
+ return model->priv->root;
+ }
+ else
+ {
+ EphyNode *host;
+ host = ephy_node_get_from_id (host_id);
+ return host;
+ }
+}
+
+static inline GtkTreePath *
+get_one_level_path_real (EphyHistoryModel *model,
+ EphyNode *node)
+{
+ GtkTreePath *retval;
+ EphyNode *my_parent;
+
+ retval = gtk_tree_path_new ();
+
+ my_parent = get_parent_node (model, node);
+
+ gtk_tree_path_append_index (retval, ephy_node_get_child_index (my_parent, node));
+
+ return retval;
+}
+
+static inline GtkTreePath *
+get_path_real (EphyHistoryModel *model,
+ EphyNode *page)
+{
+ GtkTreePath *retval;
+ EphyNode *host;
+
+ retval = gtk_tree_path_new ();
+ host = get_parent_node (model, page);
+
+ gtk_tree_path_append_index (retval, ephy_node_get_child_index (model->priv->root, host));
+ gtk_tree_path_append_index (retval, ephy_node_get_child_index (host, page));
+
+ return retval;
+}
+
+static GtkTreePath *
+ephy_history_model_get_path (GtkTreeModel *tree_model,
+ GtkTreeIter *iter)
+{
+ EphyHistoryModel *model = EPHY_HISTORY_MODEL (tree_model);
+ EphyNode *node;
+
+ g_return_val_if_fail (EPHY_IS_HISTORY_MODEL (tree_model), NULL);
+ g_return_val_if_fail (iter != NULL, NULL);
+ g_return_val_if_fail (iter->user_data != NULL, NULL);
+ g_return_val_if_fail (iter->stamp == model->stamp, NULL);
+
+ node = EPHY_NODE (iter->user_data);
+
+ if (node == model->priv->root)
+ return gtk_tree_path_new ();
+
+ return get_one_level_path_real (model, node);
+}
+
+static void
+get_property_as_date (EphyNode *node,
+ int id,
+ GValue *value)
+{
+ GTime time;
+ char s[50];
+ GDate *date;
+
+ time = ephy_node_get_property_int (node, id);
+ date = g_date_new ();
+ g_date_set_time (date, time);
+ g_date_strftime (s, 50, "%c", date);
+
+ g_value_init (value, G_TYPE_STRING);
+ g_value_set_string (value, s);
+
+ g_date_free (date);
+}
+
+static void
+ephy_history_model_get_value (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ int column,
+ GValue *value)
+{
+ EphyHistoryModel *model = EPHY_HISTORY_MODEL (tree_model);
+ EphyNode *node;
+
+ g_return_if_fail (EPHY_IS_HISTORY_MODEL (tree_model));
+ g_return_if_fail (iter != NULL);
+ g_return_if_fail (iter->stamp == model->stamp);
+ g_return_if_fail (EPHY_IS_NODE (iter->user_data));
+ g_return_if_fail (column < EPHY_HISTORY_MODEL_NUM_COLUMNS);
+
+ node = EPHY_NODE (iter->user_data);
+
+ if (ephy_node_get_property_int (node, EPHY_NODE_PAGE_PROP_HOST_ID) < 0 &&
+ (column == EPHY_HISTORY_MODEL_COL_LOCATION ||
+ column == EPHY_HISTORY_MODEL_COL_FIRST_VISIT ||
+ column == EPHY_HISTORY_MODEL_COL_LAST_VISIT ||
+ column == EPHY_HISTORY_MODEL_COL_VISITS))
+ {
+ g_value_init (value, G_TYPE_STRING);
+ g_value_set_string (value, "");
+ return;
+ }
+
+ switch (column)
+ {
+ case EPHY_HISTORY_MODEL_COL_TITLE:
+ ephy_node_get_property (node,
+ EPHY_NODE_PAGE_PROP_TITLE,
+ value);
+ break;
+ case EPHY_HISTORY_MODEL_COL_LOCATION:
+ ephy_node_get_property (node,
+ EPHY_NODE_PAGE_PROP_LOCATION,
+ value);
+ break;
+ case EPHY_HISTORY_MODEL_COL_VISITS:
+ ephy_node_get_property (node,
+ EPHY_NODE_PAGE_PROP_VISITS,
+ value);
+ break;
+ case EPHY_HISTORY_MODEL_COL_FIRST_VISIT:
+ get_property_as_date (node,
+ EPHY_NODE_PAGE_PROP_FIRST_VISIT,
+ value);
+ break;
+ case EPHY_HISTORY_MODEL_COL_LAST_VISIT:
+ get_property_as_date (node,
+ EPHY_NODE_PAGE_PROP_LAST_VISIT,
+ value);
+ break;
+ case EPHY_HISTORY_MODEL_COL_VISIBLE:
+ g_value_init (value, G_TYPE_BOOLEAN);
+
+ if (model->priv->filter != NULL)
+ {
+ g_value_set_boolean (value,
+ ephy_node_filter_evaluate (model->priv->filter, node));
+ }
+ else
+ {
+ g_value_set_boolean (value, TRUE);
+ }
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+}
+
+static gboolean
+ephy_history_model_iter_next (GtkTreeModel *tree_model,
+ GtkTreeIter *iter)
+{
+ EphyHistoryModel *model = EPHY_HISTORY_MODEL (tree_model);
+ EphyNode *node;
+
+ g_return_val_if_fail (iter != NULL, FALSE);
+ g_return_val_if_fail (iter->user_data != NULL, FALSE);
+ g_return_val_if_fail (iter->stamp == EPHY_HISTORY_MODEL (tree_model)->stamp, FALSE);
+
+ node = EPHY_NODE (iter->user_data);
+
+ iter->user_data = ephy_node_get_next_child
+ (get_parent_node (model, node), node);
+
+ return (iter->user_data != NULL);
+}
+
+static gboolean
+ephy_history_model_iter_children (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreeIter *parent)
+{
+ EphyHistoryModel *model = EPHY_HISTORY_MODEL (tree_model);
+ EphyNode *node;
+
+ node = ensure_iter (model, parent);
+
+ iter->user_data = ephy_node_get_nth_child (node, 0);
+ iter->stamp = model->stamp;
+
+ return (iter->user_data != NULL);
+}
+
+static gboolean
+ephy_history_model_iter_has_child (GtkTreeModel *tree_model,
+ GtkTreeIter *iter)
+{
+ EphyHistoryModel *model = EPHY_HISTORY_MODEL (tree_model);
+ EphyNode *node;
+ int host_id;
+
+ node = EPHY_NODE (iter->user_data);
+ host_id = ephy_node_get_property_int (node, EPHY_NODE_PAGE_PROP_HOST_ID);
+ if (host_id < 0)
+ {
+ return ephy_node_has_child (model->priv->root, node);
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+static int
+ephy_history_model_iter_n_children (GtkTreeModel *tree_model,
+ GtkTreeIter *iter)
+{
+ EphyHistoryModel *model = EPHY_HISTORY_MODEL (tree_model);
+ EphyNode *node;
+
+ g_return_val_if_fail (iter == NULL || iter->user_data != NULL, FALSE);
+
+ node = ensure_iter (model, iter);
+
+ return ephy_node_get_n_children (node);
+}
+
+static gboolean
+ephy_history_model_iter_nth_child (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreeIter *parent,
+ int n)
+{
+ EphyHistoryModel *model = EPHY_HISTORY_MODEL (tree_model);
+ EphyNode *node;
+
+ node = ensure_iter (model, parent);
+
+ iter->user_data = ephy_node_get_nth_child (node, n);
+ iter->stamp = model->stamp;
+
+ return (iter->user_data != NULL);
+}
+
+static gboolean
+ephy_history_model_iter_parent (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreeIter *child)
+{
+ EphyHistoryModel *model = EPHY_HISTORY_MODEL (tree_model);
+ EphyNode *parent, *node;
+
+ node = EPHY_NODE (iter->user_data);
+ parent = get_parent_node (model, node);
+
+ if (parent != model->priv->root)
+ {
+ iter->user_data = parent;
+ iter->stamp = model->stamp;
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+EphyNode *
+ephy_history_model_node_from_iter (EphyHistoryModel *model,
+ GtkTreeIter *iter)
+{
+ return EPHY_NODE (iter->user_data);
+}
+
+void
+ephy_history_model_iter_from_node (EphyHistoryModel *model,
+ EphyNode *node,
+ GtkTreeIter *iter)
+{
+ iter->stamp = model->stamp;
+ iter->user_data = node;
+}
+
+static inline void
+ephy_history_model_update_node (EphyHistoryModel *model,
+ EphyNode *node,
+ int idx)
+{
+ GtkTreePath *path;
+ GtkTreeIter iter;
+
+ ephy_history_model_iter_from_node (model, node, &iter);
+
+ if (idx >= 0)
+ {
+ path = gtk_tree_path_new ();
+ gtk_tree_path_append_index (path, idx);
+ }
+ else
+ {
+ path = get_one_level_path_real (model, node);
+ }
+
+ gtk_tree_model_row_changed (GTK_TREE_MODEL (model), path, &iter);
+ gtk_tree_path_free (path);
+}
+
+static void
+root_child_removed_cb (EphyNode *node,
+ EphyNode *child,
+ EphyHistoryModel *model)
+{
+ GtkTreePath *path;
+
+ if (node == model->priv->root)
+ {
+ path = get_one_level_path_real (model, child);
+ }
+ else
+ {
+ path = get_path_real (model, child);
+ }
+ gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path);
+ gtk_tree_path_free (path);
+}
+
+static void
+root_child_added_cb (EphyNode *node,
+ EphyNode *child,
+ EphyHistoryModel *model)
+{
+ GtkTreePath *path;
+ GtkTreeIter iter;
+
+ ephy_history_model_iter_from_node (model, child, &iter);
+
+ if (node == model->priv->root)
+ {
+ path = get_one_level_path_real (model, child);
+ }
+ else
+ {
+ path = get_path_real (model, child);
+ }
+
+ gtk_tree_model_row_inserted (GTK_TREE_MODEL (model), path, &iter);
+ gtk_tree_path_free (path);
+}
+
+static void
+root_child_changed_cb (EphyNode *node,
+ EphyNode *child,
+ EphyHistoryModel *model)
+{
+ ephy_history_model_update_node (model, child, -1);
+}
+
+GType
+ephy_history_model_column_get_type (void)
+{
+ static GType etype = 0;
+
+ if (etype == 0)
+ {
+ static const GEnumValue values[] =
+ {
+ { EPHY_HISTORY_MODEL_COL_TITLE, "EPHY_HISTORY_MODEL_COL_TITLE", "title" },
+ { EPHY_HISTORY_MODEL_COL_LOCATION, "EPHY_HISTORY_MODEL_COL_LOCATION", "location" },
+ { EPHY_HISTORY_MODEL_COL_VISITS, "EPHY_HISTORY_MODEL_COL_VISITS", "visits" },
+ { EPHY_HISTORY_MODEL_COL_FIRST_VISIT, "EPHY_HISTORY_MODEL_COL_FIRST_VISIT", "last_visit" },
+ { EPHY_HISTORY_MODEL_COL_LAST_VISIT, "EPHY_HISTORY_MODEL_COL_LAST_VISIT", "last_visit" },
+ { EPHY_HISTORY_MODEL_COL_VISIBLE, "EPHY_HISTORY_MODEL_COL_FIRST_VISIT", "first_visit" },
+
+ { 0, 0, 0 }
+ };
+
+ etype = g_enum_register_static ("EphyHistoryModelColumn", values);
+ }
+
+ return etype;
+}
+
diff --git a/src/ephy-history-model.h b/src/ephy-history-model.h
new file mode 100644
index 000000000..6ff0058de
--- /dev/null
+++ b/src/ephy-history-model.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen <jorn@nl.linux.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Id$
+ */
+
+#ifndef __EPHY_HISTORY_MODEL_H
+#define __EPHY_HISTORY_MODEL_H
+
+#include <gtk/gtktreemodel.h>
+
+#include "ephy-node.h"
+#include "ephy-node-filter.h"
+
+G_BEGIN_DECLS
+
+#define EPHY_TYPE_HISTORY_MODEL (ephy_history_model_get_type ())
+#define EPHY_HISTORY_MODEL(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EPHY_TYPE_HISTORY_MODEL, EphyHistoryModel))
+#define EPHY_HISTORY_MODEL_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EPHY_TYPE_HISTORY_MODEL, EphyHistoryModelClass))
+#define EPHY_IS_HISTORY_MODEL(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EPHY_TYPE_HISTORY_MODEL))
+#define EPHY_IS_HISTORY_MODEL_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EPHY_TYPE_HISTORY_MODEL))
+#define EPHY_HISTORY_MODEL_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EPHY_TYPE_HISTORY_MODEL, EphyHistoryModelClass))
+
+typedef enum
+{
+ EPHY_HISTORY_MODEL_COL_TITLE,
+ EPHY_HISTORY_MODEL_COL_LOCATION,
+ EPHY_HISTORY_MODEL_COL_VISITS,
+ EPHY_HISTORY_MODEL_COL_FIRST_VISIT,
+ EPHY_HISTORY_MODEL_COL_LAST_VISIT,
+ EPHY_HISTORY_MODEL_COL_VISIBLE,
+ EPHY_HISTORY_MODEL_NUM_COLUMNS
+} EphyHistoryModelColumn;
+
+GType ephy_history_model_column_get_type (void);
+
+#define EPHY_TYPE_HISTORY_MODEL_COLUMN (ephy_history_model_column_get_type ())
+
+typedef struct EphyHistoryModelPrivate EphyHistoryModelPrivate;
+
+typedef struct
+{
+ GObject parent;
+
+ EphyHistoryModelPrivate *priv;
+
+ int stamp;
+} EphyHistoryModel;
+
+typedef struct
+{
+ GObjectClass parent;
+} EphyHistoryModelClass;
+
+GType ephy_history_model_get_type (void);
+
+EphyHistoryModel *ephy_history_model_new (EphyNode *root,
+ EphyNode *pages,
+ EphyNodeFilter *filter);
+
+EphyNode *ephy_history_model_node_from_iter (EphyHistoryModel *model,
+ GtkTreeIter *iter);
+
+void ephy_history_model_iter_from_node (EphyHistoryModel *model,
+ EphyNode *node,
+ GtkTreeIter *iter);
+
+G_END_DECLS
+
+#endif /* EPHY_HISTORY_MODEL_H */
diff --git a/src/ephy-main.c b/src/ephy-main.c
new file mode 100644
index 000000000..0a0093974
--- /dev/null
+++ b/src/ephy-main.c
@@ -0,0 +1,340 @@
+/*
+ * Copyright (C) 2000-2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "ephy-shell.h"
+#include "ephy-automation.h"
+#include "ephy-window.h"
+#include "EphyAutomation.h"
+
+#include <libbonoboui.h>
+#include <libgnome/gnome-program.h>
+#include <libgnomeui/gnome-ui-init.h>
+#include <libgnomeui/gnome-window-icon.h>
+#include <libgnomevfs/gnome-vfs-init.h>
+#include <glade/glade-init.h>
+
+#define EPHY_FACTORY_OAFIID "OAFIID:GNOME_Epiphany_Automation_Factory"
+
+static gboolean
+ephy_main_automation_init (void);
+static gint
+ephy_main_translate_url_arguments (poptContext context, gchar ***urls);
+static gboolean
+ephy_main_start (gpointer data);
+
+GnomeProgram *program;
+CORBA_Environment corba_env; /* Global for downloader */
+static gboolean open_in_existing = FALSE; /* load in existing window? */
+static gboolean open_in_new_tab = FALSE; /* force open in a new tab? */
+static gboolean noraise = FALSE; /* no raise */
+static gboolean open_in_new_window = FALSE; /* force open in a new window? */
+static gboolean open_fullscreen = FALSE; /* open ephy in full screen ? */
+static gchar *session_filename = NULL; /* the session filename */
+static gchar *geometry_string = NULL; /* the geometry string */
+static gchar *bookmark_url = NULL; /* the temp bookmark to add */
+static gboolean close_option = FALSE; /* --close */
+static gboolean quit_option = FALSE; /* --quit */
+static gboolean ephy_server_mode = FALSE;
+static gboolean open_as_nautilus_view = FALSE;
+
+static BonoboObject *automation_object;
+static gint n_urls;
+static gchar **url;
+static gboolean first_instance;
+
+/* command line argument parsing structure */
+static struct poptOption popt_options[] =
+{
+ { NULL, '\0', POPT_ARG_INCLUDE_TABLE, &bonobo_activation_popt_options, 0, NULL,
+ NULL },
+ { "new-tab", 'n', POPT_ARG_NONE, &open_in_new_tab, 0,
+ N_("Open a new tab in an existing Ephy window"),
+ NULL },
+ { "new-window", 'w', POPT_ARG_NONE, &open_in_new_window, 0,
+ N_("Open a new window in an existing Ephy process"),
+ NULL },
+ { "noraise", '\0', POPT_ARG_NONE, &noraise, 0,
+ N_("Do not raise the window when opening a page in an existing Ephy process"),
+ NULL },
+ { "fullscreen", 'f', POPT_ARG_NONE, &open_fullscreen, 0,
+ N_("Run Ephy in full screen mode"),
+ NULL },
+ { "existing", 'x', POPT_ARG_NONE, &open_in_existing, 0,
+ N_("Attempt to load URL in existing Ephy window"),
+ NULL },
+ { "load-session", 'l', POPT_ARG_STRING, &session_filename, 0,
+ N_("Load the given session file"),
+ N_("FILE") },
+ { "server", 's', POPT_ARG_NONE, &ephy_server_mode, 0,
+ N_("Don't open any windows; instead act as a server "
+ "for quick startup of new Ephy instances"),
+ NULL },
+ { "add-bookmark", 't', POPT_ARG_STRING, &bookmark_url,
+ 0, N_("Add a bookmark (don't open any window)"),
+ N_("URL")},
+ { "geometry", 'g', POPT_ARG_STRING, &geometry_string,
+ 0, N_("Create the initial window with the given geometry.\n"
+ "see X(1) for the GEOMETRY format"),
+ N_("GEOMETRY")},
+ { "close", 'c', POPT_ARG_NONE, &close_option, 0,
+ N_("Close all Ephy windows"),
+ NULL },
+ { "quit", 'q', POPT_ARG_NONE, &quit_option, 0,
+ N_("Same as --close, but exits server mode too"),
+ NULL },
+ { "nautilus-view", 'v', POPT_ARG_NONE, &open_as_nautilus_view, 0,
+ N_("Used internally by the nautilus view"),
+ NULL },
+
+ /* terminator, must be last */
+ { NULL, 0, 0, NULL, 0, NULL, NULL }
+};
+
+int
+main (int argc, char *argv[])
+{
+ poptContext context;
+ GValue context_as_value = { 0 };
+ GnomeProgram *program;
+
+#ifdef ENABLE_NLS
+ /* Initialize the i18n stuff */
+ bindtextdomain(GETTEXT_PACKAGE, GNOMELOCALEDIR);
+ bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
+ textdomain(GETTEXT_PACKAGE);
+#endif
+
+ program = gnome_program_init (PACKAGE, VERSION,
+ LIBGNOMEUI_MODULE, argc, argv,
+ GNOME_PARAM_POPT_TABLE, popt_options,
+ GNOME_PARAM_HUMAN_READABLE_NAME, _("Ephy"),
+ GNOME_PARAM_APP_DATADIR, DATADIR,
+ NULL);
+
+ g_object_get_property (G_OBJECT (program),
+ GNOME_PARAM_POPT_CONTEXT,
+ g_value_init (&context_as_value, G_TYPE_POINTER));
+
+ context = g_value_get_pointer (&context_as_value);
+
+ /* load arguments that aren't regular options (urls to load) */
+ n_urls = ephy_main_translate_url_arguments (context, &url);
+
+ first_instance = ephy_main_automation_init ();
+
+ if (first_instance)
+ {
+ gnome_vfs_init ();
+
+ glade_gnome_init ();
+
+ gnome_window_icon_set_default_from_file (PIXMAP_DIR "/ephy.png");
+
+ ephy_shell_new ();
+
+ g_idle_add ((GSourceFunc) ephy_main_start, NULL);
+
+ bonobo_main ();
+
+ gnome_vfs_shutdown ();
+ }
+
+ return 0;
+}
+
+static gboolean
+ephy_main_start (gpointer data)
+{
+ GNOME_EphyAutomation gaserver;
+ int i;
+
+ CORBA_exception_init (&corba_env);
+
+ gaserver = bonobo_activation_activate_from_id ("OAFIID:GNOME_Epiphany_Automation",
+ 0, NULL, &corba_env);
+
+ if (gaserver == NULL)
+ {
+ GtkWidget *dialog;
+ dialog = gtk_message_dialog_new
+ (NULL,
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE,
+ "Ephy can't be used now. "
+ "Running the command \"bonobo-slay\" "
+ "from the console may fix the problem. If not, "
+ "you can try rebooting the computer or "
+ "installing Ephy again.\n\n"
+ "Bonobo couldn't locate the GNOME_Epiphany_Automation.server. ");
+ gtk_dialog_run (GTK_DIALOG (dialog));
+
+ }
+ /* FIXME ephy --server doesnt work when not first istance */
+ /* Server mode */
+ else if (ephy_server_mode)
+ {
+ g_object_ref (G_OBJECT(ephy_shell));
+ }
+ /* load the session if requested */
+ else if (session_filename)
+ {
+ GNOME_EphyAutomation_loadSession
+ (gaserver, session_filename, &corba_env);
+ }
+ /* if found and we're given a bookmark to add... */
+ else if (bookmark_url != NULL)
+ {
+ GNOME_EphyAutomation_addBookmark
+ (gaserver, bookmark_url, &corba_env);
+ }
+ else if (close_option || quit_option)
+ {
+ GNOME_EphyAutomation_quit
+ (gaserver, quit_option, &corba_env);
+ }
+ /* provided with urls? */
+ else if (n_urls == 0 &&
+ !open_as_nautilus_view)
+ {
+ /* no, open a default window */
+ GNOME_EphyAutomation_loadurl
+ (gaserver, "",
+ geometry_string ?
+ geometry_string : "",
+ open_fullscreen,
+ open_in_existing,
+ open_in_new_window,
+ open_in_new_tab,
+ !noraise,
+ &corba_env);
+ }
+ else
+ {
+ /* open all of the urls */
+ for (i = 0; i < n_urls; i++)
+ {
+ GNOME_EphyAutomation_loadurl
+ (gaserver, url[i],
+ geometry_string ?
+ geometry_string : "",
+ open_fullscreen,
+ open_in_existing,
+ open_in_new_window,
+ open_in_new_tab,
+ !noraise,
+ &corba_env);
+ }
+ }
+
+ /* Unref so it will exit if no more used */
+ if (first_instance)
+ {
+ g_object_unref (G_OBJECT(ephy_shell));
+ }
+
+ if (gaserver)
+ {
+ bonobo_object_release_unref (gaserver, &corba_env);
+ }
+
+ CORBA_exception_free (&corba_env);
+
+ return FALSE;
+}
+
+static gboolean
+ephy_main_automation_init (void)
+{
+ CORBA_Object factory;
+
+ factory = bonobo_activation_activate_from_id
+ (EPHY_FACTORY_OAFIID,
+ Bonobo_ACTIVATION_FLAG_EXISTING_ONLY,
+ NULL, NULL);
+
+ if (!factory)
+ {
+ automation_object = ephy_automation_new ();
+ return TRUE;
+ }
+ else
+ {
+ ephy_main_start (NULL);
+ g_message (_("Ephy already running, using existing process"));
+ return FALSE;
+ }
+}
+
+/**
+ * translate_url_arguments: gather URL arguments and expand them fully
+ * with realpath if they're filenames
+ */
+static gint
+ephy_main_translate_url_arguments (poptContext context, gchar ***urls)
+{
+ gchar buffer[PATH_MAX];
+ gchar **args;
+ gint i, n;
+
+ /* any context remaining? */
+ if (context == NULL)
+ {
+ *urls = NULL;
+ return 0;
+ }
+
+ /* get the args and check */
+ args = (gchar **) poptGetArgs (context);
+ if (args == NULL)
+ {
+ poptFreeContext (context);
+ *urls = NULL;
+ return 0;
+ }
+
+ /* count args */
+ for (n = 0; args[n] != NULL; n++)
+ /* nothing */;
+
+ /* allocate pointer array */
+ *urls = g_new0 (gchar *, n + 1);
+
+ /* translate each one */
+ for (i = 0; i < n; i++)
+ {
+ /* try to expand as files */
+ if (realpath (args[i], buffer) != NULL)
+ {
+ (*urls)[i] = g_strconcat ("file://", buffer, NULL);
+ }
+ else
+ {
+ (*urls)[i] = g_strdup (args[i]);
+ }
+ }
+ poptFreeContext (context);
+ (*urls)[i] = NULL;
+
+ /* return the number of urls */
+ return n;
+}
diff --git a/src/ephy-nautilus-view.c b/src/ephy-nautilus-view.c
new file mode 100644
index 000000000..f7a0ff867
--- /dev/null
+++ b/src/ephy-nautilus-view.c
@@ -0,0 +1,954 @@
+/*
+ * Copyright (C) 2001, 2002 Ricardo Fernández Pascual
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+
+#include <config.h>
+#include <libgnome/gnome-macros.h>
+#include <bonobo/bonobo-zoomable.h>
+#include <bonobo/bonobo-ui-util.h>
+#include <string.h>
+#include "ephy-embed-popup-control.h"
+#include "ephy-nautilus-view.h"
+#include "ephy-embed.h"
+#include "ephy-embed-utils.h"
+#include "find-dialog.h"
+#include "print-dialog.h"
+#include "ephy-prefs.h"
+#include "eel-gconf-extensions.h"
+
+#define NOT_IMPLEMENTED g_warning ("not implemented: " G_STRLOC);
+#define DEBUG_MSG(x) g_print x
+//#define DEBUG_MSG(x)
+
+static void gnv_embed_location_cb (EphyEmbed *embed,
+ EphyNautilusView *view);
+static void gnv_embed_title_cb (EphyEmbed *embed,
+ EphyNautilusView *view);
+static void gnv_embed_new_window_cb (EphyEmbed *embed,
+ EphyEmbed **new_embed,
+ EmbedChromeMask chromemask,
+ EphyNautilusView *view);
+static void gnv_embed_link_message_cb (EphyEmbed *embed,
+ const char *message,
+ EphyNautilusView *view);
+static gint gnv_embed_dom_mouse_down_cb (EphyEmbed *embed,
+ EphyEmbedEvent *event,
+ EphyNautilusView *view);
+static void gnv_embed_zoom_change_cb (EphyNautilusView *embed,
+ guint new_zoom,
+ EphyNautilusView *view);
+
+
+static void gnv_load_location_cb (EphyNautilusView *view,
+ const char *location,
+ gpointer user_data);
+static void gnv_stop_loading_cb (EphyNautilusView *view,
+ gpointer user_data);
+static void gnv_bonobo_control_activate_cb (BonoboControl *control,
+ gboolean state,
+ EphyNautilusView *view);
+
+/* zoomable */
+static void gnv_zoomable_set_zoom_level_cb (BonoboZoomable *zoomable,
+ float level,
+ EphyNautilusView *view);
+static void gnv_zoomable_zoom_in_cb (BonoboZoomable *zoomable,
+ EphyNautilusView *view);
+static void gnv_zoomable_zoom_out_cb (BonoboZoomable *zoomable,
+ EphyNautilusView *view);
+static void gnv_zoomable_zoom_to_fit_cb (BonoboZoomable *zoomable,
+ EphyNautilusView *view);
+static void gnv_zoomable_zoom_to_default_cb (BonoboZoomable *zoomable,
+ EphyNautilusView *view);
+/* commands */
+static void gnv_cmd_set_charset (BonoboUIComponent *uic,
+ EncodingMenuData *data,
+ const char* verbname);
+static void gnv_cmd_file_print (BonoboUIComponent *uic,
+ EphyNautilusView *view,
+ const char* verbname);
+static void gnv_cmd_edit_find (BonoboUIComponent *uic,
+ EphyNautilusView *view,
+ const char* verbname);
+
+
+/* popups */
+static EphyNautilusView *gnv_view_from_popup (EphyEmbedPopup *popup);
+
+static void gnv_popup_cmd_new_window (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname);
+static void gnv_popup_cmd_image_in_new_window (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname);
+static void gnv_popup_cmd_frame_in_new_window (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname);
+
+
+static float preferred_zoom_levels[] = {
+ 0.2, 0.4, 0.6, 0.8,
+ 1.0, 1.2, 1.4, 1.6, 1.8,
+ 2.0, 2.2, 2.4, 2.6, 2.8,
+ 3.0, 3.2, 3.4, 3.6, 3.8,
+ 4.0, 4.2, 4.4, 4.6, 4.8,
+ 5.0, 5.2, 5.4, 5.6, 5.8,
+ 6.0, 6.2, 6.4, 6.6, 6.8,
+ 7.0, 7.2, 7.4, 7.6, 7.8,
+ 8.0, 8.2, 8.4, 8.6, 8.8,
+ 9.0, 9.2, 9.4, 9.6, 9.8,
+};
+
+static const gchar *preferred_zoom_level_names[] = {
+ "20%", "40%", "60%", "80%",
+ "100%", "120%", "140%", "160%", "180%",
+ "200%", "220%", "240%", "260%", "280%",
+ "300%", "320%", "340%", "360%", "380%",
+ "400%", "420%", "440%", "460%", "480%",
+ "500%", "520%", "540%", "560%", "580%",
+ "600%", "620%", "640%", "660%", "680%",
+ "700%", "720%", "740%", "760%", "780%",
+ "800%", "820%", "840%", "860%", "880%",
+ "900%", "920%", "940%", "960%", "980%",
+};
+#define NUM_ZOOM_LEVELS (sizeof (preferred_zoom_levels) / sizeof (float))
+
+struct EphyNautilusViewPrivate {
+ EphyEmbed *embed;
+ char *title;
+ char *location;
+ int load_percent;
+
+ /*
+ BonoboPropertyBag *property_bag;
+ */
+
+ EphyEmbedPopupControl *popup;
+ BonoboUIComponent *popup_ui;
+ BonoboControl *control;
+ BonoboUIComponent *ui;
+ BonoboZoomable *zoomable;
+
+ EphyDialog *find_dialog;
+};
+
+static BonoboUIVerb ephy_popup_verbs [] = {
+ BONOBO_UI_VERB ("EPOpenInNewWindow", (BonoboUIVerbFn) gnv_popup_cmd_new_window),
+ BONOBO_UI_VERB ("EPOpenImageInNewWindow", (BonoboUIVerbFn) gnv_popup_cmd_image_in_new_window),
+ BONOBO_UI_VERB ("DPOpenFrameInNewWindow", (BonoboUIVerbFn) gnv_popup_cmd_frame_in_new_window),
+
+ BONOBO_UI_VERB_END
+};
+
+BonoboUIVerb ephy_verbs [] = {
+ BONOBO_UI_VERB ("FilePrint", (BonoboUIVerbFn) gnv_cmd_file_print),
+ BONOBO_UI_VERB ("EditFind", (BonoboUIVerbFn) gnv_cmd_edit_find),
+ BONOBO_UI_VERB_END
+};
+
+#define CHARSET_MENU_PATH "/menu/View/Encoding"
+
+
+BONOBO_CLASS_BOILERPLATE (EphyNautilusView, ephy_nautilus_view,
+ NautilusView, NAUTILUS_TYPE_VIEW)
+
+static void
+ephy_nautilus_view_instance_init (EphyNautilusView *view)
+{
+ GtkWidget *w;
+ EphyNautilusViewPrivate *p = g_new0 (EphyNautilusViewPrivate, 1);
+
+ view->priv = p;
+ view->priv->embed = ephy_embed_new (G_OBJECT (ephy_shell_get_embed_shell (ephy_shell)));
+
+ g_object_ref (G_OBJECT (ephy_shell));
+
+ g_signal_connect (view->priv->embed, "ge_link_message",
+ GTK_SIGNAL_FUNC (gnv_embed_link_message_cb),
+ view);
+ g_signal_connect (view->priv->embed, "ge_location",
+ GTK_SIGNAL_FUNC (gnv_embed_location_cb),
+ view);
+ g_signal_connect (view->priv->embed, "ge_title",
+ GTK_SIGNAL_FUNC (gnv_embed_title_cb),
+ view);
+/*
+ g_signal_connect (view->priv->embed, "ge_js_status",
+ GTK_SIGNAL_FUNC (gnv_embed_js_status_cb),
+ view);
+ g_signal_connect (view->priv->embed, "ge_progress",
+ GTK_SIGNAL_FUNC (gnv_embed_progress_cb),
+ view);
+ g_signal_connect (view->priv->embed, "ge_net_state",
+ GTK_SIGNAL_FUNC (gnv_embed_net_state_cb),
+ view);
+*/
+ g_signal_connect (view->priv->embed, "ge_new_window",
+ GTK_SIGNAL_FUNC (gnv_embed_new_window_cb),
+ view);
+/*
+ g_signal_connect (view->priv->embed, "ge_visibility",
+ GTK_SIGNAL_FUNC (gnv_embed_visibility_cb),
+ view);
+ g_signal_connect (view->priv->embed, "ge_destroy_brsr",
+ GTK_SIGNAL_FUNC (gnv_embed_destroy_brsr_cb),
+ view);
+ g_signal_connect (view->priv->embed, "ge_open_uri",
+ GTK_SIGNAL_FUNC (gnv_embed_open_uri_cb),
+ view);
+ g_signal_connect (view->priv->embed, "ge_size_to",
+ GTK_SIGNAL_FUNC (gnv_embed_size_to_cb),
+ view);
+ g_signal_connect (view->priv->embed, "ge_dom_mouse_click",
+ GTK_SIGNAL_FUNC (gnv_embed_dom_mouse_click_cb),
+ view);
+*/
+ g_signal_connect (view->priv->embed, "ge_dom_mouse_down",
+ GTK_SIGNAL_FUNC (gnv_embed_dom_mouse_down_cb),
+ view);
+/*
+ g_signal_connect (view->priv->embed, "ge_security_change",
+ GTK_SIGNAL_FUNC (gnv_embed_security_change_cb),
+ view);
+*/
+ g_signal_connect (view->priv->embed, "ge_zoom_change",
+ GTK_SIGNAL_FUNC (gnv_embed_zoom_change_cb),
+ view);
+
+ w = GTK_WIDGET (view->priv->embed);
+ gtk_widget_show (w);
+
+ nautilus_view_construct (NAUTILUS_VIEW (view), w);
+
+ g_signal_connect (G_OBJECT (view), "load_location",
+ G_CALLBACK (gnv_load_location_cb), NULL);
+
+ g_signal_connect (G_OBJECT (view), "stop_loading",
+ G_CALLBACK (gnv_stop_loading_cb), NULL);
+
+ g_signal_connect (G_OBJECT (nautilus_view_get_bonobo_control (NAUTILUS_VIEW (view))),
+ "activate",
+ G_CALLBACK (gnv_bonobo_control_activate_cb), view);
+
+ view->priv->zoomable = bonobo_zoomable_new ();
+ bonobo_object_add_interface (BONOBO_OBJECT (view),
+ BONOBO_OBJECT (view->priv->zoomable));
+
+ bonobo_zoomable_set_parameters_full (view->priv->zoomable,
+ 1.0,
+ preferred_zoom_levels [0],
+ preferred_zoom_levels [NUM_ZOOM_LEVELS - 1],
+ FALSE, FALSE, TRUE,
+ preferred_zoom_levels,
+ preferred_zoom_level_names,
+ NUM_ZOOM_LEVELS);
+
+ bonobo_object_add_interface (BONOBO_OBJECT (view),
+ BONOBO_OBJECT (view->priv->zoomable));
+
+ g_signal_connect (view->priv->zoomable, "set_zoom_level",
+ G_CALLBACK (gnv_zoomable_set_zoom_level_cb), view);
+ g_signal_connect (view->priv->zoomable, "zoom_in",
+ G_CALLBACK (gnv_zoomable_zoom_in_cb), view);
+ g_signal_connect (view->priv->zoomable, "zoom_out",
+ G_CALLBACK (gnv_zoomable_zoom_out_cb), view);
+ g_signal_connect (view->priv->zoomable, "zoom_to_fit",
+ G_CALLBACK (gnv_zoomable_zoom_to_fit_cb), view);
+ g_signal_connect (view->priv->zoomable, "zoom_to_default",
+ G_CALLBACK (gnv_zoomable_zoom_to_default_cb), view);
+
+ p->control = nautilus_view_get_bonobo_control (NAUTILUS_VIEW (view));
+
+ p->popup_ui = bonobo_control_get_popup_ui_component (p->control);
+ g_assert (BONOBO_IS_UI_COMPONENT (p->popup_ui));
+ bonobo_ui_util_set_ui (p->popup_ui, DATADIR,
+ "nautilus-ephy-view-ui.xml",
+ "EphyNutilusView", NULL);
+ p->popup = ephy_embed_popup_control_new (p->control);
+ ephy_embed_popup_connect_verbs (EPHY_EMBED_POPUP (p->popup), p->popup_ui);
+ g_object_set_data (G_OBJECT (p->popup), "NautilisView", view);
+
+ bonobo_ui_component_add_verb_list_with_data (p->popup_ui, ephy_popup_verbs, p->popup);
+}
+
+/**
+ * Returns a new EphyNautilusView as a BonoboObject
+ **/
+BonoboObject *
+ephy_nautilus_view_new_component (EphyShell *gs)
+{
+ EphyNautilusView *view;
+ view = EPHY_NAUTILUS_VIEW (g_object_new (EPHY_TYPE_NAUTILUS_VIEW, NULL));
+ return BONOBO_OBJECT (view);
+}
+
+static void
+ephy_nautilus_view_finalize (GObject *object)
+{
+ EphyNautilusView *view = EPHY_NAUTILUS_VIEW (object);
+ EphyNautilusViewPrivate *p = view->priv;
+
+ if (p->find_dialog)
+ {
+ g_object_unref (p->find_dialog);
+ }
+
+ g_object_unref (p->popup);
+
+ g_free (p->title);
+ g_free (p->location);
+ g_free (p);
+
+ GNOME_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
+
+ g_object_unref (G_OBJECT (ephy_shell));
+}
+
+static void
+ephy_nautilus_view_class_init (EphyNautilusViewClass *class)
+{
+ G_OBJECT_CLASS (class)->finalize = ephy_nautilus_view_finalize;
+}
+
+
+
+static gint
+gnv_embed_dom_mouse_down_cb (EphyEmbed *embed,
+ EphyEmbedEvent *event,
+ EphyNautilusView *view)
+{
+ EphyNautilusViewPrivate *p = view->priv;
+ int button;
+ EmbedEventContext context;
+
+ ephy_embed_event_get_mouse_button (event, &button);
+ ephy_embed_event_get_context (event, &context);
+
+ if (button == 2)
+ {
+ ephy_embed_popup_set_event (EPHY_EMBED_POPUP (p->popup), event);
+ ephy_embed_popup_show (EPHY_EMBED_POPUP (p->popup), embed);
+ return TRUE;
+
+ }
+ else if (button == 1
+ && (context & EMBED_CONTEXT_LINK))
+ {
+ GValue *value;
+ const gchar *url;
+ ephy_embed_event_get_property (event, "link", &value);
+ url = g_value_get_string (value);
+
+ g_return_val_if_fail (url, FALSE);
+
+ nautilus_view_open_location_force_new_window (NAUTILUS_VIEW (view),
+ url, NULL);
+ }
+
+ return FALSE;
+}
+
+static void
+gnv_embed_link_message_cb (EphyEmbed *embed, const char *message, EphyNautilusView *view)
+{
+ g_return_if_fail (EPHY_IS_NAUTILUS_VIEW (view));
+ g_return_if_fail (message != NULL);
+
+ nautilus_view_report_status (NAUTILUS_VIEW (view), message);
+}
+
+static void
+gnv_embed_location_cb (EphyEmbed *embed, EphyNautilusView *view)
+{
+ EphyNautilusViewPrivate *p;
+ const gchar *prefixes_to_ignore[] =
+ {
+ "about:",
+ "javascript:",
+ NULL
+ };
+ int i = 0;
+ gchar *new_uri;
+
+ g_return_if_fail (EPHY_IS_NAUTILUS_VIEW (view));
+ p = view->priv;
+ g_return_if_fail (view->priv->embed == embed);
+
+ ephy_embed_get_location (embed, TRUE, FALSE,
+ &new_uri);
+
+ g_return_if_fail (new_uri != NULL);
+
+
+ /* don't inform nautilus about uris that it can't understand */
+ while (prefixes_to_ignore[i] != NULL)
+ {
+ if (!strncmp (prefixes_to_ignore[i], new_uri, strlen (prefixes_to_ignore[i])))
+ {
+ g_free (new_uri);
+ return;
+ }
+ ++i;
+ }
+
+ nautilus_view_report_location_change (NAUTILUS_VIEW (view), new_uri, NULL, new_uri);
+
+ /* TODO, FIXME
+ nautilus_view_report_redirect (view, p->location, new_uri, NULL, new_uri);
+ */
+
+
+ g_free (p->location);
+ p->location = new_uri;
+
+
+}
+
+static void
+gnv_embed_title_cb (EphyEmbed *embed, EphyNautilusView *view)
+{
+ EphyNautilusViewPrivate *p;
+
+ g_return_if_fail (EPHY_IS_NAUTILUS_VIEW (view));
+ p = view->priv;
+ g_return_if_fail (view->priv->embed == embed);
+
+ g_free (p->title);
+ ephy_embed_get_title (embed, &p->title);
+
+ nautilus_view_set_title (NAUTILUS_VIEW (view), p->title);
+}
+
+static void
+gnv_load_location_cb (EphyNautilusView *view, const char *location, gpointer user_data)
+{
+ g_return_if_fail (EPHY_IS_NAUTILUS_VIEW (view));
+ g_return_if_fail (location != NULL);
+
+ nautilus_view_report_load_underway (NAUTILUS_VIEW (view));
+ ephy_embed_load_url (view->priv->embed, location);
+
+}
+
+static void
+gnv_stop_loading_cb (EphyNautilusView *view, gpointer user_data)
+{
+}
+
+static void
+gnv_embed_new_window_cb (EphyEmbed *embed, EphyEmbed **new_embed,
+ EmbedChromeMask chromemask, EphyNautilusView *view)
+{
+ EphyTab *new_tab;
+ EphyWindow *window;
+
+ window = ephy_window_new ();
+ if (!(chromemask & EMBED_CHROME_OPENASCHROME))
+ {
+ ephy_window_set_chrome (window,
+ chromemask |
+ EMBED_CHROME_OPENASPOPUP);
+ }
+ new_tab = ephy_tab_new ();
+ ephy_window_add_tab (window, new_tab, FALSE);
+
+ *new_embed = ephy_tab_get_embed (new_tab);
+}
+
+
+static void
+gnv_bonobo_control_activate_cb (BonoboControl *control, gboolean state, EphyNautilusView *view)
+{
+ if (state)
+ {
+ EphyNautilusViewPrivate *p = view->priv;
+
+ p->ui = nautilus_view_set_up_ui (NAUTILUS_VIEW (view), DATADIR,
+ "nautilus-ephy-view-ui.xml", "EphyNutilusView");
+ g_return_if_fail (BONOBO_IS_UI_COMPONENT (p->ui));
+
+ ephy_embed_utils_build_charsets_submenu (p->ui,
+ CHARSET_MENU_PATH,
+ (BonoboUIVerbFn) gnv_cmd_set_charset,
+ view);
+
+ bonobo_ui_component_add_verb_list_with_data (p->ui, ephy_verbs, view);
+ }
+}
+
+static EphyNautilusView *
+gnv_view_from_popup (EphyEmbedPopup *popup)
+{
+ return g_object_get_data (G_OBJECT (popup), "NautilisView");
+}
+
+
+static void
+gnv_popup_cmd_new_window (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname)
+{
+ EphyEmbedEvent *info;
+ EphyNautilusView *view;
+ GValue *value;
+
+ view = gnv_view_from_popup (popup);
+
+ info = ephy_embed_popup_get_event (popup);
+
+ ephy_embed_event_get_property (info, "link", &value);
+
+ nautilus_view_open_location_force_new_window (NAUTILUS_VIEW (view),
+ g_value_get_string (value), NULL);
+}
+
+static void
+gnv_popup_cmd_image_in_new_window (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname)
+{
+ EphyEmbedEvent *info;
+ EphyNautilusView *view;
+ GValue *value;
+
+ view = gnv_view_from_popup (popup);
+
+ info = ephy_embed_popup_get_event (popup);
+
+ ephy_embed_event_get_property (info, "image", &value);
+
+ nautilus_view_open_location_force_new_window (NAUTILUS_VIEW (view),
+ g_value_get_string (value), NULL);
+}
+
+static void
+gnv_popup_cmd_frame_in_new_window (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname)
+{
+ EphyEmbedEvent *info;
+ EphyNautilusView *view;
+ gchar *location;
+
+ view = gnv_view_from_popup (popup);
+
+ info = ephy_embed_popup_get_event (popup);
+
+ ephy_embed_get_location (view->priv->embed, FALSE, FALSE, &location);
+
+ nautilus_view_open_location_force_new_window (NAUTILUS_VIEW (view),
+ location, NULL);
+}
+
+void
+gnv_cmd_set_charset (BonoboUIComponent *uic,
+ EncodingMenuData *data,
+ const char* verbname)
+{
+ EphyNautilusView *view = data->data;
+ EphyNautilusViewPrivate *p;
+
+ g_return_if_fail (EPHY_IS_NAUTILUS_VIEW (view));
+
+ p = view->priv;
+
+ DEBUG_MSG ((data->encoding));
+ ephy_embed_set_charset (p->embed, data->encoding);
+}
+
+static void
+gnv_cmd_file_print (BonoboUIComponent *uic,
+ EphyNautilusView *view,
+ const char* verbname)
+{
+ EphyDialog *dialog;
+ EphyNautilusViewPrivate *p = view->priv;
+
+ dialog = print_dialog_new (p->embed, NULL);
+
+ //g_signal_connect (G_OBJECT(dialog),
+ // "preview",
+ // G_CALLBACK (print_dialog_preview_cb),
+ // window);
+
+ ephy_dialog_set_modal (dialog, TRUE);
+ ephy_dialog_show (dialog);
+
+}
+
+static void
+gnv_cmd_edit_find (BonoboUIComponent *uic,
+ EphyNautilusView *view,
+ const char* verbname)
+{
+ EphyNautilusViewPrivate *p = view->priv;
+
+ if (!p->find_dialog)
+ {
+ p->find_dialog = find_dialog_new (p->embed);
+ }
+
+ ephy_dialog_show (p->find_dialog);
+}
+
+
+/* zoomable */
+static void
+gnv_zoomable_set_zoom_level_cb (BonoboZoomable *zoomable,
+ float level,
+ EphyNautilusView *view)
+{
+ gint zoom = level * 100;
+ g_return_if_fail (EPHY_IS_NAUTILUS_VIEW (view));
+ if (zoom < 10) return;
+ if (zoom > 1000) return;
+ ephy_embed_zoom_set (view->priv->embed, zoom, TRUE);
+}
+
+static void
+gnv_zoomable_zoom_in_cb (BonoboZoomable *zoomable,
+ EphyNautilusView *view)
+{
+ gint zoom;
+ g_return_if_fail (EPHY_IS_NAUTILUS_VIEW (view));
+ ephy_embed_zoom_get (view->priv->embed, &zoom);
+ if (zoom > 990) return;
+ ephy_embed_zoom_set (view->priv->embed, zoom + 10, TRUE);
+}
+
+static void
+gnv_zoomable_zoom_out_cb (BonoboZoomable *zoomable,
+ EphyNautilusView *view)
+{
+ gint zoom;
+ g_return_if_fail (EPHY_IS_NAUTILUS_VIEW (view));
+ ephy_embed_zoom_get (view->priv->embed, &zoom);
+ if (zoom < 20) return;
+ ephy_embed_zoom_set (view->priv->embed, zoom - 10, TRUE);
+}
+
+static void
+gnv_zoomable_zoom_to_fit_cb (BonoboZoomable *zoomable,
+ EphyNautilusView *view)
+{
+ gnv_zoomable_zoom_to_default_cb (zoomable, view);
+}
+
+static void
+gnv_zoomable_zoom_to_default_cb (BonoboZoomable *zoomable,
+ EphyNautilusView *view)
+{
+ g_return_if_fail (EPHY_IS_NAUTILUS_VIEW (view));
+ ephy_embed_zoom_set (view->priv->embed, 100, TRUE);
+}
+
+static void
+gnv_embed_zoom_change_cb (EphyNautilusView *embed,
+ guint new_zoom,
+ EphyNautilusView *view)
+{
+ float flevel;
+ g_return_if_fail (EPHY_IS_NAUTILUS_VIEW (view));
+
+ flevel = ((float) new_zoom) / 100.0;
+
+ bonobo_zoomable_report_zoom_level_changed (view->priv->zoomable,
+ flevel, NULL);
+
+}
+
+
+#ifdef IM_TOO_LAZY_TO_MOVE_THIS_TO_ANOTHER_FILE
+
+
+/* property bag properties */
+enum {
+ ICON_NAME,
+ COMPONENT_INFO
+};
+
+
+static void
+get_bonobo_properties (BonoboPropertyBag *bag,
+ BonoboArg *arg,
+ guint arg_id,
+ CORBA_Environment *ev,
+ gpointer callback_data)
+{
+ EphyNautilusView *content_view;
+
+ content_view = (EphyNautilusView*) callback_data;
+
+ switch (arg_id) {
+ case ICON_NAME:
+ if (!strncmp (content_view->priv->uri, "man:", 4)) {
+ BONOBO_ARG_SET_STRING (arg, "manual");
+ } else if (!strncmp (content_view->priv->uri, "http:", 5)) {
+ BONOBO_ARG_SET_STRING (arg, "i-web");
+ } else if (!strncmp (content_view->priv->uri, "https:", 6)) {
+ /* FIXME: put a nice icon for secure sites */
+ BONOBO_ARG_SET_STRING (arg, "i-web");
+ } else {
+ BONOBO_ARG_SET_STRING (arg, "");
+ }
+ break;
+
+ case COMPONENT_INFO:
+ BONOBO_ARG_SET_STRING (arg, "");
+ break;
+
+ default:
+ g_warning ("Unhandled arg %d", arg_id);
+ break;
+ }
+}
+
+/* there are no settable properties, so complain if someone tries to set one */
+static void
+set_bonobo_properties (BonoboPropertyBag *bag,
+ const BonoboArg *arg,
+ guint arg_id,
+ CORBA_Environment *ev,
+ gpointer callback_data)
+{
+ g_warning ("Bad Property set on view: property ID %d",
+ arg_id);
+}
+
+static void
+ephy_nautilus_view_initialize (EphyNautilusView *view)
+{
+
+
+#ifdef NOT_PORTED
+ bonobo_control_set_properties (nautilus_view_get_bonobo_control (view->priv->nautilus_view),
+ view->priv->property_bag);
+#endif
+ bonobo_property_bag_add (view->priv->property_bag, "icon_name", ICON_NAME,
+ BONOBO_ARG_STRING, NULL,
+ _("name of icon for the mozilla view"), 0);
+ bonobo_property_bag_add (view->priv->property_bag, "summary_info", COMPONENT_INFO,
+ BONOBO_ARG_STRING, NULL,
+ _("mozilla summary info"), 0);
+}
+
+
+ /* free the property bag */
+ if (view->priv->property_bag != NULL) {
+ bonobo_object_unref (BONOBO_OBJECT (view->priv->property_bag));
+ view->priv->property_bag = NULL;
+ }
+
+}
+
+
+
+void
+ephy_nautilus_view_report_load_progress (EphyNautilusView *view,
+ double value)
+{
+ g_return_if_fail (EPHY_IS_NAUTILUS_VIEW (view));
+
+ if (value < 0.0) value = 0.0;
+ if (value > 1.0) value = 1.0;
+
+ nautilus_view_report_load_progress (view->priv->nautilus_view, value);
+}
+
+/***********************************************************************************/
+
+/**
+ * vfs_open_cb
+ *
+ * Callback for gnome_vfs_async_open. Attempt to read data from handle
+ * and pass to mozilla streaming callback.
+ *
+ **/
+static void
+vfs_open_cb (GnomeVFSAsyncHandle *handle, GnomeVFSResult result, gpointer data)
+{
+ EphyNautilusView *view = data;
+
+ DEBUG_MSG (("+%s GnomeVFSResult: %u\n", G_GNUC_FUNCTION, (unsigned)result));
+
+ if (result != GNOME_VFS_OK)
+ {
+ gtk_moz_embed_close_stream (GTK_MOZ_EMBED (view->priv->embed->mozembed));
+ /* NOTE: the view may go away after a call to report_load_failed */
+ DEBUG_MSG ((">nautilus_view_report_load_failed\n"));
+ nautilus_view_report_load_failed (view->priv->nautilus_view);
+ } else {
+ if (view->priv->vfs_read_buffer == NULL) {
+ view->priv->vfs_read_buffer = g_malloc (VFS_READ_BUFFER_SIZE);
+ }
+ gtk_moz_embed_open_stream (GTK_MOZ_EMBED (view->priv->embed->mozembed), "file:///", "text/html");
+ gnome_vfs_async_read (handle, view->priv->vfs_read_buffer, VFS_READ_BUFFER_SIZE, vfs_read_cb, view);
+ }
+ DEBUG_MSG (("-%s\n", G_GNUC_FUNCTION));
+}
+
+/**
+ * vfs_read_cb:
+ *
+ * Read data from buffer and copy into mozilla stream.
+ **/
+
+static void
+vfs_read_cb (GnomeVFSAsyncHandle *handle, GnomeVFSResult result, gpointer buffer,
+ GnomeVFSFileSize bytes_requested,
+ GnomeVFSFileSize bytes_read,
+ gpointer data)
+{
+ EphyNautilusView *view = data;
+
+ DEBUG_MSG (("+%s %ld/%ld bytes\n", G_GNUC_FUNCTION, (long)bytes_requested, (long) bytes_read));
+
+ if (bytes_read != 0) {
+ gtk_moz_embed_append_data (GTK_MOZ_EMBED (view->priv->embed->mozembed), buffer, bytes_read);
+ }
+
+ if (bytes_read == 0 || result != GNOME_VFS_OK) {
+ gtk_moz_embed_close_stream (GTK_MOZ_EMBED (view->priv->embed->mozembed));
+ view->priv->vfs_handle = NULL;
+ g_free (view->priv->vfs_read_buffer);
+ view->priv->vfs_read_buffer = NULL;
+
+ gnome_vfs_async_close (handle, (GnomeVFSAsyncCloseCallback) gtk_true, NULL);
+
+ DEBUG_MSG ((">nautilus_view_report_load_complete\n"));
+ nautilus_view_report_load_complete (view->priv->nautilus_view);
+
+ DEBUG_MSG (("=%s load complete\n", G_GNUC_FUNCTION));
+ } else {
+ gnome_vfs_async_read (handle, view->priv->vfs_read_buffer, VFS_READ_BUFFER_SIZE, vfs_read_cb, view);
+ }
+
+ DEBUG_MSG (("-%s\n", G_GNUC_FUNCTION));
+}
+
+/***********************************************************************************/
+
+static void
+cancel_pending_vfs_operation (EphyNautilusView *view)
+{
+ if (view->priv->vfs_handle != NULL) {
+ gnome_vfs_async_cancel (view->priv->vfs_handle);
+ gtk_moz_embed_close_stream (GTK_MOZ_EMBED (view->priv->embed->mozembed));
+ }
+
+ view->priv->vfs_handle = NULL;
+ g_free (view->priv->vfs_read_buffer);
+ view->priv->vfs_read_buffer = NULL;
+}
+
+
+/* this takes a "nautilus" uri, not a "mozilla" uri and uses (sometimes) GnomeVFS */
+static void
+navigate_mozilla_to_nautilus_uri (EphyNautilusView *view,
+ const char *uri)
+{
+ char *old_uri;
+
+ cancel_pending_vfs_operation (view);
+
+ if (!GTK_WIDGET_REALIZED (view->priv->embed->mozembed)) {
+
+ /* Doing certain things to gtkmozembed before
+ * the widget has realized (specifically, opening
+ * content streams) can cause crashes. To avoid
+ * this, we postpone all navigations
+ * until the widget has realized (we believe
+ * premature realization may cause other issues)
+ */
+
+ DEBUG_MSG (("=%s: Postponing navigation request to widget realization\n", G_GNUC_FUNCTION));
+ /* Note that view->priv->uri is still set below */
+ } else {
+ if (should_mozilla_load_uri_directly (uri)) {
+
+ /* See if the current URI is the same as what mozilla already
+ * has. If so, issue a reload rather than a load.
+ * We ask mozilla for it's uri rather than using view->priv->uri because,
+ * from time to time, our understanding of mozilla's URI can become inaccurate
+ * (in particular, certain errors may cause embedded mozilla to not change
+ * locations)
+ */
+
+ old_uri = view->priv->embed->location;
+
+ if (old_uri != NULL && uris_identical (uri, old_uri)) {
+ DEBUG_MSG (("=%s uri's identical, telling ephy to reload\n", G_GNUC_FUNCTION));
+ embed_reload (view->priv->embed,
+ GTK_MOZ_EMBED_FLAG_RELOADBYPASSCACHE);
+ } else {
+ embed_load_url (view->priv->embed, uri);
+ }
+
+ } else {
+ DEBUG_MSG (("=%s loading URI via gnome-vfs\n", G_GNUC_FUNCTION));
+ gnome_vfs_async_open (&(view->priv->vfs_handle), uri,
+ GNOME_VFS_OPEN_READ, GNOME_VFS_PRIORITY_DEFAULT,
+ vfs_open_cb, view);
+ }
+ }
+
+ g_free (view->priv->uri);
+ view->priv->uri = g_strdup (uri);
+
+ DEBUG_MSG (("=%s current URI is now '%s'\n", G_GNUC_FUNCTION, view->priv->uri));
+}
+
+/*
+ * This a list of URI schemes that mozilla should load directly, rather than load through gnome-vfs
+ */
+static gboolean
+should_mozilla_load_uri_directly (const char *uri)
+{
+ static const char *handled_by_mozilla[] =
+ {
+ "http",
+ "file",
+ "toc",
+ "man",
+ "info",
+ "ghelp",
+ "gnome-help",
+ "https",
+ NULL
+ };
+ gint i;
+ gint uri_length;
+
+ if (uri == NULL) return FALSE;
+
+ uri_length = strlen (uri);
+
+ for (i = 0; handled_by_mozilla[i] != NULL; i++)
+ {
+ const gchar *current = handled_by_mozilla[i];
+ gint current_length = strlen (current);
+ if ((uri_length >= current_length)
+ && (!strncasecmp (uri, current, current_length)))
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+
+#endif
diff --git a/src/ephy-nautilus-view.h b/src/ephy-nautilus-view.h
new file mode 100644
index 000000000..3dd13560b
--- /dev/null
+++ b/src/ephy-nautilus-view.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2001, 2002 Ricardo Fernández Pascual
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+
+#ifndef EPHY_NAUTILUS_VIEW_H
+#define EPHY_NAUTILUS_VIEW_H
+
+#include <libnautilus/nautilus-view.h>
+#include "ephy-shell.h"
+
+G_BEGIN_DECLS
+
+#define EPHY_TYPE_NAUTILUS_VIEW (ephy_nautilus_view_get_type ())
+#define EPHY_NAUTILUS_VIEW(obj) (GTK_CHECK_CAST ((obj), EPHY_TYPE_NAUTILUS_VIEW, \
+ EphyNautilusView))
+#define EPHY_NAUTILUS_VIEW_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), EPHY_TYPE_NAUTILUS_VIEW, \
+ EphyNautilusViewClass))
+#define EPHY_IS_NAUTILUS_VIEW(obj) (GTK_CHECK_TYPE ((obj), EPHY_TYPE_NAUTILUS_VIEW))
+#define EPHY_IS_NAUTILUS_VIEW_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), EPHY_IS_NAUTILUS_VIEW_CLASS))
+
+typedef struct EphyNautilusView EphyNautilusView;
+typedef struct EphyNautilusViewClass EphyNautilusViewClass;
+typedef struct EphyNautilusViewPrivate EphyNautilusViewPrivate;
+
+struct EphyNautilusView
+{
+ NautilusView parent;
+ EphyNautilusViewPrivate *priv;
+};
+
+struct EphyNautilusViewClass
+{
+ NautilusViewClass parent_class;
+};
+
+
+GType ephy_nautilus_view_get_type (void);
+BonoboObject * ephy_nautilus_view_new_component (EphyShell *gs);
+
+/* old public methods, probably all of them are going to be killed */
+
+void
+ephy_nautilus_view_set_title (EphyNautilusView *view,
+ const gchar *title);
+void
+ephy_nautilus_view_set_location (EphyNautilusView *view,
+ const gchar *uri);
+void
+ephy_nautilus_view_set_statusbar (EphyNautilusView *view,
+ const gchar *message);
+void
+ephy_nautilus_view_report_load_underway (EphyNautilusView *view);
+
+void
+ephy_nautilus_view_report_load_complete (EphyNautilusView *view);
+
+void
+ephy_nautilus_view_report_load_progress (EphyNautilusView *view,
+ double value);
+void
+ephy_nautilus_view_report_zoom (EphyNautilusView *view,
+ gint level);
+
+void ephy_nautilus_view_open_in_new_window (EphyNautilusView *view,
+ const gchar *url);
+
+G_END_DECLS
+
+#endif
diff --git a/src/ephy-shell.c b/src/ephy-shell.c
new file mode 100644
index 000000000..eeacdf819
--- /dev/null
+++ b/src/ephy-shell.c
@@ -0,0 +1,525 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "ephy-shell.h"
+#include "ephy-embed-shell.h"
+#include "eel-gconf-extensions.h"
+#include "ephy-prefs.h"
+#include "ephy-favicon-cache.h"
+#include "ephy-stock-icons.h"
+#include "ephy-filesystem-autocompletion.h"
+#include "ephy-window.h"
+#include "ephy-file-helpers.h"
+#include "ephy-thread-helpers.h"
+
+#include <libgnomeui/gnome-client.h>
+#include <bonobo/bonobo-main.h>
+#include <bonobo/bonobo-i18n.h>
+#include <gtk/gtksignal.h>
+#include <gtk/gtkmain.h>
+#include <gtk/gtkmessagedialog.h>
+
+#ifdef ENABLE_NAUTILUS_VIEW
+
+#include <bonobo/bonobo-generic-factory.h>
+#include "ephy-nautilus-view.h"
+
+#define EPHY_NAUTILUS_VIEW_OAFIID "OAFIID:GNOME_Ephy_NautilusViewFactory"
+
+#endif
+
+struct EphyShellPrivate
+{
+ EphyEmbedShell *embed_shell;
+ Session *session;
+ EphyAutocompletion *autocompletion;
+ EphyBookmarks *bookmarks;
+};
+
+enum
+{
+ STARTPAGE_HOME,
+ STARTPAGE_LAST,
+ STARTPAGE_BLANK,
+};
+
+static void
+ephy_shell_class_init (EphyShellClass *klass);
+static void
+ephy_shell_init (EphyShell *gs);
+static void
+ephy_shell_finalize (GObject *object);
+static void
+ephy_init_services (EphyShell *gs);
+
+#ifdef ENABLE_NAUTILUS_VIEW
+
+static void
+ephy_nautilus_view_init_factory (EphyShell *gs);
+static BonoboObject *
+ephy_nautilus_view_new (BonoboGenericFactory *factory,
+ const char *id,
+ EphyShell *gs);
+
+#endif
+
+static GObjectClass *parent_class = NULL;
+
+EphyShell *ephy_shell;
+
+GType
+ephy_shell_get_type (void)
+{
+ static GType ephy_shell_type = 0;
+
+ if (ephy_shell_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (EphyShellClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) ephy_shell_class_init,
+ NULL,
+ NULL, /* class_data */
+ sizeof (EphyShell),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) ephy_shell_init
+ };
+
+ ephy_shell_type = g_type_register_static (G_TYPE_OBJECT,
+ "EphyShell",
+ &our_info, 0);
+ }
+
+ return ephy_shell_type;
+
+}
+
+static void
+ephy_shell_class_init (EphyShellClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = ephy_shell_finalize;
+}
+
+static void
+ephy_shell_new_window_cb (EphyEmbedShell *shell,
+ EphyEmbed **new_embed,
+ EmbedChromeMask chromemask,
+ gpointer data)
+{
+ EphyTab *new_tab;
+ EphyWindow *window;
+ gboolean open_in_tab;
+
+ g_assert (new_embed != NULL);
+
+ open_in_tab = (chromemask & EMBED_CHROME_OPENASCHROME) ?
+ FALSE :
+ eel_gconf_get_boolean (CONF_TABS_TABBED_POPUPS);
+
+ if (open_in_tab)
+ {
+ window = ephy_shell_get_active_window (ephy_shell);
+ }
+ else
+ {
+ window = ephy_window_new ();
+ ephy_window_set_chrome (window, chromemask);
+ }
+
+ new_tab = ephy_tab_new ();
+ ephy_window_add_tab (window, new_tab, FALSE);
+ *new_embed = ephy_tab_get_embed (new_tab);
+}
+
+static void
+ephy_shell_init (EphyShell *gs)
+{
+ ephy_shell = gs;
+ g_object_add_weak_pointer (G_OBJECT(ephy_shell),
+ (gpointer *)&ephy_shell);
+
+ ephy_thread_helpers_init ();
+ ephy_node_system_init ();
+ ephy_file_helpers_init ();
+ ephy_stock_icons_init ();
+ ephy_ensure_dir_exists (ephy_dot_dir ());
+
+ gs->priv = g_new0 (EphyShellPrivate, 1);
+ gs->priv->session = NULL;
+ gs->priv->bookmarks = NULL;
+
+ gs->priv->embed_shell = ephy_embed_shell_new ("mozilla");
+
+ g_assert (gs->priv->embed_shell != NULL);
+
+ g_signal_connect (G_OBJECT(embed_shell),
+ "new_window_orphan",
+ G_CALLBACK(ephy_shell_new_window_cb),
+ NULL);
+
+ ephy_init_services (gs);
+}
+
+static void
+ephy_shell_finalize (GObject *object)
+{
+ EphyShell *gs;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (IS_EPHY_SHELL (object));
+
+ gs = EPHY_SHELL (object);
+
+ g_return_if_fail (gs->priv != NULL);
+
+ g_assert (ephy_shell == NULL);
+
+ g_return_if_fail (IS_EPHY_EMBED_SHELL (gs->priv->embed_shell));
+ g_object_unref (G_OBJECT (gs->priv->embed_shell));
+
+ if (gs->priv->session)
+ {
+ g_return_if_fail (IS_SESSION(gs->priv->session));
+ g_object_remove_weak_pointer
+ (G_OBJECT(gs->priv->session),
+ (gpointer *)&gs->priv->session);
+ g_object_unref (G_OBJECT (gs->priv->session));
+ }
+
+ if (gs->priv->autocompletion)
+ {
+ g_object_unref (gs->priv->autocompletion);
+ }
+
+ if (gs->priv->bookmarks)
+ {
+ g_object_unref (gs->priv->bookmarks);
+ }
+
+ ephy_file_helpers_shutdown ();
+ ephy_node_system_shutdown ();
+
+ g_free (gs->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+
+#ifdef DEBUG_MARCO
+ g_print ("Ephy shell finalized\n");
+#endif
+
+ bonobo_main_quit ();
+
+#ifdef DEBUG_MARCO
+ g_print ("Bonobo quit done\n");
+#endif
+}
+
+EphyShell *
+ephy_shell_new (void)
+{
+ return EPHY_SHELL (g_object_new (EPHY_SHELL_TYPE, NULL));
+}
+
+/**
+ * ephy_shell_get_embed_shell:
+ * @gs: a #EphyShell
+ *
+ * Returns the embed shell created by the #EphyShell
+ *
+ * Return value: the embed shell
+ **/
+EphyEmbedShell *
+ephy_shell_get_embed_shell (EphyShell *gs)
+{
+ g_return_val_if_fail (IS_EPHY_SHELL (gs), NULL);
+
+ return gs->priv->embed_shell;
+}
+
+static void
+ephy_init_services (EphyShell *gs)
+{
+ /* preload the prefs */
+ /* it also enables notifiers support */
+ eel_gconf_monitor_add ("/apps/epiphany");
+ eel_gconf_monitor_add ("/apps/nautilus/preferences");
+
+#ifdef ENABLE_NAUTILUS_VIEW
+
+ ephy_nautilus_view_init_factory (gs);
+
+#endif
+
+}
+
+static char *
+build_homepage_url (EphyShell *gs,
+ EphyEmbed *previous_embed)
+{
+ const gchar *last_page_url;
+ gchar *home_page_url;
+ gint page_type;
+ EphyHistory *gh;
+ char *result = NULL;
+
+ if (previous_embed == NULL)
+ {
+ page_type = STARTPAGE_HOME;
+ }
+ else
+ {
+ page_type = eel_gconf_get_integer (CONF_GENERAL_NEWPAGE_TYPE);
+ }
+
+ /* return the appropriate page */
+ if (page_type == STARTPAGE_HOME)
+ {
+ /* get location of home page */
+ home_page_url = eel_gconf_get_string(CONF_GENERAL_HOMEPAGE);
+ result = home_page_url;
+ }
+ else if (page_type == STARTPAGE_LAST)
+ {
+ if (previous_embed != NULL)
+ {
+ ephy_embed_get_location (previous_embed,
+ TRUE, TRUE,
+ &result);
+ }
+
+ if (result == NULL)
+ {
+ /* get location of last page */
+ gh = ephy_embed_shell_get_global_history
+ (gs->priv->embed_shell);
+ last_page_url = ephy_history_get_last_page (gh);
+ result = g_strdup (last_page_url);
+ }
+ }
+
+ if (result == NULL)
+ {
+ /* even in case of error, it's a good default */
+ result = g_strdup ("about:blank");
+ }
+
+ return result;
+}
+
+/**
+ * ephy_shell_get_active_window:
+ * @gs: a #EphyShell
+ *
+ * Get the current active window. Use it when you
+ * need to take an action (like opening an url) on
+ * a window but you dont have a target window.
+ * Ex. open a new tab from command line.
+ *
+ * Return value: the current active window
+ **/
+EphyWindow *
+ephy_shell_get_active_window (EphyShell *gs)
+{
+ Session *session;
+ GList *windows;
+
+ session = ephy_shell_get_session (gs);
+ windows = session_get_windows (session);
+
+ if (windows == NULL) return NULL;
+
+ return EPHY_WINDOW(windows->data);
+}
+
+/**
+ * ephy_shell_new_tab:
+ * @shell: a #EphyShell
+ * @parent_window: the target #EphyWindow or %NULL
+ * @previous_tab: the referrer tab or %NULL
+ * @url: an url to load or %NULL
+ *
+ * Create a new tab and the parent window when necessary.
+ * Ever use this function to open urls in new window/tabs.
+ *
+ * ReturnValue: the created #EphyTab
+ **/
+EphyTab *
+ephy_shell_new_tab (EphyShell *shell,
+ EphyWindow *parent_window,
+ EphyTab *previous_tab,
+ const char *url,
+ EphyNewTabFlags flags)
+{
+ EphyWindow *window;
+ EphyTab *tab;
+ EphyEmbed *embed;
+ gboolean in_new_window;
+ gboolean jump_to;
+ EphyEmbed *previous_embed = NULL;
+
+ in_new_window = !eel_gconf_get_boolean (CONF_TABS_TABBED);
+
+ if (flags & EPHY_NEW_TAB_IN_NEW_WINDOW) in_new_window = TRUE;
+ if (flags & EPHY_NEW_TAB_IN_EXISTING_WINDOW) in_new_window = FALSE;
+
+ jump_to = eel_gconf_get_boolean (CONF_TABS_TABBED_AUTOJUMP);
+
+ if (flags & EPHY_NEW_TAB_JUMP) jump_to = TRUE;
+ if (flags & EPHY_NEW_TAB_DONT_JUMP_TO) jump_to = FALSE;
+
+ if (!in_new_window && parent_window != NULL)
+ {
+ window = parent_window;
+ }
+ else
+ {
+ window = ephy_window_new ();
+ }
+
+ if (previous_tab)
+ {
+ previous_embed = ephy_tab_get_embed (previous_tab);
+ }
+
+ tab = ephy_tab_new ();
+ embed = ephy_tab_get_embed (tab);
+ gtk_widget_show (GTK_WIDGET(embed));
+ ephy_window_add_tab (window, tab,
+ jump_to);
+ gtk_widget_show (GTK_WIDGET(window));
+
+ if (flags & EPHY_NEW_TAB_HOMEPAGE)
+ {
+ char *homepage;
+
+ homepage = build_homepage_url (shell, previous_embed);
+ g_assert (homepage != NULL);
+
+ ephy_embed_load_url (embed, homepage);
+
+ g_free (homepage);
+ }
+ else if ((flags & EPHY_NEW_TAB_IS_A_COPY) ||
+ (flags & EPHY_NEW_TAB_VIEW_SOURCE))
+ {
+ EmbedDisplayType display_type =
+ (flags & EPHY_NEW_TAB_VIEW_SOURCE) ?
+ DISPLAY_AS_SOURCE : DISPLAY_NORMAL;
+ EphyEmbed *source = ephy_tab_get_embed(previous_tab);
+ ephy_embed_load_url (embed, "about:blank");
+ ephy_embed_copy_page (embed, source, display_type);
+ }
+ else if (url)
+ {
+ ephy_embed_load_url (embed, url);
+ }
+
+ return tab;
+}
+
+#ifdef ENABLE_NAUTILUS_VIEW
+
+static void
+ephy_nautilus_view_init_factory (EphyShell *gs)
+{
+ BonoboGenericFactory *ephy_nautilusview_factory;
+ ephy_nautilusview_factory = bonobo_generic_factory_new
+ (EPHY_NAUTILUS_VIEW_OAFIID,
+ (BonoboFactoryCallback) ephy_nautilus_view_new, gs);
+ if (!BONOBO_IS_GENERIC_FACTORY (ephy_nautilusview_factory))
+ g_warning ("Couldn't create the factory!");
+
+}
+
+static BonoboObject *
+ephy_nautilus_view_new (BonoboGenericFactory *factory, const char *id,
+ EphyShell *gs)
+{
+ return ephy_nautilus_view_new_component (gs);
+}
+
+#endif
+
+/**
+ * ephy_shell_get_session:
+ * @gs: a #EphyShell
+ *
+ * Returns current session.
+ *
+ * Return value: the current session.
+ **/
+Session *
+ephy_shell_get_session (EphyShell *gs)
+{
+ if (!gs->priv->session)
+ {
+ gs->priv->session = session_new ();
+ g_object_add_weak_pointer
+ (G_OBJECT(gs->priv->session),
+ (gpointer *)&gs->priv->session);
+ }
+
+ return gs->priv->session;
+}
+
+EphyAutocompletion *
+ephy_shell_get_autocompletion (EphyShell *gs)
+{
+ EphyShellPrivate *p = gs->priv;
+
+ if (!p->autocompletion)
+ {
+ static const gchar *prefixes[] = {
+ EPHY_AUTOCOMPLETION_USUAL_WEB_PREFIXES,
+ NULL
+ };
+
+ EphyHistory *gh = ephy_embed_shell_get_global_history (gs->priv->embed_shell);
+ EphyFilesystemAutocompletion *fa = ephy_filesystem_autocompletion_new ();
+ p->autocompletion = ephy_autocompletion_new ();
+ ephy_autocompletion_set_prefixes (p->autocompletion, prefixes);
+
+ ephy_autocompletion_add_source (p->autocompletion,
+ EPHY_AUTOCOMPLETION_SOURCE (gh));
+ ephy_autocompletion_add_source (p->autocompletion,
+ EPHY_AUTOCOMPLETION_SOURCE (fa));
+ ephy_autocompletion_add_source (p->autocompletion,
+ EPHY_AUTOCOMPLETION_SOURCE (gs->priv->bookmarks));
+
+ g_object_unref (fa);
+ g_object_unref (gs->priv->bookmarks);
+ }
+ return p->autocompletion;
+}
+
+EphyBookmarks *
+ephy_shell_get_bookmarks (EphyShell *gs)
+{
+ if (gs->priv->bookmarks == NULL)
+ {
+ gs->priv->bookmarks = ephy_bookmarks_new ();
+ }
+
+ return gs->priv->bookmarks;
+}
diff --git a/src/ephy-shell.h b/src/ephy-shell.h
new file mode 100644
index 000000000..3590931f9
--- /dev/null
+++ b/src/ephy-shell.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EPHY_SHELL_H
+#define EPHY_SHELL_H
+
+#include "ephy-autocompletion.h"
+#include "prefs-dialog.h"
+#include "downloader-view.h"
+#include "ephy-embed-shell.h"
+#include "session.h"
+#include "ephy-bookmarks.h"
+
+#include <glib-object.h>
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+#ifndef EPHY_SHELL_TYPE_DEF
+typedef struct EphyShell EphyShell;
+#define EPHY_SHELL_TYPE_DEF
+#endif
+
+typedef struct EphyShellClass EphyShellClass;
+
+#define EPHY_SHELL_TYPE (ephy_shell_get_type ())
+#define EPHY_SHELL(obj) (GTK_CHECK_CAST ((obj), EPHY_SHELL_TYPE, EphyShell))
+#define EPHY_SHELL_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), EPHY_SHELL, EphyShellClass))
+#define IS_EPHY_SHELL(obj) (GTK_CHECK_TYPE ((obj), EPHY_SHELL_TYPE))
+#define IS_EPHY_SHELL_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), EPHY_SHELL))
+
+typedef struct EphyShellPrivate EphyShellPrivate;
+
+extern EphyShell *ephy_shell;
+
+typedef enum
+{
+ EPHY_NEW_TAB_HOMEPAGE = 1 << 0,
+ EPHY_NEW_TAB_FULLSCREEN = 1 << 1,
+ EPHY_NEW_TAB_APPEND = 1 << 2,
+ EPHY_NEW_TAB_PREPEND = 1 << 3,
+ EPHY_NEW_TAB_APPEND_AFTER_CURRENT = 1 << 4,
+ EPHY_NEW_TAB_JUMP = 1 << 5,
+ EPHY_NEW_TAB_DONT_JUMP_TO = 1 << 6,
+ EPHY_NEW_TAB_RAISE_WINDOW = 1 << 7,
+ EPHY_NEW_TAB_DONT_RAISE_WINDOW = 1 << 8,
+ EPHY_NEW_TAB_IN_NEW_WINDOW = 1 << 9,
+ EPHY_NEW_TAB_IN_EXISTING_WINDOW = 1 << 10,
+ EPHY_NEW_TAB_IS_A_COPY = 1 << 11,
+ EPHY_NEW_TAB_VIEW_SOURCE = 1 << 12
+} EphyNewTabFlags;
+
+struct EphyShell
+{
+ GObject parent;
+ EphyShellPrivate *priv;
+};
+
+struct EphyShellClass
+{
+ GObjectClass parent_class;
+};
+
+GType ephy_shell_get_type (void);
+
+EphyShell *ephy_shell_new (void);
+
+EphyEmbedShell *ephy_shell_get_embed_shell (EphyShell *gs);
+
+EphyWindow *ephy_shell_get_active_window (EphyShell *gs);
+
+EphyTab *ephy_shell_new_tab (EphyShell *shell,
+ EphyWindow *parent_window,
+ EphyTab *previous_tab,
+ const char *url,
+ EphyNewTabFlags flags);
+
+Session *ephy_shell_get_session (EphyShell *gs);
+
+EphyAutocompletion *ephy_shell_get_autocompletion (EphyShell *gs);
+
+EphyBookmarks *ephy_shell_get_bookmarks (EphyShell *gs);
+
+G_END_DECLS
+
+#endif
diff --git a/src/ephy-tab.c b/src/ephy-tab.c
new file mode 100644
index 000000000..b1fe71fb6
--- /dev/null
+++ b/src/ephy-tab.c
@@ -0,0 +1,945 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define DEBUG_MSG(x) g_print x
+//#define DEBUG_MSG(x)
+
+#define NOT_IMPLEMENTED g_warning ("not implemented: " G_STRLOC);
+
+#include "ephy-tab.h"
+#include "ephy-shell.h"
+#include "ephy-embed-popup-bw.h"
+#include "eel-gconf-extensions.h"
+#include "ephy-prefs.h"
+#include "ephy-embed-prefs.h"
+
+#include <bonobo/bonobo-i18n.h>
+#include <libgnomevfs/gnome-vfs-uri.h>
+#include <gtk/gtklabel.h>
+#include <gtk/gtkbutton.h>
+#include <gtk/gtkstock.h>
+#include <gtk/gtkmisc.h>
+#include <gtk/gtkhbox.h>
+#include <gtk/gtkimage.h>
+#include <gtk/gtkiconfactory.h>
+#include <gtk/gtkstyle.h>
+#include <gtk/gtkselection.h>
+#include <string.h>
+
+struct EphyTabPrivate
+{
+ EphyEmbed *embed;
+ EphyWindow *window;
+ gboolean is_active;
+ TabLoadStatus load_status;
+ char status_message[255];
+ char *title;
+ char *location;
+ int load_percent;
+ gboolean visibility;
+ int cur_requests;
+ int total_requests;
+ int width;
+ int height;
+};
+
+static void
+ephy_tab_class_init (EphyTabClass *klass);
+static void
+ephy_tab_init (EphyTab *tab);
+static void
+ephy_tab_finalize (GObject *object);
+
+enum
+{
+ PROP_0,
+ PROP_EPHY_SHELL
+};
+
+static void
+ephy_tab_link_message_cb (EphyEmbed *embed,
+ const char *message,
+ EphyTab *tab);
+static void
+ephy_tab_js_status_cb (EphyEmbed *embed,
+ const char *status,
+ EphyTab *tab);
+static void
+ephy_tab_location_cb (EphyEmbed *embed, EphyTab *tab);
+static void
+ephy_tab_title_cb (EphyEmbed *embed, EphyTab *tab);
+static void
+ephy_tab_net_state_cb (EphyEmbed *embed, const char *uri,
+ EmbedState state, EphyTab *tab);
+static void
+ephy_tab_new_window_cb (EphyEmbed *embed, EphyEmbed **new_embed,
+ EmbedChromeMask chromemask, EphyTab *tab);
+static void
+ephy_tab_visibility_cb (EphyEmbed *embed, gboolean visibility,
+ EphyTab *tab);
+static void
+ephy_tab_destroy_brsr_cb (EphyEmbed *embed, EphyTab *tab);
+static gint
+ephy_tab_open_uri_cb (EphyEmbed *embed, const char *uri,
+ EphyTab *tab);
+static void
+ephy_tab_size_to_cb (EphyEmbed *embed, gint width, gint height,
+ EphyTab *tab);
+static gint
+ephy_tab_dom_mouse_click_cb (EphyEmbed *embed,
+ EphyEmbedEvent *event,
+ EphyTab *tab);
+static gint
+ephy_tab_dom_mouse_down_cb (EphyEmbed *embed,
+ EphyEmbedEvent *event,
+ EphyTab *tab);
+static void
+ephy_tab_security_change_cb (EphyEmbed *embed, EmbedSecurityLevel level,
+ EphyTab *tab);
+static void
+ephy_tab_zoom_changed_cb (EphyEmbed *embed, gint zoom,
+ EphyTab *tab);
+
+static GObjectClass *parent_class = NULL;
+
+/* Class functions */
+
+GType
+ephy_tab_get_type (void)
+{
+ static GType ephy_tab_type = 0;
+
+ if (ephy_tab_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (EphyTabClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) ephy_tab_class_init,
+ NULL,
+ NULL, /* class_data */
+ sizeof (EphyTab),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) ephy_tab_init
+ };
+
+ ephy_tab_type = g_type_register_static (G_TYPE_OBJECT,
+ "EphyTab",
+ &our_info, 0);
+ }
+
+ return ephy_tab_type;
+}
+
+static void
+ephy_tab_class_init (EphyTabClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = ephy_tab_finalize;
+}
+
+static void
+ephy_tab_parent_set_cb (GtkWidget *widget, GtkWidget *previous_parent,
+ EphyTab *tab)
+{
+ GtkWidget *toplevel;
+
+ /* FIXME maybe we dont need to set the tab parent explicitly
+ * anymore with this callback taking care of it */
+
+ if (widget->parent == NULL) return;
+
+ toplevel = gtk_widget_get_toplevel (widget);
+
+ tab->priv->window = EPHY_WINDOW (toplevel);
+}
+
+static void
+ephy_tab_embed_destroy_cb (GtkWidget *widget, EphyTab *tab)
+{
+#ifdef DEBUG_MARCO
+ g_print ("GtkMozEmbed destroy signal on EphyTab\n");
+#endif
+ g_object_unref (tab);
+}
+
+static void
+ephy_tab_init (EphyTab *tab)
+{
+ GObject *embed, *embed_widget;
+ EphyEmbedShell *shell;
+
+ tab->priv = g_new0 (EphyTabPrivate, 1);
+
+ shell = ephy_shell_get_embed_shell (ephy_shell);
+
+ tab->priv->embed = ephy_embed_new (G_OBJECT(shell));
+
+ tab->priv->window = NULL;
+ tab->priv->is_active = FALSE;
+ *tab->priv->status_message = '\0';
+ tab->priv->load_status = TAB_LOAD_NONE;
+ tab->priv->load_percent = 0;
+ tab->priv->title = NULL;
+ tab->priv->location = NULL;
+ tab->priv->total_requests = 0;
+ tab->priv->cur_requests = 0;
+ tab->priv->width = -1;
+ tab->priv->height = -1;
+
+
+ embed = G_OBJECT (tab->priv->embed);
+ embed_widget = G_OBJECT (tab->priv->embed);
+
+ /* set a pointer in the embed's widget back to the tab */
+ g_object_set_data (embed_widget, "EphyTab", tab);
+
+ g_signal_connect (embed_widget, "parent_set",
+ G_CALLBACK (ephy_tab_parent_set_cb),
+ tab);
+ g_signal_connect (embed_widget, "destroy",
+ GTK_SIGNAL_FUNC (ephy_tab_embed_destroy_cb),
+ tab);
+ g_signal_connect (embed, "ge_link_message",
+ GTK_SIGNAL_FUNC (ephy_tab_link_message_cb),
+ tab);
+ g_signal_connect (embed, "ge_js_status",
+ GTK_SIGNAL_FUNC (ephy_tab_js_status_cb),
+ tab);
+ g_signal_connect (embed, "ge_location",
+ GTK_SIGNAL_FUNC (ephy_tab_location_cb),
+ tab);
+ g_signal_connect (embed, "ge_title",
+ GTK_SIGNAL_FUNC (ephy_tab_title_cb),
+ tab);
+ g_signal_connect (embed, "ge_zoom_change",
+ GTK_SIGNAL_FUNC (ephy_tab_zoom_changed_cb),
+ tab);
+ g_signal_connect (embed, "ge_net_state",
+ GTK_SIGNAL_FUNC (ephy_tab_net_state_cb),
+ tab);
+ g_signal_connect (embed, "ge_new_window",
+ GTK_SIGNAL_FUNC (ephy_tab_new_window_cb),
+ tab);
+ g_signal_connect (embed, "ge_visibility",
+ GTK_SIGNAL_FUNC (ephy_tab_visibility_cb),
+ tab);
+ g_signal_connect (embed, "ge_destroy_brsr",
+ GTK_SIGNAL_FUNC (ephy_tab_destroy_brsr_cb),
+ tab);
+ g_signal_connect (embed, "ge_open_uri",
+ GTK_SIGNAL_FUNC (ephy_tab_open_uri_cb),
+ tab);
+ g_signal_connect (embed, "ge_size_to",
+ GTK_SIGNAL_FUNC (ephy_tab_size_to_cb),
+ tab);
+ g_signal_connect (embed, "ge_dom_mouse_click",
+ GTK_SIGNAL_FUNC (ephy_tab_dom_mouse_click_cb),
+ tab);
+ g_signal_connect (embed, "ge_dom_mouse_down",
+ GTK_SIGNAL_FUNC (ephy_tab_dom_mouse_down_cb),
+ tab);
+ g_signal_connect (embed, "ge_security_change",
+ GTK_SIGNAL_FUNC (ephy_tab_security_change_cb),
+ tab);
+}
+
+/* Destructor */
+
+static void
+ephy_tab_finalize (GObject *object)
+{
+ EphyTab *tab;
+
+ g_return_if_fail (IS_EPHY_TAB (object));
+
+ tab = EPHY_TAB (object);
+
+ g_return_if_fail (tab->priv != NULL);
+
+ g_idle_remove_by_data (tab->priv->embed);
+
+ g_free (tab->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+
+#ifdef DEBUG_MARCO
+ g_print ("EphyTab finalized %p\n", tab);
+#endif
+}
+
+/* Public functions */
+
+EphyTab *
+ephy_tab_new ()
+{
+ EphyTab *tab;
+
+ tab = EPHY_TAB (g_object_new (EPHY_TAB_TYPE, NULL));
+ g_return_val_if_fail (tab->priv != NULL, NULL);
+ return tab;
+}
+
+static void
+ephy_tab_set_load_status (EphyTab *tab,
+ TabLoadStatus status)
+{
+ if (status == TAB_LOAD_COMPLETED)
+ {
+ Session *s;
+ s = ephy_shell_get_session (ephy_shell);
+ session_save (s, SESSION_CRASHED);
+ }
+
+ if (ephy_tab_get_is_active (tab) &&
+ status == TAB_LOAD_COMPLETED)
+ {
+ tab->priv->load_status = TAB_LOAD_NONE;
+ }
+ else
+ {
+ tab->priv->load_status = status;
+ }
+}
+
+EphyEmbed *
+ephy_tab_get_embed (EphyTab *tab)
+{
+ g_return_val_if_fail (IS_EPHY_TAB (G_OBJECT (tab)), NULL);
+
+ return tab->priv->embed;
+}
+
+void
+ephy_tab_set_window (EphyTab *tab, EphyWindow *window)
+{
+ g_return_if_fail (IS_EPHY_TAB (G_OBJECT (tab)));
+ if (window) g_return_if_fail (IS_EPHY_WINDOW (G_OBJECT (window)));
+
+ tab->priv->window = window;
+}
+
+EphyWindow *
+ephy_tab_get_window (EphyTab *tab)
+{
+ g_return_val_if_fail (IS_EPHY_TAB (G_OBJECT (tab)), NULL);
+
+ return tab->priv->window;
+}
+
+static void
+ephy_tab_update_color (EphyTab *tab)
+{
+ TabLoadStatus status = ephy_tab_get_load_status (tab);
+ EphyNotebookPageLoadStatus page_status = 0;
+ GtkWidget *nb;
+
+ nb = ephy_window_get_notebook (tab->priv->window);
+
+ switch (status)
+ {
+ case TAB_LOAD_NONE:
+ page_status = EPHY_NOTEBOOK_TAB_LOAD_NORMAL;
+ break;
+ case TAB_LOAD_STARTED:
+ page_status = EPHY_NOTEBOOK_TAB_LOAD_LOADING;
+ break;
+ case TAB_LOAD_COMPLETED:
+ page_status = EPHY_NOTEBOOK_TAB_LOAD_COMPLETED;
+ break;
+ }
+
+ ephy_notebook_set_page_status (EPHY_NOTEBOOK (nb),
+ GTK_WIDGET (tab->priv->embed),
+ page_status);
+}
+
+void
+ephy_tab_set_is_active (EphyTab *tab, gboolean is_active)
+{
+ TabLoadStatus status;
+
+ g_return_if_fail (IS_EPHY_TAB (G_OBJECT (tab)));
+
+ tab->priv->is_active = is_active;
+
+ status = ephy_tab_get_load_status (tab);
+ if (status == TAB_LOAD_COMPLETED)
+ {
+ ephy_tab_set_load_status (tab, TAB_LOAD_NONE);
+ }
+ ephy_tab_update_color (tab);
+}
+
+gboolean
+ephy_tab_get_is_active (EphyTab *tab)
+{
+ g_return_val_if_fail (IS_EPHY_TAB (G_OBJECT (tab)), FALSE);
+
+ return tab->priv->is_active;
+}
+
+gboolean
+ephy_tab_get_visibility (EphyTab *tab)
+{
+ return tab->priv->visibility;
+}
+
+void
+ephy_tab_get_size (EphyTab *tab, int *width, int *height)
+{
+ *width = tab->priv->width;
+ *height = tab->priv->height;
+}
+
+static void
+ephy_tab_set_visibility (EphyTab *tab,
+ gboolean visible)
+{
+ g_return_if_fail (tab->priv->window != NULL);
+
+ /* FIXME show/hide the tab widget */
+
+ tab->priv->visibility = visible;
+}
+
+/* Private callbacks for embed signals */
+
+static void
+ephy_tab_link_message_cb (EphyEmbed *embed,
+ const char *message,
+ EphyTab *tab)
+{
+ if (!tab->priv->is_active) return;
+
+ g_strlcpy (tab->priv->status_message,
+ message, 255);
+
+ ephy_window_update_control (tab->priv->window,
+ StatusbarMessageControl);
+}
+
+static void
+ephy_tab_js_status_cb (EphyEmbed *embed,
+ const char *status,
+ EphyTab *tab)
+{
+ if (!tab->priv->is_active)
+ return;
+
+ g_strlcpy (tab->priv->status_message,
+ status, 255);
+
+ ephy_window_update_control (tab->priv->window,
+ StatusbarMessageControl);
+}
+
+static void
+ephy_tab_location_cb (EphyEmbed *embed, EphyTab *tab)
+{
+ if (tab->priv->location) g_free (tab->priv->location);
+ ephy_embed_get_location (embed, TRUE, FALSE,
+ &tab->priv->location);
+
+ if (tab->priv->is_active)
+ {
+ ephy_window_update_control (tab->priv->window, LocationControl);
+ ephy_window_update_control (tab->priv->window, NavControl);
+ }
+}
+
+static void
+ephy_tab_zoom_changed_cb (EphyEmbed *embed, gint zoom, EphyTab *tab)
+{
+ if (tab->priv->is_active)
+ {
+ ephy_window_update_control (tab->priv->window, ZoomControl);
+ }
+}
+
+static void
+ephy_tab_set_title (EphyTab *tab, const char *title)
+{
+ GtkWidget *nb;
+
+ nb = ephy_window_get_notebook (tab->priv->window);
+ ephy_notebook_set_page_title (EPHY_NOTEBOOK (nb),
+ GTK_WIDGET (tab->priv->embed),
+ title);
+}
+
+static void
+ephy_tab_title_cb (EphyEmbed *embed, EphyTab *tab)
+{
+ if (tab->priv->title) g_free (tab->priv->title);
+ ephy_embed_get_title (embed, &tab->priv->title);
+
+ if (*(tab->priv->title) == '\0')
+ {
+ g_free (tab->priv->title);
+ tab->priv->title = g_strdup (_("Untitled"));
+ }
+
+ ephy_tab_set_title (tab, tab->priv->title);
+
+ if (tab->priv->is_active)
+ {
+ ephy_window_update_control (tab->priv->window,
+ TitleControl);
+ }
+}
+
+static int
+build_load_percent (int bytes_loaded, int max_bytes_loaded)
+{
+ if (max_bytes_loaded > 0)
+ {
+ return (bytes_loaded * 100) / max_bytes_loaded;
+ }
+ else
+ {
+ return -1;
+ }
+}
+
+static char *
+get_host_name_from_uri (const char *uri)
+{
+ GnomeVFSURI *vfs_uri = NULL;
+ const char *host = NULL;
+ char *result;
+
+ if (uri)
+ {
+ vfs_uri = gnome_vfs_uri_new (uri);
+ }
+
+ if (vfs_uri)
+ {
+ host = gnome_vfs_uri_get_host_name (vfs_uri);
+ }
+
+ if (!host)
+ {
+ host = _("site");
+ }
+
+ result = g_strdup (host);
+
+ if (vfs_uri) gnome_vfs_uri_unref (vfs_uri);
+
+ return result;
+}
+
+static void
+build_net_state_message (char *message,
+ const char *uri,
+ EmbedState flags)
+{
+ const char *msg = NULL;
+ char *host;
+
+ host = get_host_name_from_uri (uri);
+
+ /* IS_REQUEST and IS_NETWORK can be both set */
+
+ if (flags & EMBED_STATE_IS_REQUEST)
+ {
+ if (flags & EMBED_STATE_REDIRECTING)
+ {
+ msg = _("Redirecting to %s...");
+ }
+ else if (flags & EMBED_STATE_TRANSFERRING)
+ {
+ msg = _("Transferring data from %s...");
+ }
+ else if (flags & EMBED_STATE_NEGOTIATING)
+ {
+ msg = _("Waiting for authorization from %s...");
+ }
+ }
+
+ if (flags & EMBED_STATE_IS_NETWORK)
+ {
+ if (flags & EMBED_STATE_START)
+ {
+ msg = _("Loading %s...");
+ }
+ else if (flags & EMBED_STATE_STOP)
+ {
+ msg = _("Done.");
+ }
+ }
+
+ if (msg)
+ {
+ g_snprintf (message, 255, msg, host);
+ }
+
+ g_free (host);
+}
+
+static void
+build_progress_from_requests (EphyTab *tab, EmbedState state)
+{
+ int load_percent;
+
+ if (state & EMBED_STATE_IS_REQUEST)
+ {
+ if (state & EMBED_STATE_START)
+ {
+ tab->priv->total_requests ++;
+ }
+ else if (state & EMBED_STATE_STOP)
+ {
+ tab->priv->cur_requests ++;
+ }
+
+ load_percent = build_load_percent (tab->priv->cur_requests,
+ tab->priv->total_requests);
+ if (load_percent > tab->priv->load_percent)
+ {
+ tab->priv->load_percent = load_percent;
+ }
+ }
+}
+
+static void
+ensure_location (EphyTab *tab, const char *uri)
+{
+ if (tab->priv->location == NULL)
+ {
+ tab->priv->location = g_strdup (uri);
+ ephy_window_update_control (tab->priv->window,
+ LocationControl);
+ }
+}
+
+static void
+ephy_tab_net_state_cb (EphyEmbed *embed, const char *uri,
+ EmbedState state, EphyTab *tab)
+{
+ build_net_state_message (tab->priv->status_message, uri, state);
+
+ ephy_window_update_control (tab->priv->window,
+ StatusbarMessageControl);
+
+ if (state & EMBED_STATE_IS_NETWORK)
+ {
+ if (state & EMBED_STATE_START)
+ {
+ tab->priv->total_requests = 0;
+ tab->priv->cur_requests = 0;
+ tab->priv->load_percent = 0;
+
+ ensure_location (tab, uri);
+
+ ephy_tab_set_load_status (tab, TAB_LOAD_STARTED);
+
+ ephy_window_update_control (tab->priv->window,
+ NavControl);
+ ephy_window_update_control (tab->priv->window,
+ SpinnerControl);
+ ephy_tab_update_color (tab);
+ }
+ else if (state & EMBED_STATE_STOP)
+ {
+ tab->priv->load_percent = 0;
+
+ ephy_tab_set_load_status (tab, TAB_LOAD_COMPLETED);
+
+ ephy_window_update_control (tab->priv->window,
+ NavControl);
+ ephy_window_update_control (tab->priv->window,
+ SpinnerControl);
+ ephy_tab_update_color (tab);
+ }
+ }
+
+ build_progress_from_requests (tab, state);
+
+ ephy_window_update_control (tab->priv->window,
+ StatusbarProgressControl);
+}
+
+static void
+ephy_tab_new_window_cb (EphyEmbed *embed, EphyEmbed **new_embed,
+ EmbedChromeMask chromemask, EphyTab *tab)
+{
+ EphyTab *new_tab;
+ EphyWindow *window;
+ gboolean open_in_tab;
+
+ open_in_tab = (chromemask & EMBED_CHROME_OPENASCHROME) ?
+ FALSE :
+ eel_gconf_get_boolean (CONF_TABS_TABBED_POPUPS);
+
+ if (open_in_tab)
+ {
+ window = ephy_tab_get_window (tab);
+ }
+ else
+ {
+ window = ephy_window_new ();
+ ephy_window_set_chrome (window, chromemask);
+ }
+
+ new_tab = ephy_tab_new ();
+ ephy_window_add_tab (window, new_tab, FALSE);
+
+ *new_embed = ephy_tab_get_embed (new_tab);
+}
+
+static gboolean
+let_me_resize_hack (gpointer data)
+{
+ gtk_widget_set_size_request (GTK_WIDGET(data),
+ -1, -1);
+ return FALSE;
+}
+
+static void
+ephy_tab_visibility_cb (EphyEmbed *embed, gboolean visibility,
+ EphyTab *tab)
+{
+ EphyWindow *window;
+
+ if (visibility)
+ {
+ gtk_widget_show (GTK_WIDGET(embed));
+ }
+ else
+ {
+ gtk_widget_hide (GTK_WIDGET(embed));
+ }
+
+ ephy_tab_set_visibility (tab, visibility);
+
+ window = ephy_tab_get_window (tab);
+ g_return_if_fail (window != NULL);
+
+ ephy_window_update_control (window, WindowVisibilityControl);
+}
+
+static void
+ephy_tab_destroy_brsr_cb (EphyEmbed *embed, EphyTab *tab)
+{
+ EphyWindow *window;
+
+ window = ephy_tab_get_window (tab);
+
+ ephy_window_remove_tab (window, tab);
+}
+
+static gint
+ephy_tab_open_uri_cb (EphyEmbed *embed, const char *uri,
+ EphyTab *tab)
+{
+ return FALSE;
+}
+
+static void
+ephy_tab_size_to_cb (EphyEmbed *embed, gint width, gint height,
+ EphyTab *tab)
+{
+ GList *tabs;
+ EphyWindow *window;
+ GtkWidget *widget;
+ EmbedChromeMask chromemask;
+
+ tab->priv->width = width;
+ tab->priv->height = height;
+
+ window = ephy_tab_get_window (tab);
+ tabs = (GList *) ephy_window_get_tabs (window);
+ widget = GTK_WIDGET (embed);
+ chromemask = ephy_window_get_chrome (window);
+
+ /* Do not resize window with multiple tabs.
+ * Do not resize window already showed because
+ * it's not possible to calculate a sensible window
+ * size based on the embed size */
+ if (g_list_length (tabs) == 1 && !tab->priv->visibility)
+ {
+ gtk_widget_set_size_request
+ (widget, width, height);
+
+ /* HACK reset widget requisition after the container
+ * has been resized. It appears to be the only way
+ * to have the window sized according to embed
+ * size correctly.
+ * We dont do it for XUL dialogs because in that case
+ * a "forced" requisition appear correct.
+ */
+ if (!(chromemask & EMBED_CHROME_OPENASCHROME))
+ {
+ g_idle_add (let_me_resize_hack, embed);
+ }
+ }
+}
+
+static gint
+ephy_tab_dom_mouse_click_cb (EphyEmbed *embed,
+ EphyEmbedEvent *event,
+ EphyTab *tab)
+{
+ return FALSE;
+}
+
+static void
+ephy_tab_show_embed_popup (EphyTab *tab, EphyEmbedEvent *event)
+{
+ EphyEmbedPopup *popup;
+ EphyWindow *window;
+ EphyEmbed *embed;
+
+ window = ephy_tab_get_window (tab);
+ embed = ephy_tab_get_embed (tab);
+
+ popup = EPHY_EMBED_POPUP (ephy_window_get_popup_factory (window));
+ ephy_embed_popup_set_event (popup, event);
+ ephy_embed_popup_show (popup, embed);
+}
+
+static gint
+ephy_tab_dom_mouse_down_cb (EphyEmbed *embed,
+ EphyEmbedEvent *event,
+ EphyTab *tab)
+{
+ EphyWindow *window;
+ int button;
+ EmbedEventContext context;
+
+ g_assert (IS_EPHY_EMBED_EVENT(event));
+
+ window = ephy_tab_get_window (tab);
+ g_return_val_if_fail (window != NULL, FALSE);
+
+ ephy_embed_event_get_mouse_button (event, &button);
+ ephy_embed_event_get_context (event, &context);
+
+ if (button == 2)
+ {
+ ephy_tab_show_embed_popup (tab, event);
+ }
+ else if (button == 1
+ && (context & EMBED_CONTEXT_LINK))
+ {
+ GValue *value;
+
+ ephy_embed_event_get_property (event, "link", &value);
+ ephy_shell_new_tab (ephy_shell, window, tab,
+ g_value_get_string (value), 0);
+ }
+ else if (button == 1
+ && !(context & EMBED_CONTEXT_LINK
+ || context & EMBED_CONTEXT_EMAIL_LINK
+ || context & EMBED_CONTEXT_INPUT))
+ {
+ /* paste url */
+ gtk_selection_convert (GTK_WIDGET (window),
+ GDK_SELECTION_PRIMARY,
+ GDK_SELECTION_TYPE_STRING,
+ GDK_CURRENT_TIME);
+ }
+
+ return FALSE;
+}
+
+static void
+ephy_tab_security_change_cb (EphyEmbed *embed, EmbedSecurityLevel level,
+ EphyTab *tab)
+{
+ if (!tab->priv->is_active) return;
+
+ ephy_window_update_control (tab->priv->window,
+ StatusbarSecurityControl);
+}
+
+TabLoadStatus
+ephy_tab_get_load_status (EphyTab *tab)
+{
+ return tab->priv->load_status;
+}
+
+int
+ephy_tab_get_load_percent (EphyTab *tab)
+{
+ return tab->priv->load_percent;
+}
+
+const char *
+ephy_tab_get_status_message (EphyTab *tab)
+{
+ if (tab->priv->status_message)
+ {
+ return tab->priv->status_message;
+ }
+ else
+ {
+ return " ";
+ }
+}
+
+const char *
+ephy_tab_get_title (EphyTab *tab)
+{
+ if (tab->priv->title &&
+ g_utf8_strlen(tab->priv->title, -1))
+ {
+ return tab->priv->title;
+ }
+ else
+ {
+ return _("Untitled");
+ }
+}
+
+const char *
+ephy_tab_get_location (EphyTab *tab)
+{
+ return tab->priv->location;
+}
+
+void
+ephy_tab_set_location (EphyTab *tab,
+ char *location)
+{
+ if (tab->priv->location) g_free (tab->priv->location);
+ tab->priv->location = location;
+}
+
+void
+ephy_tab_update_control (EphyTab *tab,
+ TabControlID id)
+{
+ switch (id)
+ {
+ case TAB_CONTROL_TITLE:
+ ephy_tab_set_title (tab, tab->priv->title);
+ break;
+ }
+}
diff --git a/src/ephy-tab.h b/src/ephy-tab.h
new file mode 100644
index 000000000..02e06746f
--- /dev/null
+++ b/src/ephy-tab.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EPHY_TAB_H
+#define EPHY_TAB_H
+
+#include "ephy-embed.h"
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+typedef struct EphyTabClass EphyTabClass;
+
+#define EPHY_TAB_TYPE (ephy_tab_get_type ())
+#define EPHY_TAB(obj) (GTK_CHECK_CAST ((obj), EPHY_TAB_TYPE, EphyTab))
+#define EPHY_TAB_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), EPHY_TAB, EphyTabClass))
+#define IS_EPHY_TAB(obj) (GTK_CHECK_TYPE ((obj), EPHY_TAB_TYPE))
+#define IS_EPHY_TAB_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), EPHY_TAB))
+
+typedef struct EphyTab EphyTab;
+typedef struct EphyTabPrivate EphyTabPrivate;
+
+typedef enum
+{
+ TAB_CONTROL_TITLE
+} TabControlID;
+
+typedef enum
+{
+ TAB_LOAD_NONE,
+ TAB_LOAD_STARTED,
+ TAB_LOAD_COMPLETED
+} TabLoadStatus;
+
+struct EphyTab
+{
+ GObject parent;
+ EphyTabPrivate *priv;
+};
+
+struct EphyTabClass
+{
+ GObjectClass parent_class;
+};
+
+/* Include the header down here to resolve circular dependency */
+#include "ephy-window.h"
+
+GType ephy_tab_get_type (void);
+
+EphyTab *ephy_tab_new (void);
+
+EphyEmbed *ephy_tab_get_embed (EphyTab *tab);
+
+void ephy_tab_set_window (EphyTab *tab,
+ EphyWindow *window);
+
+EphyWindow *ephy_tab_get_window (EphyTab *tab);
+
+void ephy_tab_set_is_active (EphyTab *tab,
+ gboolean is_active);
+
+gboolean ephy_tab_get_is_active (EphyTab *tab);
+
+gboolean ephy_tab_get_visibility (EphyTab *tab);
+
+TabLoadStatus ephy_tab_get_load_status (EphyTab *tab);
+
+int ephy_tab_get_load_percent (EphyTab *tab);
+
+const char *ephy_tab_get_status_message (EphyTab *tab);
+
+const char *ephy_tab_get_title (EphyTab *tab);
+
+const char *ephy_tab_get_location (EphyTab *tab);
+
+void ephy_tab_set_location (EphyTab *tab,
+ char *location);
+
+void ephy_tab_get_size (EphyTab *tab,
+ int *width,
+ int *height);
+
+void ephy_tab_update_control (EphyTab *tab,
+ TabControlID id);
+
+G_END_DECLS
+
+#endif
diff --git a/src/ephy-window.c b/src/ephy-window.c
new file mode 100644
index 000000000..311d6202c
--- /dev/null
+++ b/src/ephy-window.c
@@ -0,0 +1,1428 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "ephy-window.h"
+#include "ephy-favorites-menu.h"
+#include "ephy-state.h"
+#include "ephy-gobject-misc.h"
+#include "statusbar.h"
+#include "toolbar.h"
+#include "ppview-toolbar.h"
+#include "window-commands.h"
+#include "find-dialog.h"
+#include "history-dialog.h"
+#include "popup-commands.h"
+#include "ephy-shell.h"
+#include "ephy-bonobo-extensions.h"
+#include "eel-gconf-extensions.h"
+#include "ephy-prefs.h"
+#include "ephy-embed-utils.h"
+
+#include <string.h>
+#include <bonobo/bonobo-window.h>
+#include <bonobo/bonobo-i18n.h>
+#include <bonobo/bonobo-ui-util.h>
+#include <bonobo/bonobo-ui-component.h>
+#include <libgnomevfs/gnome-vfs-uri.h>
+#include <gtk/gtk.h>
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#include <gdk/gdkx.h>
+#include <gdk/gdkkeysyms.h>
+
+#define CHARSET_MENU_PATH "/menu/View/EncodingMenuPlaceholder"
+#define GO_FAVORITES_PATH "/menu/Go/Favorites"
+
+#define GO_BACK_CMD_PATH "/commands/GoBack"
+#define GO_FORWARD_CMD_PATH "/commands/GoForward"
+#define GO_UP_CMD_PATH "/commands/GoUp"
+#define EDIT_FIND_NEXT_CMD_PATH "/commands/EditFindNext"
+#define EDIT_FIND_PREV_CMD_PATH "/commands/EditFindPrev"
+#define VIEW_MENUBAR_PATH "/commands/View Menubar"
+#define VIEW_STATUSBAR_PATH "/commands/View Statusbar"
+#define VIEW_TOOLBAR_PATH "/commands/View Toolbar"
+#define VIEW_BOOKMARKSBAR_PATH "/commands/View BookmarksBar"
+#define VIEW_FULLSCREEN_PATH "/commands/View Fullscreen"
+
+#define ID_VIEW_MENUBAR "View Menubar"
+#define ID_VIEW_STATUSBAR "View Statusbar"
+#define ID_VIEW_TOOLBAR "View Toolbar"
+#define ID_VIEW_BOOKMARKSBAR "View BookmarksBar"
+#define ID_VIEW_FULLSCREEN "View Fullscreen"
+
+static BonoboUIVerb ephy_verbs [] = {
+ BONOBO_UI_VERB ("EditFind", (BonoboUIVerbFn)window_cmd_edit_find),
+ BONOBO_UI_VERB ("FilePrint", (BonoboUIVerbFn)window_cmd_file_print),
+ BONOBO_UI_VERB ("GoStop", (BonoboUIVerbFn)window_cmd_go_stop),
+ BONOBO_UI_VERB ("GoReload", (BonoboUIVerbFn)window_cmd_go_reload),
+ BONOBO_UI_VERB ("GoBack", (BonoboUIVerbFn)window_cmd_go_back),
+ BONOBO_UI_VERB ("GoForward", (BonoboUIVerbFn)window_cmd_go_forward),
+ BONOBO_UI_VERB ("GoGo", (BonoboUIVerbFn)window_cmd_go_go),
+ BONOBO_UI_VERB ("GoUp", (BonoboUIVerbFn)window_cmd_go_up),
+ BONOBO_UI_VERB ("GoHome", (BonoboUIVerbFn)window_cmd_go_home),
+ BONOBO_UI_VERB ("GoMyportal", (BonoboUIVerbFn)window_cmd_go_myportal),
+ BONOBO_UI_VERB ("GoLocation", (BonoboUIVerbFn)window_cmd_go_location),
+ BONOBO_UI_VERB ("FileNew", (BonoboUIVerbFn)window_cmd_new),
+ BONOBO_UI_VERB ("FileNewWindow", (BonoboUIVerbFn)window_cmd_new_window),
+ BONOBO_UI_VERB ("FileNewTab", (BonoboUIVerbFn)window_cmd_new_tab),
+ BONOBO_UI_VERB ("FileOpen", (BonoboUIVerbFn)window_cmd_file_open),
+ BONOBO_UI_VERB ("FileSaveAs", (BonoboUIVerbFn)window_cmd_file_save_as),
+ BONOBO_UI_VERB ("FileCloseTab", (BonoboUIVerbFn)window_cmd_file_close_tab),
+ BONOBO_UI_VERB ("FileCloseWindow", (BonoboUIVerbFn)window_cmd_file_close_window),
+ BONOBO_UI_VERB ("FileSendTo", (BonoboUIVerbFn)window_cmd_file_send_to),
+ BONOBO_UI_VERB ("EditCut", (BonoboUIVerbFn)window_cmd_edit_cut),
+ BONOBO_UI_VERB ("EditCopy", (BonoboUIVerbFn)window_cmd_edit_copy),
+ BONOBO_UI_VERB ("EditPaste", (BonoboUIVerbFn)window_cmd_edit_paste),
+ BONOBO_UI_VERB ("EditSelectAll", (BonoboUIVerbFn)window_cmd_edit_select_all),
+ BONOBO_UI_VERB ("EditPrefs", (BonoboUIVerbFn)window_cmd_edit_prefs),
+ BONOBO_UI_VERB ("SettingsToolbarEditor", (BonoboUIVerbFn)window_cmd_settings_toolbar_editor),
+ BONOBO_UI_VERB ("Zoom In", (BonoboUIVerbFn)window_cmd_view_zoom_in),
+ BONOBO_UI_VERB ("EditFindNext", (BonoboUIVerbFn)window_cmd_edit_find_next),
+ BONOBO_UI_VERB ("EditFindPrev", (BonoboUIVerbFn)window_cmd_edit_find_prev),
+ BONOBO_UI_VERB ("Zoom Out", (BonoboUIVerbFn)window_cmd_view_zoom_out),
+ BONOBO_UI_VERB ("Zoom Normal", (BonoboUIVerbFn)window_cmd_view_zoom_normal),
+ BONOBO_UI_VERB ("ViewPageSource", (BonoboUIVerbFn)window_cmd_view_page_source),
+ BONOBO_UI_VERB ("BookmarksAddDefault", (BonoboUIVerbFn)window_cmd_bookmarks_add_default),
+ BONOBO_UI_VERB ("BookmarksEdit", (BonoboUIVerbFn)window_cmd_bookmarks_edit),
+ BONOBO_UI_VERB ("ToolsHistory", (BonoboUIVerbFn)window_cmd_tools_history),
+ BONOBO_UI_VERB ("ToolsPDM", (BonoboUIVerbFn)window_cmd_tools_pdm),
+ BONOBO_UI_VERB ("TabsNext", (BonoboUIVerbFn)window_cmd_tabs_next),
+ BONOBO_UI_VERB ("TabsPrevious", (BonoboUIVerbFn)window_cmd_tabs_previous),
+ BONOBO_UI_VERB ("TabsMoveLeft", (BonoboUIVerbFn)window_cmd_tabs_move_left),
+ BONOBO_UI_VERB ("TabsMoveRight", (BonoboUIVerbFn)window_cmd_tabs_move_right),
+ BONOBO_UI_VERB ("TabsDetach", (BonoboUIVerbFn)window_cmd_tabs_detach),
+ BONOBO_UI_VERB ("HelpContents", (BonoboUIVerbFn)window_cmd_help_manual),
+ BONOBO_UI_VERB ("About", (BonoboUIVerbFn)window_cmd_help_about),
+
+ BONOBO_UI_VERB_END
+};
+
+static BonoboUIVerb ephy_popup_verbs [] = {
+ BONOBO_UI_VERB ("EPOpenInNewWindow", (BonoboUIVerbFn)popup_cmd_new_window),
+ BONOBO_UI_VERB ("EPOpenInNewTab", (BonoboUIVerbFn)popup_cmd_new_tab),
+ BONOBO_UI_VERB ("EPAddBookmark", (BonoboUIVerbFn)popup_cmd_add_bookmark),
+ BONOBO_UI_VERB ("EPOpenImageInNewWindow", (BonoboUIVerbFn)popup_cmd_image_in_new_window),
+ BONOBO_UI_VERB ("EPOpenImageInNewTab", (BonoboUIVerbFn)popup_cmd_image_in_new_tab),
+ BONOBO_UI_VERB ("DPOpenFrameInNewWindow", (BonoboUIVerbFn)popup_cmd_frame_in_new_window),
+ BONOBO_UI_VERB ("DPOpenFrameInNewTab", (BonoboUIVerbFn)popup_cmd_frame_in_new_tab),
+ BONOBO_UI_VERB ("DPAddFrameBookmark", (BonoboUIVerbFn)popup_cmd_add_frame_bookmark),
+ BONOBO_UI_VERB ("DPViewSource", (BonoboUIVerbFn)popup_cmd_view_source),
+
+ BONOBO_UI_VERB_END
+};
+
+struct EphyWindowPrivate
+{
+ EphyFavoritesMenu *fav_menu;
+ PPViewToolbar *ppview_toolbar;
+ Toolbar *toolbar;
+ Statusbar *statusbar;
+ GtkNotebook *notebook;
+ EphyTab *active_tab;
+ GtkWidget *sidebar;
+ EphyEmbedPopupBW *embed_popup;
+ EphyDialog *find_dialog;
+ EphyDialog *history_dialog;
+ EphyDialog *history_sidebar;
+ EmbedChromeMask chrome_mask;
+ gboolean ignore_layout_toggles;
+ gboolean has_default_size;
+ gboolean closing;
+};
+
+static void
+ephy_window_class_init (EphyWindowClass *klass);
+static void
+ephy_window_init (EphyWindow *gs);
+static void
+ephy_window_finalize (GObject *object);
+static void
+ephy_window_show (GtkWidget *widget);
+static void
+ephy_window_notebook_switch_page_cb (GtkNotebook *notebook,
+ GtkNotebookPage *page,
+ guint page_num,
+ EphyWindow *window);
+
+static void
+ephy_window_tab_detached_cb (EphyNotebook *notebook, gint page,
+ gint x, gint y, gpointer data);
+
+
+static GObjectClass *parent_class = NULL;
+
+GType
+ephy_window_get_type (void)
+{
+ static GType ephy_window_type = 0;
+
+ if (ephy_window_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (EphyWindowClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) ephy_window_class_init,
+ NULL,
+ NULL, /* class_data */
+ sizeof (EphyWindow),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) ephy_window_init
+ };
+
+ ephy_window_type = g_type_register_static (BONOBO_TYPE_WINDOW,
+ "EphyWindow",
+ &our_info, 0);
+ }
+
+ return ephy_window_type;
+}
+
+static void
+ephy_window_class_init (EphyWindowClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = ephy_window_finalize;
+
+ widget_class->show = ephy_window_show;
+}
+
+static
+gboolean
+ephy_window_key_press_event_cb (GtkWidget *widget,
+ GdkEventKey *event,
+ EphyWindow *window)
+{
+ int page;
+
+ if ((event->state & GDK_Shift_L) || (event->state & GDK_Shift_R))
+ return FALSE;
+
+ if ((event->state & GDK_Alt_L) || (event->state & GDK_Alt_R))
+ {
+ page = event->keyval - GDK_0 -1;
+
+ if (page == -1) page = 9;
+
+ if (page>=-1 && page<=9)
+ {
+ gtk_notebook_set_current_page
+ (GTK_NOTEBOOK (window->priv->notebook),
+ page == -1 ? -1 : page);
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static void
+ephy_window_selection_received_cb (GtkWidget *widget,
+ GtkSelectionData *selection_data,
+ guint time, EphyWindow *window)
+{
+ EphyTab *tab;
+
+ if (selection_data->length <= 0 || selection_data->data == NULL)
+ return;
+
+ tab = ephy_window_get_active_tab (window);
+ ephy_shell_new_tab (ephy_shell, window, tab,
+ selection_data->data, 0);
+}
+
+static void
+save_window_state (GtkWidget *win)
+{
+ EphyWindow *window = EPHY_WINDOW (win);
+
+ if (!(window->priv->chrome_mask & EMBED_CHROME_OPENASPOPUP) &&
+ !(window->priv->chrome_mask & EMBED_CHROME_OPENASFULLSCREEN))
+ {
+ ephy_state_save_window (win, "main_window");
+ }
+}
+
+static gboolean
+ephy_window_configure_event_cb (GtkWidget *widget,
+ GdkEventConfigure *event,
+ gpointer data)
+{
+ save_window_state (widget);
+ return FALSE;
+}
+
+static gboolean
+ephy_window_state_event_cb (GtkWidget *widget,
+ GdkEventWindowState *event,
+ gpointer data)
+{
+ save_window_state (widget);
+ return FALSE;
+}
+
+static void
+setup_bonobo_window (EphyWindow *window,
+ BonoboUIComponent **ui_component)
+{
+ BonoboWindow *win = BONOBO_WINDOW(window);
+ BonoboUIContainer *container;
+ Bonobo_UIContainer corba_container;
+
+ container = bonobo_window_get_ui_container (win);
+
+ bonobo_ui_engine_config_set_path (bonobo_window_get_ui_engine (win),
+ "/apps/ephy/UIConfig/kvps");
+
+ corba_container = BONOBO_OBJREF (container);
+
+ *ui_component = bonobo_ui_component_new_default ();
+
+ bonobo_ui_component_set_container (*ui_component,
+ corba_container,
+ NULL);
+
+ bonobo_ui_util_set_ui (*ui_component,
+ DATADIR,
+ "epiphany-ui.xml",
+ "ephy", NULL);
+
+ /* Key handling */
+ g_signal_connect(G_OBJECT(win),
+ "key-press-event",
+ G_CALLBACK(ephy_window_key_press_event_cb),
+ window);
+
+ g_signal_connect (G_OBJECT(win), "configure_event",
+ G_CALLBACK (ephy_window_configure_event_cb), NULL);
+ g_signal_connect (G_OBJECT(win), "window_state_event",
+ G_CALLBACK (ephy_window_state_event_cb), NULL);
+
+ g_signal_connect (G_OBJECT(win),
+ "selection-received",
+ G_CALLBACK (ephy_window_selection_received_cb),
+ window);
+}
+
+static EphyEmbedPopupBW *
+setup_popup_factory (EphyWindow *window,
+ BonoboUIComponent *ui_component)
+{
+ EphyEmbedPopupBW *popup;
+
+ popup = ephy_window_get_popup_factory (window);
+ g_object_set_data (G_OBJECT(popup), "EphyWindow", window);
+ bonobo_ui_component_add_verb_list_with_data (ui_component,
+ ephy_popup_verbs,
+ popup);
+
+ return popup;
+}
+
+static GtkNotebook *
+setup_notebook (EphyWindow *window)
+{
+ GtkNotebook *notebook;
+
+ notebook = GTK_NOTEBOOK (ephy_notebook_new ());
+ gtk_notebook_set_scrollable (notebook, TRUE);
+ gtk_notebook_set_show_border (notebook, FALSE);
+ gtk_notebook_set_show_tabs (notebook, FALSE);
+
+ g_signal_connect_after (G_OBJECT (notebook), "switch_page",
+ G_CALLBACK (
+ ephy_window_notebook_switch_page_cb),
+ window);
+
+ g_signal_connect (G_OBJECT (notebook), "tab_detached",
+ G_CALLBACK (ephy_window_tab_detached_cb),
+ NULL);
+
+ gtk_widget_show (GTK_WIDGET (notebook));
+
+ return notebook;
+}
+
+static void
+view_toolbar_changed_cb (BonoboUIComponent *component,
+ const char *path,
+ Bonobo_UIComponent_EventType type,
+ const char *state,
+ EphyWindow *window)
+{
+ EmbedChromeMask mask;
+
+ if (window->priv->ignore_layout_toggles) return;
+
+ mask = ephy_window_get_chrome (window);
+ mask ^= EMBED_CHROME_TOOLBARON;
+ ephy_window_set_chrome (window, mask);
+}
+
+static void
+view_statusbar_changed_cb (BonoboUIComponent *component,
+ const char *path,
+ Bonobo_UIComponent_EventType type,
+ const char *state,
+ EphyWindow *window)
+{
+ EmbedChromeMask mask;
+
+ if (window->priv->ignore_layout_toggles) return;
+
+ mask = ephy_window_get_chrome (window);
+ mask ^= EMBED_CHROME_STATUSBARON;
+ ephy_window_set_chrome (window, mask);
+}
+
+static void
+view_fullscreen_changed_cb (BonoboUIComponent *component,
+ const char *path,
+ Bonobo_UIComponent_EventType type,
+ const char *state,
+ EphyWindow *window)
+{
+ EmbedChromeMask mask;
+
+ if (window->priv->ignore_layout_toggles) return;
+
+ mask = ephy_window_get_chrome (window);
+ mask ^= EMBED_CHROME_OPENASFULLSCREEN;
+ mask |= EMBED_CHROME_DEFAULT;
+ ephy_window_set_chrome (window, mask);
+}
+
+static void
+update_layout_toggles (EphyWindow *window)
+{
+ BonoboUIComponent *ui_component = BONOBO_UI_COMPONENT (window->ui_component);
+ EmbedChromeMask mask = window->priv->chrome_mask;
+
+ window->priv->ignore_layout_toggles = TRUE;
+
+ ephy_bonobo_set_toggle_state (ui_component, VIEW_TOOLBAR_PATH,
+ mask & EMBED_CHROME_TOOLBARON);
+ ephy_bonobo_set_toggle_state (ui_component, VIEW_STATUSBAR_PATH,
+ mask & EMBED_CHROME_STATUSBARON);
+ ephy_bonobo_set_toggle_state (ui_component, VIEW_FULLSCREEN_PATH,
+ mask & EMBED_CHROME_OPENASFULLSCREEN);
+
+ window->priv->ignore_layout_toggles = FALSE;
+}
+
+static void
+setup_layout_menus (EphyWindow *window)
+{
+ BonoboUIComponent *ui_component = BONOBO_UI_COMPONENT (window->ui_component);
+
+ bonobo_ui_component_add_listener (ui_component, ID_VIEW_TOOLBAR,
+ (BonoboUIListenerFn)view_toolbar_changed_cb,
+ window);
+ bonobo_ui_component_add_listener (ui_component, ID_VIEW_STATUSBAR,
+ (BonoboUIListenerFn)view_statusbar_changed_cb,
+ window);
+ bonobo_ui_component_add_listener (ui_component, ID_VIEW_FULLSCREEN,
+ (BonoboUIListenerFn)view_fullscreen_changed_cb,
+ window);
+}
+
+static void
+ephy_window_init (EphyWindow *window)
+{
+ BonoboUIComponent *ui_component;
+ Session *session;
+
+ session = ephy_shell_get_session (ephy_shell);
+
+ window->priv = g_new0 (EphyWindowPrivate, 1);
+ window->priv->embed_popup = NULL;
+ window->priv->active_tab = NULL;
+ window->priv->chrome_mask = 0;
+ window->priv->ignore_layout_toggles = FALSE;
+ window->priv->closing = FALSE;
+ window->priv->has_default_size = FALSE;
+
+ /* Setup the window and connect verbs */
+ setup_bonobo_window (window, &ui_component);
+ window->ui_component = G_OBJECT (ui_component);
+ bonobo_ui_component_add_verb_list_with_data (ui_component,
+ ephy_verbs,
+ window);
+ setup_layout_menus (window);
+
+ /* Setup the embed popups factory */
+ window->priv->embed_popup = setup_popup_factory (window,
+ ui_component);
+
+ bonobo_ui_component_freeze (ui_component, NULL);
+
+ /* Setup menubar */
+ ephy_embed_utils_build_charsets_submenu (ui_component,
+ CHARSET_MENU_PATH,
+ (BonoboUIVerbFn)window_cmd_set_charset,
+ window);
+ window->priv->fav_menu = ephy_favorites_menu_new (window);
+ ephy_favorites_menu_set_path (window->priv->fav_menu, GO_FAVORITES_PATH);
+
+ /* Setup toolbar and statusbar */
+ window->priv->toolbar = toolbar_new (window);
+ window->priv->statusbar = statusbar_new (window);
+ window->priv->ppview_toolbar = ppview_toolbar_new (window);
+
+ /* Setup window contents */
+ window->priv->notebook = setup_notebook (window);
+ bonobo_window_set_contents (BONOBO_WINDOW (window),
+ GTK_WIDGET (window->priv->notebook));
+
+ bonobo_ui_component_thaw (ui_component, NULL);
+
+ g_object_ref (ephy_shell);
+
+ /*Once window is fully created, add it to the session list*/
+ session_add_window (session, window);
+}
+
+static void
+save_window_chrome (EphyWindow *window)
+{
+ EmbedChromeMask flags = window->priv->chrome_mask;
+
+ if (flags & EMBED_CHROME_OPENASPOPUP)
+ {
+ }
+ else if (flags & EMBED_CHROME_PPVIEWTOOLBARON)
+ {
+ }
+ else if (flags & EMBED_CHROME_OPENASFULLSCREEN)
+ {
+ eel_gconf_set_boolean (CONF_WINDOWS_FS_SHOW_TOOLBARS,
+ flags & EMBED_CHROME_TOOLBARON);
+ eel_gconf_set_boolean (CONF_WINDOWS_FS_SHOW_STATUSBAR,
+ flags & EMBED_CHROME_STATUSBARON);
+ }
+ else
+ {
+ eel_gconf_set_boolean (CONF_WINDOWS_SHOW_TOOLBARS,
+ flags & EMBED_CHROME_TOOLBARON);
+ eel_gconf_set_boolean (CONF_WINDOWS_SHOW_STATUSBAR,
+ flags & EMBED_CHROME_STATUSBARON);
+ }
+}
+
+static void
+remove_from_session (EphyWindow *window)
+{
+ Session *session;
+
+ session = ephy_shell_get_session (ephy_shell);
+ g_return_if_fail (session != NULL);
+
+ session_remove_window (session, window);
+}
+
+static void
+ephy_window_finalize (GObject *object)
+{
+ EphyWindow *window;
+
+ g_return_if_fail (IS_EPHY_WINDOW (object));
+
+ window = EPHY_WINDOW (object);
+
+ g_return_if_fail (window->priv != NULL);
+
+ remove_from_session (window);
+
+ if (window->priv->embed_popup)
+ {
+ g_object_unref (G_OBJECT (window->priv->embed_popup));
+ }
+
+ g_object_unref (G_OBJECT (window->priv->toolbar));
+ g_object_unref (G_OBJECT (window->priv->statusbar));
+
+ if (window->priv->find_dialog)
+ {
+ g_object_unref (G_OBJECT (window->priv->find_dialog));
+ }
+
+ if (window->priv->history_dialog)
+ {
+ g_object_remove_weak_pointer
+ (G_OBJECT(window->priv->history_dialog),
+ (gpointer *)&window->priv->history_dialog);
+ }
+
+ g_free (window->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+
+#ifdef DEBUG_MARCO
+ g_print ("Ephy Window finalized %p\n", window);
+#endif
+
+ g_object_unref (ephy_shell);
+}
+
+EphyWindow *
+ephy_window_new (void)
+{
+ return EPHY_WINDOW (g_object_new (EPHY_WINDOW_TYPE, NULL));
+}
+
+static void
+dock_item_set_visibility (EphyWindow *window,
+ const char *path,
+ gboolean visibility)
+{
+ ephy_bonobo_set_hidden (BONOBO_UI_COMPONENT(window->ui_component),
+ path,
+ !visibility);
+}
+
+EmbedChromeMask
+ephy_window_get_chrome (EphyWindow *window)
+{
+ return window->priv->chrome_mask;
+}
+
+static void
+wmspec_change_state (gboolean add,
+ GdkWindow *window,
+ GdkAtom state1,
+ GdkAtom state2)
+{
+ XEvent xev;
+
+ #define _NET_WM_STATE_REMOVE 0 /* remove/unset property */
+ #define _NET_WM_STATE_ADD 1 /* add/set property */
+ #define _NET_WM_STATE_TOGGLE 2 /* toggle property */
+
+ xev.xclient.type = ClientMessage;
+ xev.xclient.serial = 0;
+ xev.xclient.send_event = True;
+ xev.xclient.display = gdk_display;
+ xev.xclient.window = GDK_WINDOW_XID (window);
+ xev.xclient.message_type = gdk_x11_get_xatom_by_name ("_NET_WM_STATE");
+ xev.xclient.format = 32;
+ xev.xclient.data.l[0] = add ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
+ xev.xclient.data.l[1] = gdk_x11_atom_to_xatom (state1);
+ xev.xclient.data.l[2] = gdk_x11_atom_to_xatom (state2);
+
+ XSendEvent (gdk_display, GDK_WINDOW_XID (gdk_get_default_root_window ()),
+ False,
+ SubstructureRedirectMask | SubstructureNotifyMask,
+ &xev);
+}
+
+static void
+window_set_fullscreen_mode (EphyWindow *window, gboolean active)
+{
+ GdkWindow *gdk_window;
+
+ gdk_window = GTK_WIDGET(window)->window;
+
+ if (gdk_net_wm_supports (gdk_atom_intern ("_NET_WM_STATE_FULLSCREEN",
+ FALSE)))
+ {
+ wmspec_change_state (active,
+ gdk_window,
+ gdk_atom_intern ("_NET_WM_STATE_FULLSCREEN",
+ FALSE),
+ GDK_NONE);
+ }
+ else
+ {
+ g_warning ("NET_WM_STATE_FULLSCREEN not supported");
+ }
+}
+
+static void
+translate_default_chrome (EmbedChromeMask *chrome_mask)
+{
+ /* keep only not layout flags */
+ *chrome_mask &= (EMBED_CHROME_WINDOWRAISED |
+ EMBED_CHROME_WINDOWLOWERED |
+ EMBED_CHROME_CENTERSCREEN |
+ EMBED_CHROME_OPENASDIALOG |
+ EMBED_CHROME_OPENASCHROME |
+ EMBED_CHROME_OPENASPOPUP |
+ EMBED_CHROME_OPENASFULLSCREEN);
+
+ /* Load defaults */
+ if (*chrome_mask & EMBED_CHROME_OPENASFULLSCREEN)
+ {
+ if (eel_gconf_get_boolean (CONF_WINDOWS_FS_SHOW_STATUSBAR))
+ {
+ *chrome_mask |= EMBED_CHROME_STATUSBARON;
+ }
+ if (eel_gconf_get_boolean (CONF_WINDOWS_FS_SHOW_TOOLBARS))
+ {
+ *chrome_mask |= EMBED_CHROME_TOOLBARON;
+ }
+ }
+ else
+ {
+ if (eel_gconf_get_boolean (CONF_WINDOWS_SHOW_STATUSBAR))
+ {
+ *chrome_mask |= EMBED_CHROME_STATUSBARON;
+ }
+ if (eel_gconf_get_boolean (CONF_WINDOWS_SHOW_TOOLBARS))
+ {
+ *chrome_mask |= EMBED_CHROME_TOOLBARON;
+ }
+
+ *chrome_mask |= EMBED_CHROME_PERSONALTOOLBARON;
+ *chrome_mask |= EMBED_CHROME_MENUBARON;
+ }
+}
+
+void
+ephy_window_set_chrome (EphyWindow *window,
+ EmbedChromeMask flags)
+{
+ gboolean toolbar, ppvtoolbar, statusbar;
+
+ if (flags & EMBED_CHROME_DEFAULT)
+ {
+ translate_default_chrome (&flags);
+ }
+
+ dock_item_set_visibility (window, "/menu",
+ flags & EMBED_CHROME_MENUBARON);
+
+ toolbar = (flags & EMBED_CHROME_TOOLBARON) != FALSE;
+ toolbar_set_visibility (window->priv->toolbar,
+ toolbar);
+
+ statusbar = (flags & EMBED_CHROME_STATUSBARON) != FALSE;
+ statusbar_set_visibility (window->priv->statusbar,
+ statusbar);
+
+ ppvtoolbar = (flags & EMBED_CHROME_PPVIEWTOOLBARON) != FALSE;
+ ppview_toolbar_set_old_chrome (window->priv->ppview_toolbar,
+ window->priv->chrome_mask);
+ ppview_toolbar_set_visibility (window->priv->ppview_toolbar,
+ ppvtoolbar);
+
+ /* set fullscreen only when it's really changed */
+ if ((window->priv->chrome_mask & EMBED_CHROME_OPENASFULLSCREEN) !=
+ (flags & EMBED_CHROME_OPENASFULLSCREEN))
+ {
+ save_window_chrome (window);
+ window_set_fullscreen_mode (window,
+ flags & EMBED_CHROME_OPENASFULLSCREEN);
+ }
+
+ window->priv->chrome_mask = flags;
+
+ update_layout_toggles (window);
+
+ save_window_chrome (window);
+}
+
+GtkWidget *
+ephy_window_get_notebook (EphyWindow *window)
+{
+ return GTK_WIDGET (window->priv->notebook);
+}
+
+void
+ephy_window_add_tab (EphyWindow *window,
+ EphyTab *tab,
+ gboolean jump_to)
+{
+ GtkWidget *widget;
+
+ g_return_if_fail (IS_EPHY_WINDOW (window));
+ g_return_if_fail (IS_EPHY_TAB (tab));
+
+ ephy_tab_set_window (tab, window);
+
+ widget = GTK_WIDGET(ephy_tab_get_embed (tab));
+
+ ephy_notebook_insert_page (EPHY_NOTEBOOK (window->priv->notebook),
+ widget,
+ EPHY_NOTEBOOK_INSERT_GROUPED,
+ jump_to);
+}
+
+void
+ephy_window_jump_to_tab (EphyWindow *window,
+ EphyTab *tab)
+{
+ GtkWidget *widget;
+ int page;
+
+ widget = GTK_WIDGET(ephy_tab_get_embed (tab));
+
+ page = gtk_notebook_page_num
+ (window->priv->notebook, widget);
+ gtk_notebook_set_current_page
+ (window->priv->notebook, page);
+}
+
+static EphyTab *
+get_tab_from_page_num (GtkNotebook *notebook, gint page_num)
+{
+ EphyTab *tab;
+ GtkWidget *embed_widget;
+
+ if (page_num < 0) return NULL;
+
+ embed_widget = gtk_notebook_get_nth_page (notebook, page_num);
+
+ g_return_val_if_fail (GTK_IS_WIDGET (embed_widget), NULL);
+ tab = g_object_get_data (G_OBJECT (embed_widget), "EphyTab");
+ g_return_val_if_fail (IS_EPHY_TAB (G_OBJECT (tab)), NULL);
+
+ return tab;
+}
+
+static EphyTab *
+real_get_active_tab (EphyWindow *window, int page_num)
+{
+ if (page_num == -1)
+ {
+ page_num = gtk_notebook_get_current_page (window->priv->notebook);
+ }
+
+ return get_tab_from_page_num (window->priv->notebook, page_num);
+}
+
+void
+ephy_window_remove_tab (EphyWindow *window,
+ EphyTab *tab)
+{
+ GtkWidget *embed;
+
+ g_return_if_fail (IS_EPHY_WINDOW (window));
+ g_return_if_fail (IS_EPHY_TAB (tab));
+
+ window->priv->active_tab = NULL;
+
+ embed = GTK_WIDGET (ephy_tab_get_embed (tab));
+
+ ephy_notebook_remove_page (EPHY_NOTEBOOK (window->priv->notebook),
+ embed);
+}
+
+void
+ephy_window_load_url (EphyWindow *window,
+ const char *url)
+{
+ EphyEmbed *embed;
+
+ g_return_if_fail (IS_EPHY_WINDOW(window));
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+ g_return_if_fail (url != NULL);
+
+ ephy_embed_load_url (embed, url);
+}
+
+void ephy_window_activate_location (EphyWindow *window)
+{
+ toolbar_activate_location (window->priv->toolbar);
+}
+
+void
+ephy_window_show (GtkWidget *widget)
+{
+ EphyWindow *window = EPHY_WINDOW(widget);
+ EphyTab *tab;
+ int w = -1, h = -1;
+
+ if (!window->priv->chrome_mask)
+ {
+ ephy_window_set_chrome (window, EMBED_CHROME_DEFAULT);
+ }
+
+ tab = ephy_window_get_active_tab (window);
+ if (tab) ephy_tab_get_size (tab, &w, &h);
+
+ if (!window->priv->has_default_size && w == -1 && h == -1)
+ {
+ ephy_state_load_window (GTK_WIDGET(window),
+ "main_window",
+ 600, 500, TRUE);
+ window->priv->has_default_size = TRUE;
+ }
+
+ GTK_WIDGET_CLASS (parent_class)->show (widget);
+}
+
+static void
+update_status_message (EphyWindow *window)
+{
+ const char *message;
+ EphyTab *tab;
+
+ tab = ephy_window_get_active_tab (window);
+ g_return_if_fail (tab != NULL);
+
+ message = ephy_tab_get_status_message (tab);
+ g_return_if_fail (message != NULL);
+
+ statusbar_set_message (STATUSBAR(window->priv->statusbar),
+ message);
+}
+
+static void
+update_progress (EphyWindow *window)
+{
+ EphyTab *tab;
+ int load_percent;
+
+ tab = ephy_window_get_active_tab (window);
+ g_return_if_fail (tab != NULL);
+
+ load_percent = ephy_tab_get_load_percent (tab);
+
+ statusbar_set_progress (STATUSBAR(window->priv->statusbar),
+ load_percent);
+}
+
+static void
+update_security (EphyWindow *window)
+{
+ EphyEmbed *embed;
+ EmbedSecurityLevel level;
+ char *description;
+ char *state = NULL;
+ gboolean secure;
+ char *tooltip;
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+
+ if (ephy_embed_get_security_level (embed, &level, &description) != G_OK)
+ {
+ level = STATE_IS_UNKNOWN;
+ description = NULL;
+ }
+
+ secure = FALSE;
+ switch (level)
+ {
+ case STATE_IS_UNKNOWN:
+ state = _("Unknown");
+ break;
+ case STATE_IS_INSECURE:
+ state = _("Insecure");
+ break;
+ case STATE_IS_BROKEN:
+ state = _("Broken");
+ break;
+ case STATE_IS_SECURE_MED:
+ state = _("Medium");
+ secure = TRUE;
+ break;
+ case STATE_IS_SECURE_LOW:
+ state = _("Low");
+ secure = TRUE;
+ break;
+ case STATE_IS_SECURE_HIGH:
+ state = _("High");
+ secure = TRUE;
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ if (description != NULL)
+ {
+ tooltip = g_strdup_printf (_("Security level: %s\n%s"),
+ state, description);
+ g_free (description);
+ }
+ else
+ {
+ tooltip = g_strdup_printf (_("Security level: %s"), state);
+
+ }
+
+ statusbar_set_security_state (STATUSBAR (window->priv->statusbar),
+ secure, tooltip);
+ g_free (tooltip);
+}
+
+static void
+update_nav_control (EphyWindow *window)
+{
+ /* the zoom control is updated at the same time than the navigation
+ controls. This keeps it synched most of the time, but not always,
+ because we don't get a notification when zoom changes */
+
+ gresult back, forward, up, stop;
+ EphyEmbed *embed;
+ EphyTab *tab;
+ gint zoom;
+
+ g_return_if_fail (window != NULL);
+
+ tab = ephy_window_get_active_tab (window);
+ g_return_if_fail (tab != NULL);
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+
+ back = ephy_embed_can_go_back (embed);
+ forward = ephy_embed_can_go_forward (embed);
+ up = ephy_embed_can_go_up (embed);
+ stop = ephy_tab_get_load_status (tab) & TAB_LOAD_STARTED;
+
+ toolbar_button_set_sensitive (window->priv->toolbar,
+ TOOLBAR_BACK_BUTTON,
+ back == G_OK ? TRUE : FALSE);
+ toolbar_button_set_sensitive (window->priv->toolbar,
+ TOOLBAR_FORWARD_BUTTON,
+ forward == G_OK ? TRUE : FALSE);
+ toolbar_button_set_sensitive (window->priv->toolbar,
+ TOOLBAR_UP_BUTTON,
+ up == G_OK ? TRUE : FALSE);
+ toolbar_button_set_sensitive (window->priv->toolbar,
+ TOOLBAR_STOP_BUTTON,
+ stop);
+ if (ephy_embed_zoom_get (embed, &zoom) == G_OK)
+ {
+ toolbar_set_zoom (window->priv->toolbar, zoom);
+ }
+
+ ephy_bonobo_set_sensitive (BONOBO_UI_COMPONENT(window->ui_component),
+ GO_BACK_CMD_PATH, !back);
+ ephy_bonobo_set_sensitive (BONOBO_UI_COMPONENT(window->ui_component),
+ GO_FORWARD_CMD_PATH, !forward);
+ ephy_bonobo_set_sensitive (BONOBO_UI_COMPONENT(window->ui_component),
+ GO_UP_CMD_PATH, !up);
+}
+
+static void
+update_title_control (EphyWindow *window)
+{
+ EphyTab *tab;
+ const char *title;
+
+ tab = ephy_window_get_active_tab (window);
+ g_return_if_fail (tab != NULL);
+
+ title = ephy_tab_get_title (tab);
+
+ if (title)
+ {
+ gtk_window_set_title (GTK_WINDOW(window),
+ title);
+ }
+}
+
+static void
+update_location_control (EphyWindow *window)
+{
+ EphyTab *tab;
+ const char *location;
+
+ tab = ephy_window_get_active_tab (window);
+ g_return_if_fail (tab != NULL);
+
+ location = ephy_tab_get_location (tab);
+
+ if (!location) location = "";
+
+ toolbar_set_location (window->priv->toolbar,
+ location);
+}
+
+static void
+update_favorites_control (EphyWindow *window)
+{
+ ephy_favorites_menu_update (window->priv->fav_menu);
+}
+
+static void
+update_favicon_control (EphyWindow *window)
+{
+ toolbar_update_favicon (window->priv->toolbar);
+}
+
+static void
+update_find_control (EphyWindow *window)
+{
+ gboolean can_go_next, can_go_prev;
+
+ if (window->priv->find_dialog)
+ {
+ can_go_next = find_dialog_can_go_next
+ (FIND_DIALOG(window->priv->find_dialog));
+ can_go_prev = find_dialog_can_go_prev
+ (FIND_DIALOG(window->priv->find_dialog));
+
+ ephy_bonobo_set_sensitive (BONOBO_UI_COMPONENT(window->ui_component),
+ EDIT_FIND_NEXT_CMD_PATH, can_go_next);
+ ephy_bonobo_set_sensitive (BONOBO_UI_COMPONENT(window->ui_component),
+ EDIT_FIND_PREV_CMD_PATH, can_go_prev);
+ }
+}
+
+static void
+update_window_visibility (EphyWindow *window)
+{
+ GList *l;
+
+ l = ephy_window_get_tabs (window);
+ for (; l != NULL; l = l->next)
+ {
+ EphyTab *tab = EPHY_TAB(l->data);
+ g_return_if_fail (IS_EPHY_TAB(tab));
+
+ if (ephy_tab_get_visibility (tab))
+ {
+ gtk_widget_show (GTK_WIDGET(window));
+ return;
+ }
+ }
+ g_list_free (l);
+
+ if (GTK_WIDGET_VISIBLE (GTK_WIDGET (window)))
+ {
+ gtk_widget_hide (GTK_WIDGET (window));
+ }
+}
+
+static void
+update_spinner_control (EphyWindow *window)
+{
+ GList *l;
+
+ l = ephy_window_get_tabs (window);
+ for (; l != NULL; l = l->next)
+ {
+ EphyTab *tab = EPHY_TAB(l->data);
+ g_return_if_fail (IS_EPHY_TAB(tab));
+
+ if (ephy_tab_get_load_status (tab) & TAB_LOAD_STARTED)
+ {
+ toolbar_spinner_start (window->priv->toolbar);
+ return;
+ }
+ }
+ g_list_free (l);
+
+ toolbar_spinner_stop (window->priv->toolbar);
+}
+
+void
+ephy_window_update_control (EphyWindow *window,
+ ControlID control)
+{
+ g_return_if_fail (IS_EPHY_WINDOW (window));
+
+ switch (control)
+ {
+ case StatusbarMessageControl:
+ update_status_message (window);
+ break;
+ case StatusbarProgressControl:
+ update_progress (window);
+ break;
+ case StatusbarSecurityControl:
+ update_security (window);
+ break;
+ case FindControl:
+ update_find_control (window);
+ break;
+ case ZoomControl:
+ /* the zoom control is updated at the same time than the navigation
+ controls. This keeps it synched most of the time, but not always,
+ because we don't get a notification when zoom changes */
+ case NavControl:
+ update_nav_control (window);
+ break;
+ case TitleControl:
+ update_title_control (window);
+ break;
+ case WindowVisibilityControl:
+ update_window_visibility (window);
+ break;
+ case SpinnerControl:
+ update_spinner_control (window);
+ break;
+ case LocationControl:
+ update_location_control (window);
+ break;
+ case FaviconControl:
+ update_favicon_control (window);
+ break;
+ case FavoritesControl:
+ update_favorites_control (window);
+ break;
+ default:
+ g_warning ("unknown control specified for updating");
+ break;
+ }
+}
+
+void
+ephy_window_update_all_controls (EphyWindow *window)
+{
+ g_return_if_fail (IS_EPHY_WINDOW (window));
+
+ if (ephy_window_get_active_tab (window) != NULL)
+ {
+ update_nav_control (window);
+ update_title_control (window);
+ update_location_control (window);
+ update_favicon_control (window);
+ update_status_message (window);
+ update_progress (window);
+ update_security (window);
+ update_find_control (window);
+ update_spinner_control (window);
+ }
+}
+
+EphyTab *
+ephy_window_get_active_tab (EphyWindow *window)
+{
+ g_return_val_if_fail (IS_EPHY_WINDOW (window), NULL);
+
+ return window->priv->active_tab;
+}
+
+EphyEmbed *
+ephy_window_get_active_embed (EphyWindow *window)
+{
+ EphyTab *tab;
+
+ tab = ephy_window_get_active_tab (window);
+
+ if (tab)
+ {
+ g_return_val_if_fail (IS_EPHY_WINDOW (G_OBJECT (window)),
+ NULL);
+ return ephy_tab_get_embed (tab);
+ }
+ else return NULL;
+}
+
+EphyEmbedPopupBW *
+ephy_window_get_popup_factory (EphyWindow *window)
+{
+ if (!window->priv->embed_popup)
+ {
+ window->priv->embed_popup = ephy_embed_popup_bw_new
+ (BONOBO_WINDOW(window));
+ ephy_embed_popup_connect_verbs
+ (EPHY_EMBED_POPUP (window->priv->embed_popup),
+ BONOBO_UI_COMPONENT (window->ui_component));
+ }
+
+ return window->priv->embed_popup;
+}
+
+GList *
+ephy_window_get_tabs (EphyWindow *window)
+{
+ GList *tabs = NULL;
+ GtkWidget *w;
+ int i = 0;
+
+ while ((w = gtk_notebook_get_nth_page (window->priv->notebook, i)) != NULL)
+ {
+ EphyTab *tab;
+
+ tab = g_object_get_data (G_OBJECT (w), "EphyTab");
+ g_return_val_if_fail (IS_EPHY_TAB (G_OBJECT (tab)), NULL);
+
+ tabs = g_list_append (tabs, tab);
+ i++;
+ }
+
+ return tabs;
+}
+
+static void
+save_old_embed_status (EphyTab *tab, EphyWindow *window)
+{
+ /* save old tab location status */
+ ephy_tab_set_location (tab, toolbar_get_location (window->priv->toolbar));
+}
+
+static void
+update_embed_dialogs (EphyWindow *window,
+ EphyTab *tab)
+{
+ EphyEmbed *embed;
+ EphyDialog *find_dialog = window->priv->find_dialog;
+ EphyDialog *history_dialog = window->priv->history_dialog;
+ EphyDialog *history_sidebar = window->priv->history_sidebar;
+
+ embed = ephy_tab_get_embed (tab);
+
+ if (find_dialog)
+ {
+ ephy_embed_dialog_set_embed
+ (EPHY_EMBED_DIALOG(find_dialog),
+ embed);
+ }
+
+ if (history_dialog)
+ {
+ ephy_embed_dialog_set_embed
+ (EPHY_EMBED_DIALOG(history_dialog),
+ embed);
+ }
+
+ if (history_sidebar)
+ {
+ ephy_embed_dialog_set_embed
+ (EPHY_EMBED_DIALOG(history_sidebar),
+ embed);
+ }
+}
+
+static void
+ephy_window_notebook_switch_page_cb (GtkNotebook *notebook,
+ GtkNotebookPage *page,
+ guint page_num,
+ EphyWindow *window)
+{
+ EphyTab *tab, *old_tab;
+
+ if (window->priv->closing) return;
+
+ g_return_if_fail (IS_EPHY_WINDOW (window));
+
+ /* get the new tab */
+ tab = real_get_active_tab (window, page_num);
+
+ /* update old tab */
+ old_tab = window->priv->active_tab;
+ if (old_tab && tab != old_tab)
+ {
+ g_return_if_fail (IS_EPHY_TAB (G_OBJECT (old_tab)));
+ ephy_tab_set_is_active (old_tab, FALSE);
+ save_old_embed_status (old_tab, window);
+ }
+
+ /* update new tab */
+ window->priv->active_tab = tab;
+ ephy_tab_set_is_active (tab, TRUE);
+
+ update_embed_dialogs (window, tab);
+
+ /* update window controls */
+ ephy_window_update_all_controls (window);
+}
+
+static void
+find_dialog_search_cb (FindDialog *dialog, EphyWindow *window)
+{
+ ephy_window_update_control (window, FindControl);
+}
+
+EphyDialog *
+ephy_window_get_find_dialog (EphyWindow *window)
+{
+ EphyDialog *dialog;
+ EphyEmbed *embed;
+
+ if (window->priv->find_dialog)
+ {
+ return window->priv->find_dialog;
+ }
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_val_if_fail (GTK_IS_WINDOW(window), NULL);
+ dialog = find_dialog_new_with_parent (GTK_WIDGET(window),
+ embed);
+
+ g_signal_connect (dialog, "search",
+ G_CALLBACK (find_dialog_search_cb),
+ window);
+
+ window->priv->find_dialog = dialog;
+
+ return dialog;
+}
+
+void
+ephy_window_show_history (EphyWindow *window)
+{
+ EphyEmbed *embed;
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+
+ window->priv->history_dialog = history_dialog_new_with_parent
+ (GTK_WIDGET(window),
+ embed,
+ FALSE);
+ g_object_add_weak_pointer
+ (G_OBJECT(window->priv->history_dialog),
+ (gpointer *)&window->priv->history_dialog);
+
+ ephy_dialog_show (window->priv->history_dialog);
+}
+
+void
+ephy_window_set_zoom (EphyWindow *window,
+ gint zoom)
+{
+ EphyEmbed *embed;
+
+ g_return_if_fail (IS_EPHY_WINDOW (window));
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+
+ ephy_embed_zoom_set (embed, zoom, TRUE);
+}
+
+Toolbar *
+ephy_window_get_toolbar (EphyWindow *window)
+{
+ return window->priv->toolbar;
+}
+
+void
+ephy_window_tab_detached_cb (EphyNotebook *notebook, gint page,
+ gint x, gint y, gpointer data)
+{
+ EphyTab *tab;
+ EphyWindow *window;
+ GtkWidget *src_page;
+
+ src_page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), page);
+ tab = get_tab_from_page_num (GTK_NOTEBOOK (notebook), page);
+ window = ephy_window_new ();
+ ephy_notebook_move_page (notebook,
+ EPHY_NOTEBOOK (ephy_window_get_notebook (window)),
+ src_page, 0);
+ ephy_tab_set_window (tab, window);
+ gtk_widget_show (GTK_WIDGET (window));
+}
diff --git a/src/ephy-window.h b/src/ephy-window.h
new file mode 100644
index 000000000..315cd8cca
--- /dev/null
+++ b/src/ephy-window.h
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EPHY_WINDOW_H
+#define EPHY_WINDOW_H
+
+#include "ephy-embed.h"
+#include "ephy-embed-persist.h"
+#include "ephy-embed-popup-bw.h"
+#include "ephy-dialog.h"
+#include "ephy-notebook.h"
+#include <glib-object.h>
+#include <glib.h>
+#include <bonobo/bonobo-window.h>
+
+G_BEGIN_DECLS
+
+typedef struct EphyWindowClass EphyWindowClass;
+
+#define EPHY_WINDOW_TYPE (ephy_window_get_type ())
+#define EPHY_WINDOW(obj) (GTK_CHECK_CAST ((obj), EPHY_WINDOW_TYPE, EphyWindow))
+#define EPHY_WINDOW_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), EPHY_WINDOW, EphyWindowClass))
+#define IS_EPHY_WINDOW(obj) (GTK_CHECK_TYPE ((obj), EPHY_WINDOW_TYPE))
+#define IS_EPHY_WINDOW_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), EPHY_WINDOW))
+
+typedef struct EphyWindow EphyWindow;
+typedef struct EphyWindowPrivate EphyWindowPrivate;
+typedef struct Toolbar Toolbar;
+
+struct EphyWindow
+{
+ BonoboWindow parent;
+ EphyWindowPrivate *priv;
+
+ /* Public to toolbar and statusbar, dont use outside */
+ GObject *ui_component;
+};
+
+struct EphyWindowClass
+{
+ BonoboWindowClass parent_class;
+};
+
+typedef enum
+{
+ NormalMode,
+ FullscreenMode
+} EphyWindowMode;
+
+typedef enum
+{
+ TabsControl,
+ NavControl,
+ FindControl,
+ ZoomControl,
+ CharsetsControl,
+ TitleControl,
+ LocationControl,
+ FaviconControl,
+ StatusbarSecurityControl,
+ StatusbarMessageControl,
+ StatusbarProgressControl,
+ SpinnerControl,
+ WindowVisibilityControl,
+ BMAndHistoryControl,
+ TabsAppeareanceControl,
+ FavoritesControl
+} ControlID;
+
+/* Include the header down here to resolve circular dependency */
+#include "ephy-tab.h"
+
+GType ephy_window_get_type (void);
+
+EphyWindow *ephy_window_new (void);
+
+void ephy_window_set_chrome (EphyWindow *window,
+ EmbedChromeMask chrome_flags);
+
+EmbedChromeMask ephy_window_get_chrome (EphyWindow *window);
+
+GtkWidget *ephy_window_get_notebook (EphyWindow *window);
+
+void ephy_window_add_tab (EphyWindow *window,
+ EphyTab *tab,
+ gboolean jump_to);
+
+void ephy_window_remove_tab (EphyWindow *window,
+ EphyTab *tab);
+
+void ephy_window_jump_to_tab (EphyWindow *window,
+ EphyTab *tab);
+
+void ephy_window_load_url (EphyWindow *window,
+ const char *url);
+
+void ephy_window_set_zoom (EphyWindow *window,
+ gint zoom);
+
+void ephy_window_activate_location (EphyWindow *window);
+
+void ephy_window_update_control (EphyWindow *window,
+ ControlID control);
+
+void ephy_window_update_all_controls (EphyWindow *window);
+
+EphyTab *ephy_window_get_active_tab (EphyWindow *window);
+
+EphyEmbed *ephy_window_get_active_embed (EphyWindow *window);
+
+EphyEmbedPopupBW *ephy_window_get_popup_factory (EphyWindow *window);
+
+GList *ephy_window_get_tabs (EphyWindow *window);
+
+Toolbar *ephy_window_get_toolbar (EphyWindow *window);
+
+/* Dialogs */
+
+EphyDialog *ephy_window_get_find_dialog (EphyWindow *window);
+
+void ephy_window_show_history (EphyWindow *window);
+
+G_END_DECLS
+
+#endif
diff --git a/src/general-prefs.c b/src/general-prefs.c
new file mode 100755
index 000000000..f9eecf4e6
--- /dev/null
+++ b/src/general-prefs.c
@@ -0,0 +1,484 @@
+/*
+ * Copyright (C) 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "general-prefs.h"
+#include "ephy-shell.h"
+#include "ephy-prefs.h"
+#include "ephy-embed-prefs.h"
+#include "ephy-shell.h"
+#include "eel-gconf-extensions.h"
+#include "language-editor.h"
+
+#include <string.h>
+#include <gtk/gtkeditable.h>
+#include <gtk/gtkmenu.h>
+#include <gtk/gtkoptionmenu.h>
+#include <gtk/gtkmenuitem.h>
+#include <bonobo/bonobo-i18n.h>
+
+static void general_prefs_class_init (GeneralPrefsClass *klass);
+static void general_prefs_init (GeneralPrefs *dialog);
+static void general_prefs_finalize (GObject *object);
+
+/* Glade callbacks */
+void
+prefs_homepage_current_button_clicked_cb (GtkWidget *button,
+ EphyDialog *dialog);
+void
+prefs_homepage_blank_button_clicked_cb (GtkWidget *button,
+ EphyDialog *dialog);
+void
+prefs_language_more_button_clicked_cb (GtkWidget *button,
+ EphyDialog *dialog);
+
+static GObjectClass *parent_class = NULL;
+
+struct GeneralPrefsPrivate
+{
+ gpointer dummy;
+};
+
+enum
+{
+ HOMEPAGE_ENTRY_PROP,
+ NEW_PAGE_PROP,
+ AUTOCHARSET_PROP,
+ DEFAULT_CHARSET_PROP,
+ LANGUAGE_PROP
+};
+
+static const
+EphyDialogProperty properties [] =
+{
+ { HOMEPAGE_ENTRY_PROP, "homepage_entry", CONF_GENERAL_HOMEPAGE, PT_AUTOAPPLY, NULL },
+ { NEW_PAGE_PROP, "new_page_show_homepage", CONF_GENERAL_NEWPAGE_TYPE, PT_AUTOAPPLY, NULL },
+ { AUTOCHARSET_PROP, "autocharset_optionmenu", CONF_LANGUAGE_AUTODETECT_CHARSET, PT_AUTOAPPLY, NULL },
+ { DEFAULT_CHARSET_PROP, "default_charset_optionmenu", NULL, PT_NORMAL, NULL },
+ { LANGUAGE_PROP, "language_optionmenu", NULL, PT_NORMAL, NULL },
+
+ { -1, NULL, NULL }
+};
+
+static const
+struct
+{
+ char *name;
+ char *code;
+}
+languages [] =
+{
+ { _("Afrikaans"), "ak" },
+ { _("Albanian"), "sq" },
+ { _("Arabic"), "ar" },
+ { _("Azerbaijani"), "az" },
+ { _("Basque"), "eu" },
+ { _("Breton"), "br" },
+ { _("Bulgarian"), "bg" },
+ { _("Byelorussian"), "be" },
+ { _("Catalan"), "ca" },
+ { _("Chinese"), "zh" },
+ { _("Croatian"), "hr" },
+ { _("Czech"), "cs" },
+ { _("Danish"), "da" },
+ { _("Dutch"), "nl" },
+ { _("English"), "en" },
+ { _("Esperanto"), "eo" },
+ { _("Estonian"), "et" },
+ { _("Faeroese"), "fo" },
+ { _("Finnish"), "fi" },
+ { _("French"), "fr" },
+ { _("Galician"), "gl" },
+ { _("German"), "de" },
+ { _("Greek"), "el" },
+ { _("Hebrew"), "he" },
+ { _("Hungarian"), "hu" },
+ { _("Icelandic"), "is" },
+ { _("Indonesian"), "id" },
+ { _("Irish"), "ga" },
+ { _("Italian"), "it" },
+ { _("Japanese"), "ja" },
+ { _("Korean"), "ko" },
+ { _("Latvian"), "lv" },
+ { _("Lithuanian"), "lt" },
+ { _("Macedonian"), "mk" },
+ { _("Malay"), "ms" },
+ { _("Norwegian/Nynorsk"), "nn" },
+ { _("Norwegian/Bokmaal"), "nb" },
+ { _("Norwegian"), "no" },
+ { _("Polish"), "pl" },
+ { _("Portuguese"), "pt" },
+ { _("Portuguese of Brazil"), "pt-BR" },
+ { _("Romanian"), "ro" },
+ { _("Russian"), "ru" },
+ { _("Scottish"), "gd" },
+ { _("Serbian"), "sr" },
+ { _("Slovak"), "sk" },
+ { _("Slovenian"), "sl" },
+ { _("Spanish"), "es" },
+ { _("Swedish"), "sv" },
+ { _("Tamil"), "ta" },
+ { _("Turkish"), "tr" },
+ { _("Ukrainian"), "uk" },
+ { _("Vietnamian"), "vi" },
+ { _("Walloon"), "wa" },
+ { NULL, NULL }
+};
+
+GType
+general_prefs_get_type (void)
+{
+ static GType general_prefs_type = 0;
+
+ if (general_prefs_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (GeneralPrefsClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) general_prefs_class_init,
+ NULL,
+ NULL, /* class_data */
+ sizeof (GeneralPrefs),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) general_prefs_init
+ };
+
+ general_prefs_type = g_type_register_static (EPHY_DIALOG_TYPE,
+ "GeneralPrefs",
+ &our_info, 0);
+ }
+
+ return general_prefs_type;
+
+}
+
+static void
+general_prefs_class_init (GeneralPrefsClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = general_prefs_finalize;
+}
+
+static void
+default_charset_menu_changed_cb (GtkOptionMenu *option_menu,
+ EphyEmbedShell *shell)
+{
+ GList *charsets;
+ int i;
+ CharsetInfo *info;
+
+ ephy_embed_shell_get_charset_titles (shell, NULL, &charsets);
+
+ i = gtk_option_menu_get_history (option_menu);
+ charsets = g_list_nth (charsets, i);
+ g_assert (charsets != NULL);
+ info = (CharsetInfo *) charsets->data;
+ eel_gconf_set_string (CONF_LANGUAGE_DEFAULT_CHARSET,
+ info->name);
+
+ g_list_free (charsets);
+}
+
+static gint
+find_charset_in_list_cmp (gconstpointer a,
+ gconstpointer b)
+{
+ CharsetInfo *info = (CharsetInfo *)a;
+ const char *value = b;
+
+ return (strcmp (info->name, value));
+}
+
+static void
+create_default_charset_menu (GeneralPrefs *dialog)
+{
+ EphyEmbedShell *shell;
+ GList *l;
+ GList *charsets;
+ GtkWidget *menu;
+ GtkWidget *optionmenu;
+ char *value;
+
+ shell = ephy_shell_get_embed_shell (ephy_shell);
+ ephy_embed_shell_get_charset_titles (shell, NULL, &l);
+
+ menu = gtk_menu_new ();
+
+ optionmenu = ephy_dialog_get_control (EPHY_DIALOG (dialog),
+ DEFAULT_CHARSET_PROP);
+
+ for (charsets = l; charsets != NULL; charsets = charsets->next)
+ {
+ CharsetInfo *info = (CharsetInfo *) charsets->data;
+ GtkWidget *item;
+
+ item = gtk_menu_item_new_with_label (info->title);
+ gtk_menu_shell_append (GTK_MENU_SHELL(menu),
+ item);
+ gtk_widget_show (item);
+ }
+
+ gtk_option_menu_set_menu (GTK_OPTION_MENU(optionmenu), menu);
+
+ /* init value */
+ charsets = l;
+ value = eel_gconf_get_string (CONF_LANGUAGE_DEFAULT_CHARSET);
+ charsets = g_list_find_custom (charsets, (gconstpointer)value,
+ (GCompareFunc)find_charset_in_list_cmp);
+ gtk_option_menu_set_history (GTK_OPTION_MENU(optionmenu),
+ g_list_position (l, charsets));
+ g_free (value);
+
+ g_signal_connect (optionmenu, "changed",
+ G_CALLBACK (default_charset_menu_changed_cb),
+ shell);
+
+ g_list_free (l);
+}
+
+static GtkWidget *
+general_prefs_new_language_menu (GeneralPrefs *dialog)
+{
+ int i;
+ GtkWidget *menu;
+
+ menu = gtk_menu_new ();
+
+ for (i = 0; languages[i].name != NULL; i++)
+ {
+ GtkWidget *item;
+
+ item = gtk_menu_item_new_with_label (languages[i].name);
+ gtk_menu_shell_append (GTK_MENU_SHELL(menu),
+ item);
+ gtk_widget_show (item);
+ g_object_set_data (G_OBJECT(item), "desc",
+ languages[i].name);
+ }
+
+ return menu;
+}
+
+static void
+language_menu_changed_cb (GtkOptionMenu *option_menu,
+ gpointer data)
+{
+ GSList *list;
+ GSList *l = NULL;
+ int history;
+
+ list = eel_gconf_get_string_list (CONF_RENDERING_LANGUAGE);
+ l = g_slist_copy (list);
+
+ /* Subst the first item according to the optionmenu */
+ history = gtk_option_menu_get_history (option_menu);
+ l->data = languages [history].code;
+
+ eel_gconf_set_string_list (CONF_RENDERING_LANGUAGE, l);
+
+ g_slist_free (l);
+}
+
+static void
+create_language_menu (GeneralPrefs *dialog)
+{
+ GtkWidget *optionmenu;
+ GtkWidget *menu;
+ const char *value;
+ int i;
+ GSList *list;
+
+ optionmenu = ephy_dialog_get_control (EPHY_DIALOG (dialog),
+ LANGUAGE_PROP);
+
+ menu = general_prefs_new_language_menu (dialog);
+
+ gtk_option_menu_set_menu (GTK_OPTION_MENU(optionmenu), menu);
+
+ /* init value */
+ list = eel_gconf_get_string_list (CONF_RENDERING_LANGUAGE);
+ g_return_if_fail (list != NULL);
+ value = (const char *)list->data;
+
+ i = 0;
+ while (languages[i].code && strcmp (languages[i].code, value) != 0)
+ {
+ i++;
+ }
+
+ gtk_option_menu_set_history (GTK_OPTION_MENU(optionmenu), i);
+
+ g_signal_connect (optionmenu, "changed",
+ G_CALLBACK (language_menu_changed_cb),
+ NULL);
+}
+
+static void
+general_prefs_init (GeneralPrefs *dialog)
+{
+ dialog->priv = g_new0 (GeneralPrefsPrivate, 1);
+
+ ephy_dialog_construct (EPHY_DIALOG(dialog),
+ properties,
+ "prefs-dialog.glade",
+ "general_page_box");
+
+ create_default_charset_menu (dialog);
+ create_language_menu (dialog);
+}
+
+static void
+general_prefs_finalize (GObject *object)
+{
+ GeneralPrefs *dialog;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (IS_GENERAL_PREFS (object));
+
+ dialog = GENERAL_PREFS (object);
+
+ g_return_if_fail (dialog->priv != NULL);
+
+ g_free (dialog->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+EphyDialog *
+general_prefs_new (void)
+{
+ GeneralPrefs *dialog;
+
+ dialog = GENERAL_PREFS (g_object_new (GENERAL_PREFS_TYPE,
+ NULL));
+
+ return EPHY_DIALOG(dialog);
+}
+
+static void
+set_homepage_entry (EphyDialog *dialog,
+ const char *new_location)
+{
+ GtkWidget *entry;
+ int pos;
+
+ entry = ephy_dialog_get_control (dialog, HOMEPAGE_ENTRY_PROP);
+
+ gtk_editable_delete_text (GTK_EDITABLE (entry), 0, -1);
+ gtk_editable_insert_text (GTK_EDITABLE (entry), new_location,
+ g_utf8_strlen (new_location, -1),
+ &pos);
+}
+
+void
+prefs_homepage_current_button_clicked_cb (GtkWidget *button,
+ EphyDialog *dialog)
+{
+ EphyWindow *window;
+ EphyTab *tab;
+
+ window = ephy_shell_get_active_window (ephy_shell);
+ g_return_if_fail (window != NULL);
+
+ tab = ephy_window_get_active_tab (window);
+ g_return_if_fail (tab != NULL);
+
+ set_homepage_entry (dialog, ephy_tab_get_location (tab));
+}
+
+void
+prefs_homepage_blank_button_clicked_cb (GtkWidget *button,
+ EphyDialog *dialog)
+{
+ set_homepage_entry (dialog, "about:blank");
+}
+
+static void
+fill_language_editor (LanguageEditor *le)
+{
+ GSList *strings;
+ GSList *tmp;
+ int i;
+
+ /* Fill the list */
+ strings = eel_gconf_get_string_list (CONF_RENDERING_LANGUAGE);
+
+ for (tmp = strings; tmp != NULL; tmp = g_slist_next (tmp))
+ {
+ char *value = (char *)tmp->data;
+
+ i = 0;
+ while (languages[i].code && strcmp (languages[i].code, value) != 0)
+ {
+ i++;
+ }
+
+ /* FIXME unsafe, bad prefs could cause it to access random memory */
+ language_editor_add (le, languages[i].name, i);
+ }
+}
+
+static void
+language_dialog_changed_cb (LanguageEditor *le,
+ GSList *list,
+ GeneralPrefs *dialog)
+{
+ GtkWidget *optionmenu;
+ GSList *l = list;
+ GSList *langs = NULL;
+
+ optionmenu = ephy_dialog_get_control (EPHY_DIALOG (dialog),
+ LANGUAGE_PROP);
+ gtk_option_menu_set_history (GTK_OPTION_MENU(optionmenu),
+ (int)(l->data));
+
+ for (; l != NULL; l = l->next)
+ {
+ int i = (int)l->data;
+ langs = g_slist_append (langs, languages[i].code);
+ }
+
+ eel_gconf_set_string_list (CONF_RENDERING_LANGUAGE, langs);
+}
+
+void
+prefs_language_more_button_clicked_cb (GtkWidget *button,
+ EphyDialog *dialog)
+{
+ LanguageEditor *editor;
+ GtkWidget *menu;
+ GtkWidget *toplevel;
+
+ menu = general_prefs_new_language_menu (GENERAL_PREFS(dialog));
+
+ toplevel = gtk_widget_get_toplevel (button);
+ editor = language_editor_new (toplevel);
+ language_editor_set_menu (editor, menu);
+ fill_language_editor (editor);
+ ephy_dialog_set_modal (EPHY_DIALOG(editor), TRUE);
+
+ g_signal_connect (editor, "changed",
+ G_CALLBACK(language_dialog_changed_cb),
+ dialog);
+
+ ephy_dialog_show (EPHY_DIALOG(editor));
+}
diff --git a/src/general-prefs.h b/src/general-prefs.h
new file mode 100644
index 000000000..74cfa26a7
--- /dev/null
+++ b/src/general-prefs.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GENERAL_PREFS_H
+#define GENERAL_PREFS_H
+
+#include "ephy-embed-dialog.h"
+
+#include <glib-object.h>
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef struct GeneralPrefs GeneralPrefs;
+typedef struct GeneralPrefsClass GeneralPrefsClass;
+
+#define GENERAL_PREFS_TYPE (general_prefs_get_type ())
+#define GENERAL_PREFS(obj) (GTK_CHECK_CAST ((obj), GENERAL_PREFS_TYPE, GeneralPrefs))
+#define GENERAL_PREFS_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GENERAL_PREFS, GeneralPrefsClass))
+#define IS_GENERAL_PREFS(obj) (GTK_CHECK_TYPE ((obj), GENERAL_PREFS_TYPE))
+#define IS_GENERAL_PREFS_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GENERAL_PREFS))
+
+typedef struct GeneralPrefsPrivate GeneralPrefsPrivate;
+
+struct GeneralPrefs
+{
+ EphyDialog parent;
+ GeneralPrefsPrivate *priv;
+};
+
+struct GeneralPrefsClass
+{
+ EphyDialogClass parent_class;
+};
+
+GType general_prefs_get_type (void);
+
+EphyDialog *general_prefs_new (void);
+
+G_END_DECLS
+
+#endif
+
diff --git a/src/history-dialog.c b/src/history-dialog.c
new file mode 100755
index 000000000..4f5b5cc2b
--- /dev/null
+++ b/src/history-dialog.c
@@ -0,0 +1,478 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "history-dialog.h"
+#include "ephy-shell.h"
+#include "ephy-embed-shell.h"
+#include "ephy-string.h"
+#include "ephy-gui.h"
+#include "ephy-dnd.h"
+#include "ephy-node-filter.h"
+#include "ephy-history-model.h"
+#include "eggtreemodelfilter.h"
+#include "eggtreemultidnd.h"
+#include "ephy-tree-model-sort.h"
+
+#include <gtk/gtktreeview.h>
+#include <gtk/gtktreestore.h>
+#include <gtk/gtkcellrenderertext.h>
+#include <bonobo/bonobo-i18n.h>
+
+#define CONF_HISTORY_SEARCH_TEXT "/apps/epiphany/history/search_text"
+#define CONF_HISTORY_SEARCH_TIME "/apps/epiphany/history/search_time"
+
+static void history_dialog_class_init (HistoryDialogClass *klass);
+static void history_dialog_init (HistoryDialog *dialog);
+static void history_dialog_finalize (GObject *object);
+static void history_dialog_set_embedded (HistoryDialog *d,
+ gboolean embedded);
+
+
+/* Glade callbacks */
+void
+history_host_checkbutton_toggled_cb (GtkWidget *widget,
+ HistoryDialog *dialog);
+void
+history_time_optionmenu_changed_cb (GtkWidget *widget,
+ HistoryDialog *dialog);
+void
+history_entry_changed_cb (GtkWidget *widget,
+ HistoryDialog *dialog);
+void
+history_ok_button_clicked_cb (GtkWidget *button,
+ HistoryDialog *dialog);
+void
+history_clear_button_clicked_cb (GtkWidget *button,
+ HistoryDialog *dialog);
+
+
+static GObjectClass *parent_class = NULL;
+
+struct HistoryDialogPrivate
+{
+ EphyHistory *gh;
+ EphyNode *root;
+ EphyNode *pages;
+ EphyNodeFilter *filter;
+ GtkTreeView *treeview;
+ GtkTreeModel *model;
+ EphyHistoryModel *nodemodel;
+ GtkTreeModel *filtermodel;
+ EphyTreeModelSort *sortmodel;
+ gboolean group;
+ gboolean embedded;
+};
+
+enum
+{
+ PROP_0,
+ PROP_EMBEDDED
+};
+
+enum
+{
+ PROP_TREEVIEW,
+ PROP_WORD,
+ PROP_TIME
+};
+
+static const
+EphyDialogProperty properties [] =
+{
+ { PROP_TREEVIEW, "history_treeview", NULL, PT_NORMAL, NULL },
+ { PROP_WORD, "history_entry", CONF_HISTORY_SEARCH_TEXT, PT_NORMAL, NULL },
+ { PROP_TIME, "history_time_optionmenu", CONF_HISTORY_SEARCH_TIME, PT_NORMAL, NULL },
+ { -1, NULL, NULL }
+};
+
+GType
+history_dialog_get_type (void)
+{
+ static GType history_dialog_type = 0;
+
+ if (history_dialog_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (HistoryDialogClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) history_dialog_class_init,
+ NULL,
+ NULL, /* class_data */
+ sizeof (HistoryDialog),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) history_dialog_init
+ };
+
+ history_dialog_type = g_type_register_static (EPHY_EMBED_DIALOG_TYPE,
+ "HistoryDialog",
+ &our_info, 0);
+ }
+
+ return history_dialog_type;
+
+}
+
+static void
+history_dialog_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ HistoryDialog *d = HISTORY_DIALOG (object);
+
+ switch (prop_id)
+ {
+ case PROP_EMBEDDED:
+ history_dialog_set_embedded
+ (d, g_value_get_boolean (value));
+ break;
+ }
+}
+
+static void
+history_dialog_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ HistoryDialog *d = HISTORY_DIALOG (object);
+
+ switch (prop_id)
+ {
+ case PROP_EMBEDDED:
+ g_value_set_boolean (value, d->priv->embedded);
+ break;
+ }
+}
+
+
+static void
+history_dialog_class_init (HistoryDialogClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = history_dialog_finalize;
+ object_class->set_property = history_dialog_set_property;
+ object_class->get_property = history_dialog_get_property;
+
+ g_object_class_install_property (object_class,
+ PROP_EMBEDDED,
+ g_param_spec_boolean ("embedded",
+ "Show embedded in another widget",
+ "Show embedded in another widget",
+ TRUE,
+ G_PARAM_READWRITE));
+}
+
+static void
+add_column (HistoryDialog *dialog,
+ const char *title,
+ EphyHistoryModelColumn column)
+{
+ GtkTreeViewColumn *gcolumn;
+ GtkCellRenderer *renderer;
+
+ gcolumn = (GtkTreeViewColumn *) gtk_tree_view_column_new ();
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_tree_view_column_pack_start (gcolumn, renderer, TRUE);
+ gtk_tree_view_column_set_attributes (gcolumn, renderer,
+ "text", column,
+ NULL);
+ gtk_tree_view_column_set_sizing (gcolumn,
+ GTK_TREE_VIEW_COLUMN_AUTOSIZE);
+ gtk_tree_view_column_set_sort_column_id (gcolumn, column);
+ gtk_tree_view_column_set_title (gcolumn, title);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (dialog->priv->treeview),
+ gcolumn);
+}
+
+static void
+history_view_row_activated_cb (GtkTreeView *treeview,
+ GtkTreePath *path,
+ GtkTreeViewColumn *column,
+ HistoryDialog *dialog)
+{
+ GtkTreeIter iter, iter2;
+ EphyNode *node;
+ EphyEmbed *embed;
+ const char *location;
+
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (dialog->priv->sortmodel), &iter, path);
+ gtk_tree_model_sort_convert_iter_to_child_iter
+ (GTK_TREE_MODEL_SORT (dialog->priv->sortmodel), &iter2, &iter);
+ egg_tree_model_filter_convert_iter_to_child_iter
+ (EGG_TREE_MODEL_FILTER (dialog->priv->filtermodel), &iter, &iter2);
+
+ node = ephy_history_model_node_from_iter (dialog->priv->nodemodel, &iter);
+ location = ephy_node_get_property_string (node, EPHY_NODE_PAGE_PROP_LOCATION);
+ g_return_if_fail (location != NULL);
+ embed = ephy_embed_dialog_get_embed (EPHY_EMBED_DIALOG(dialog));
+ ephy_embed_load_url (embed, location);
+}
+
+static void
+node_from_sort_iter_cb (EphyTreeModelSort *model,
+ GtkTreeIter *iter,
+ void **node,
+ HistoryDialog *dialog)
+{
+ GtkTreeIter filter_iter, node_iter;
+
+ gtk_tree_model_sort_convert_iter_to_child_iter (GTK_TREE_MODEL_SORT (model),
+ &filter_iter, iter);
+ egg_tree_model_filter_convert_iter_to_child_iter (EGG_TREE_MODEL_FILTER (dialog->priv->filtermodel),
+ &node_iter, &filter_iter);
+ *node = ephy_history_model_node_from_iter (EPHY_HISTORY_MODEL (dialog->priv->nodemodel), &node_iter);
+ g_return_if_fail (*node != NULL);
+}
+
+static void
+history_dialog_setup_view (HistoryDialog *dialog)
+{
+ dialog->priv->nodemodel = ephy_history_model_new (dialog->priv->root,
+ dialog->priv->pages,
+ dialog->priv->filter);
+ dialog->priv->filtermodel = egg_tree_model_filter_new (GTK_TREE_MODEL (dialog->priv->nodemodel),
+ NULL);
+ egg_tree_model_filter_set_visible_column (EGG_TREE_MODEL_FILTER (dialog->priv->filtermodel),
+ EPHY_HISTORY_MODEL_COL_VISIBLE);
+ dialog->priv->sortmodel = EPHY_TREE_MODEL_SORT (
+ ephy_tree_model_sort_new (GTK_TREE_MODEL (dialog->priv->filtermodel)));
+ g_signal_connect_object (G_OBJECT (dialog->priv->sortmodel),
+ "node_from_iter",
+ G_CALLBACK (node_from_sort_iter_cb),
+ dialog,
+ 0);
+ gtk_tree_view_set_model (dialog->priv->treeview,
+ GTK_TREE_MODEL (dialog->priv->sortmodel));
+
+ egg_tree_multi_drag_add_drag_support (GTK_TREE_VIEW (dialog->priv->treeview));
+ ephy_dnd_enable_model_drag_source (GTK_WIDGET (dialog->priv->treeview));
+
+ add_column (dialog, _("Title"), EPHY_HISTORY_MODEL_COL_TITLE);
+ add_column (dialog, _("Location"), EPHY_HISTORY_MODEL_COL_LOCATION);
+ add_column (dialog, _("Last Visit"), EPHY_HISTORY_MODEL_COL_LAST_VISIT);
+
+ g_signal_connect (dialog->priv->treeview,
+ "row_activated",
+ G_CALLBACK (history_view_row_activated_cb),
+ dialog);
+}
+
+static GTime
+get_date_filter (int filter_type,
+ GTime atime)
+{
+ GDate date, current_date;
+ struct tm tm;
+
+ g_date_clear (&current_date, 1);
+ g_date_set_time (&current_date, time (NULL));
+
+ g_date_clear (&date, 1);
+ g_date_set_time (&date, atime);
+
+ switch (filter_type)
+ {
+ /* Always */
+ case 0:
+ return 0;
+ /* Today */
+ case 1:
+ break;
+ /* Last two days */
+ case 2:
+ g_date_subtract_days (&current_date, 1);
+ break;
+ /* Last three days */
+ case 3:
+ g_date_subtract_days (&current_date, 2);
+ break;
+ /* Week */
+ case 4:
+ g_date_subtract_days (&current_date, 7);
+ break;
+ /* Month */
+ case 5:
+ g_date_subtract_months (&current_date, 1);
+ break;
+ default:
+ break;
+ }
+
+ g_date_to_struct_tm (&current_date, &tm);
+ return mktime (&tm);
+}
+
+static void
+history_dialog_setup_filter (HistoryDialog *dialog)
+{
+ GValue word = {0, };
+ GValue atime = {0, };
+ const char *search_text;
+ GTime date_filter;
+
+ ephy_dialog_get_value (EPHY_DIALOG(dialog), PROP_WORD, &word);
+ search_text = g_value_get_string (&word);
+ ephy_dialog_get_value (EPHY_DIALOG(dialog), PROP_TIME, &atime);
+ date_filter = get_date_filter (g_value_get_int (&atime), time (NULL));
+
+ GDK_THREADS_ENTER ();
+
+ ephy_node_filter_empty (dialog->priv->filter);
+ ephy_node_filter_add_expression (dialog->priv->filter,
+ ephy_node_filter_expression_new (EPHY_NODE_FILTER_EXPRESSION_STRING_PROP_CONTAINS,
+ EPHY_NODE_PAGE_PROP_TITLE,
+ search_text),
+ 0);
+ ephy_node_filter_add_expression (dialog->priv->filter,
+ ephy_node_filter_expression_new (EPHY_NODE_FILTER_EXPRESSION_STRING_PROP_CONTAINS,
+ EPHY_NODE_PAGE_PROP_LOCATION,
+ search_text),
+ 0);
+ ephy_node_filter_add_expression (dialog->priv->filter,
+ ephy_node_filter_expression_new (EPHY_NODE_FILTER_EXPRESSION_INT_PROP_BIGGER_THAN,
+ EPHY_NODE_PAGE_PROP_LAST_VISIT,
+ date_filter),
+ 1);
+
+ ephy_node_filter_done_changing (dialog->priv->filter);
+
+ GDK_THREADS_LEAVE ();
+}
+
+static void
+history_dialog_init (HistoryDialog *dialog)
+{
+ EphyEmbedShell *ges;
+
+ dialog->priv = g_new0 (HistoryDialogPrivate, 1);
+
+ ges = ephy_shell_get_embed_shell (ephy_shell);
+ dialog->priv->gh = ephy_embed_shell_get_global_history (ges);
+ g_return_if_fail (dialog->priv->gh != NULL);
+
+ dialog->priv->root = ephy_history_get_hosts (dialog->priv->gh);
+ dialog->priv->pages = ephy_history_get_pages (dialog->priv->gh);
+ dialog->priv->filter = ephy_node_filter_new ();
+}
+
+static void
+history_dialog_set_embedded (HistoryDialog *dialog,
+ gboolean embedded)
+{
+ dialog->priv->embedded = embedded;
+
+ ephy_dialog_construct (EPHY_DIALOG(dialog),
+ properties,
+ "epiphany.glade",
+ embedded ?
+ "history_dock_box" :
+ "history_dialog");
+
+ dialog->priv->treeview = GTK_TREE_VIEW (
+ ephy_dialog_get_control (EPHY_DIALOG(dialog),
+ PROP_TREEVIEW));
+ history_dialog_setup_view (dialog);
+ history_dialog_setup_filter (dialog);
+}
+
+static void
+history_dialog_finalize (GObject *object)
+{
+ HistoryDialog *dialog;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (IS_HISTORY_DIALOG (object));
+
+ dialog = HISTORY_DIALOG (object);
+
+ g_return_if_fail (dialog->priv != NULL);
+
+ g_object_unref (G_OBJECT (dialog->priv->sortmodel));
+ g_object_unref (G_OBJECT (dialog->priv->filtermodel));
+ g_object_unref (G_OBJECT (dialog->priv->nodemodel));
+
+ g_free (dialog->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+EphyDialog *
+history_dialog_new (EphyEmbed *embed,
+ gboolean embedded)
+{
+ HistoryDialog *dialog;
+
+ dialog = HISTORY_DIALOG (g_object_new (HISTORY_DIALOG_TYPE,
+ "embedded", embedded,
+ "EphyEmbed", embed,
+ NULL));
+
+ return EPHY_DIALOG(dialog);
+}
+
+EphyDialog *
+history_dialog_new_with_parent (GtkWidget *window,
+ EphyEmbed *embed,
+ gboolean embedded)
+{
+ HistoryDialog *dialog;
+
+ dialog = HISTORY_DIALOG (g_object_new (HISTORY_DIALOG_TYPE,
+ "embedded", embedded,
+ "EphyEmbed", embed,
+ "ParentWindow", window,
+ NULL));
+
+ return EPHY_DIALOG(dialog);
+}
+
+void
+history_entry_changed_cb (GtkWidget *widget,
+ HistoryDialog *dialog)
+{
+ if (dialog->priv->treeview == NULL) return;
+ history_dialog_setup_filter (dialog);
+}
+
+void
+history_time_optionmenu_changed_cb (GtkWidget *widget,
+ HistoryDialog *dialog)
+{
+ if (dialog->priv->treeview == NULL) return;
+ history_dialog_setup_filter (dialog);
+}
+
+void
+history_ok_button_clicked_cb (GtkWidget *button,
+ HistoryDialog *dialog)
+{
+ g_object_unref (G_OBJECT(dialog));
+}
+
+void
+history_clear_button_clicked_cb (GtkWidget *button,
+ HistoryDialog *dialog)
+{
+ ephy_history_clear (dialog->priv->gh);
+}
diff --git a/src/history-dialog.h b/src/history-dialog.h
new file mode 100644
index 000000000..9a064de5c
--- /dev/null
+++ b/src/history-dialog.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef HISTORY_DIALOG_H
+#define HISTORY_DIALOG_H
+
+#include "ephy-embed-dialog.h"
+
+#include <glib-object.h>
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef struct HistoryDialog HistoryDialog;
+typedef struct HistoryDialogClass HistoryDialogClass;
+
+#define HISTORY_DIALOG_TYPE (history_dialog_get_type ())
+#define HISTORY_DIALOG(obj) (GTK_CHECK_CAST ((obj), HISTORY_DIALOG_TYPE, HistoryDialog))
+#define HISTORY_DIALOG_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), HISTORY_DIALOG, HistoryDialogClass))
+#define IS_HISTORY_DIALOG(obj) (GTK_CHECK_TYPE ((obj), HISTORY_DIALOG_TYPE))
+#define IS_HISTORY_DIALOG_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), HISTORY_DIALOG))
+
+typedef struct HistoryDialogPrivate HistoryDialogPrivate;
+
+struct HistoryDialog
+{
+ EphyEmbedDialog parent;
+ HistoryDialogPrivate *priv;
+};
+
+struct HistoryDialogClass
+{
+ EphyEmbedDialogClass parent_class;
+};
+
+GType history_dialog_get_type (void);
+
+EphyDialog *history_dialog_new (EphyEmbed *embed,
+ gboolean embedded);
+
+EphyDialog *history_dialog_new_with_parent (GtkWidget *window,
+ EphyEmbed *embed,
+ gboolean embedded);
+
+G_END_DECLS
+
+#endif
+
diff --git a/src/language-editor.c b/src/language-editor.c
new file mode 100644
index 000000000..7c24f99fd
--- /dev/null
+++ b/src/language-editor.c
@@ -0,0 +1,388 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "language-editor.h"
+#include "ephy-gui.h"
+#include "ephy-prefs.h"
+#include "eel-gconf-extensions.h"
+
+#include <gtk/gtklabel.h>
+#include <gtk/gtkoptionmenu.h>
+#include <gtk/gtksignal.h>
+#include <gtk/gtkbutton.h>
+#include <gtk/gtkeditable.h>
+#include <gtk/gtktreeview.h>
+#include <gtk/gtktreeselection.h>
+#include <gtk/gtkliststore.h>
+#include <gtk/gtkcellrenderertext.h>
+
+enum
+{
+ COL_DESCRIPTION,
+ COL_DATA
+};
+
+enum
+{
+ TREEVIEW_PROP,
+ ADD_PROP,
+ REMOVE_PROP,
+ LANGUAGE_PROP
+};
+
+static const
+EphyDialogProperty properties [] =
+{
+ { TREEVIEW_PROP, "languages_treeview", NULL, PT_NORMAL, NULL },
+ { ADD_PROP, "add_button", NULL, PT_NORMAL, NULL },
+ { REMOVE_PROP, "remove_button", NULL, PT_NORMAL, NULL },
+ { LANGUAGE_PROP, "languages_optionmenu", NULL, PT_NORMAL, NULL },
+
+ { -1, NULL, NULL }
+};
+
+
+struct LanguageEditorPrivate
+{
+ GtkWidget *treeview;
+ GtkTreeModel *model;
+ GtkWidget *optionmenu;
+};
+
+enum
+{
+ CHANGED,
+ LAST_SIGNAL
+};
+
+static void
+language_editor_class_init (LanguageEditorClass *klass);
+static void
+language_editor_init (LanguageEditor *ge);
+static void
+language_editor_finalize (GObject *object);
+
+/* Glade callbacks */
+
+void
+language_editor_close_button_cb (GtkWidget *button, EphyDialog *dialog);
+
+static GObjectClass *parent_class = NULL;
+
+static gint signals[LAST_SIGNAL];
+
+GType
+language_editor_get_type (void)
+{
+ static GType language_editor_type = 0;
+
+ if (language_editor_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (LanguageEditorClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) language_editor_class_init,
+ NULL,
+ NULL, /* class_data */
+ sizeof (LanguageEditor),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) language_editor_init
+ };
+
+ language_editor_type = g_type_register_static (EPHY_DIALOG_TYPE,
+ "LanguageEditor",
+ &our_info, 0);
+ }
+
+ return language_editor_type;
+
+}
+
+static void
+language_editor_class_init (LanguageEditorClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = language_editor_finalize;
+
+ signals[CHANGED] =
+ g_signal_new ("changed",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (LanguageEditorClass, changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__POINTER,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_POINTER);
+}
+
+static void
+language_editor_update_pref (LanguageEditor *editor)
+{
+ GtkTreeIter iter;
+ int index;
+ GSList *strings = NULL;
+
+ if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (editor->priv->model), &iter))
+ {
+ return;
+ }
+
+ do
+ {
+ GValue val = {0, };
+ gtk_tree_model_get_value (GTK_TREE_MODEL (editor->priv->model),
+ &iter, COL_DATA, &val);
+ index = g_value_get_int (&val);
+
+ strings = g_slist_append(strings, GINT_TO_POINTER(index));
+ }
+ while (gtk_tree_model_iter_next (GTK_TREE_MODEL (editor->priv->model), &iter));
+
+ g_signal_emit (editor, signals[CHANGED], 0, strings);
+
+ g_slist_free (strings);
+}
+
+static void
+language_editor_add_button_clicked_cb (GtkButton *button,
+ LanguageEditor *editor)
+{
+ const char *description;
+ GtkTreeIter iter;
+ GtkWidget *menu;
+ GtkWidget *item;
+ int history;
+
+ history = gtk_option_menu_get_history (GTK_OPTION_MENU(editor->priv->optionmenu));
+ menu = gtk_option_menu_get_menu (GTK_OPTION_MENU(editor->priv->optionmenu));
+ item = gtk_menu_get_active (GTK_MENU(menu));
+ description = (const char *) g_object_get_data (G_OBJECT(item), "desc");
+
+ g_return_if_fail (description != NULL);
+
+ gtk_list_store_append (GTK_LIST_STORE (editor->priv->model),
+ &iter);
+
+ gtk_list_store_set (GTK_LIST_STORE (editor->priv->model),
+ &iter,
+ COL_DESCRIPTION, description,
+ COL_DATA, history,
+ -1);
+
+ language_editor_update_pref (editor);
+}
+
+static void
+language_editor_remove_button_clicked_cb (GtkButton *button,
+ LanguageEditor *editor)
+{
+ GList *l, *r = NULL;
+ GtkTreeIter iter;
+ GtkTreeSelection *selection;
+ GtkTreeModel *model;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(editor->priv->treeview));
+ l = gtk_tree_selection_get_selected_rows (selection, &model);
+ for (;l != NULL; l = l->next)
+ {
+ r = g_list_append (r, gtk_tree_row_reference_new
+ (model, (GtkTreePath *)l->data));
+ }
+
+ for (; r != NULL; r = r->next)
+ {
+ GtkTreePath *node;
+
+ node = gtk_tree_row_reference_get_path
+ ((GtkTreeRowReference *)r->data);
+
+ gtk_tree_model_get_iter (model, &iter, node);
+
+ gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
+
+ gtk_tree_row_reference_free ((GtkTreeRowReference *)r->data);
+ }
+
+ l = g_list_first (l);
+ g_list_foreach (l, (GFunc)gtk_tree_path_free, NULL);
+ g_list_free (l);
+ g_list_free (r);
+
+ language_editor_update_pref (editor);
+}
+
+static void
+language_editor_treeview_drag_end_cb (GtkWidget *widget,
+ GdkDragContext *context,
+ LanguageEditor *editor)
+{
+ language_editor_update_pref (editor);
+}
+
+static void
+language_editor_set_view (LanguageEditor *ge,
+ GtkWidget *treeview,
+ GtkWidget *add_button,
+ GtkWidget *remove_button,
+ GtkWidget *optionmenu)
+{
+ GtkTreeViewColumn *column;
+ GtkCellRenderer *renderer;
+ GtkListStore *liststore;
+ GtkTreeSelection *selection;
+
+ ge->priv->treeview = treeview;
+ ge->priv->optionmenu = optionmenu;
+
+ gtk_tree_view_set_reorderable (GTK_TREE_VIEW(ge->priv->treeview), TRUE);
+
+ liststore = gtk_list_store_new (2,
+ G_TYPE_STRING,
+ G_TYPE_INT);
+
+ ge->priv->model = GTK_TREE_MODEL (liststore);
+
+ gtk_tree_view_set_model (GTK_TREE_VIEW(ge->priv->treeview),
+ ge->priv->model);
+ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(ge->priv->treeview),
+ FALSE);
+
+ renderer = gtk_cell_renderer_text_new ();
+
+ gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(ge->priv->treeview),
+ 0, "Language",
+ renderer,
+ "text", 0,
+ NULL);
+ column = gtk_tree_view_get_column (GTK_TREE_VIEW(ge->priv->treeview), 0);
+ gtk_tree_view_column_set_resizable (column, TRUE);
+ gtk_tree_view_column_set_sort_column_id (column, COL_DESCRIPTION);
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(ge->priv->treeview));
+ gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
+
+ /* Connect treeview signals */
+ g_signal_connect
+ (G_OBJECT (ge->priv->treeview),
+ "drag_end",
+ G_CALLBACK(language_editor_treeview_drag_end_cb),
+ ge);
+
+ /* Connect buttons signals */
+ g_signal_connect
+ (G_OBJECT (add_button),
+ "clicked",
+ G_CALLBACK(language_editor_add_button_clicked_cb),
+ ge);
+
+ g_signal_connect
+ (G_OBJECT (remove_button),
+ "clicked",
+ G_CALLBACK(language_editor_remove_button_clicked_cb),
+ ge);
+}
+
+static void
+language_editor_init (LanguageEditor *le)
+{
+ GtkWidget *treeview;
+ GtkWidget *optionmenu;
+ GtkWidget *add_button;
+ GtkWidget *remove_button;
+
+ le->priv = g_new0 (LanguageEditorPrivate, 1);
+
+ ephy_dialog_construct (EPHY_DIALOG(le),
+ properties,
+ "prefs-dialog.glade",
+ "languages_dialog");
+
+ treeview = ephy_dialog_get_control (EPHY_DIALOG(le),
+ TREEVIEW_PROP);
+ add_button = ephy_dialog_get_control (EPHY_DIALOG(le),
+ ADD_PROP);
+ remove_button = ephy_dialog_get_control (EPHY_DIALOG(le),
+ REMOVE_PROP);
+ optionmenu = ephy_dialog_get_control (EPHY_DIALOG(le),
+ LANGUAGE_PROP);
+
+ language_editor_set_view (le, treeview, add_button, remove_button,
+ optionmenu);
+}
+
+static void
+language_editor_finalize (GObject *object)
+{
+ LanguageEditor *ge;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (IS_LANGUAGE_EDITOR (object));
+
+ ge = LANGUAGE_EDITOR (object);
+
+ g_return_if_fail (ge->priv != NULL);
+
+ g_free (ge->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+LanguageEditor *
+language_editor_new (GtkWidget *parent)
+{
+ return LANGUAGE_EDITOR (g_object_new (LANGUAGE_EDITOR_TYPE,
+ "ParentWindow", parent,
+ NULL));
+}
+
+void
+language_editor_set_menu (LanguageEditor *editor,
+ GtkWidget *menu)
+{
+ gtk_option_menu_set_menu (GTK_OPTION_MENU(editor->priv->optionmenu),
+ menu);
+}
+
+void
+language_editor_add (LanguageEditor *ge,
+ const char *language,
+ int id)
+{
+ GtkTreeIter iter;
+
+ gtk_list_store_append (GTK_LIST_STORE (ge->priv->model),
+ &iter);
+
+ gtk_list_store_set (GTK_LIST_STORE (ge->priv->model),
+ &iter,
+ COL_DESCRIPTION, language,
+ COL_DATA, id,
+ -1);
+}
+
+void
+language_editor_close_button_cb (GtkWidget *button, EphyDialog *dialog)
+{
+ g_object_unref (dialog);
+}
diff --git a/src/language-editor.h b/src/language-editor.h
new file mode 100644
index 000000000..153fa136a
--- /dev/null
+++ b/src/language-editor.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef LANGUAGE_EDITOR_H
+#define LANGUAGE_EDITOR_H
+
+#include "general-prefs.h"
+
+#include <gtk/gtkwidget.h>
+#include <glib-object.h>
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef struct LanguageEditor LanguageEditor;
+typedef struct LanguageEditorClass LanguageEditorClass;
+
+#define LANGUAGE_EDITOR_TYPE (language_editor_get_type ())
+#define LANGUAGE_EDITOR(obj) (GTK_CHECK_CAST ((obj), LANGUAGE_EDITOR_TYPE, LanguageEditor))
+#define LANGUAGE_EDITOR_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), LANGUAGE_EDITOR, LanguageEditorClass))
+#define IS_LANGUAGE_EDITOR(obj) (GTK_CHECK_TYPE ((obj), LANGUAGE_EDITOR_TYPE))
+#define IS_LANGUAGE_EDITOR_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), LANGUAGE_EDITOR))
+
+typedef struct LanguageEditorPrivate LanguageEditorPrivate;
+
+struct LanguageEditor
+{
+ EphyDialog parent;
+ LanguageEditorPrivate *priv;
+};
+
+struct LanguageEditorClass
+{
+ EphyDialogClass parent_class;
+
+ void (* changed) (GSList *languages);
+};
+
+GType language_editor_get_type (void);
+
+LanguageEditor *language_editor_new (GtkWidget *parent);
+
+void language_editor_set_menu (LanguageEditor *editor,
+ GtkWidget *menu);
+
+void language_editor_add (LanguageEditor *editor,
+ const char *language,
+ int id);
+
+G_END_DECLS
+
+#endif
diff --git a/src/pdm-dialog.c b/src/pdm-dialog.c
new file mode 100755
index 000000000..5e077972a
--- /dev/null
+++ b/src/pdm-dialog.c
@@ -0,0 +1,669 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "pdm-dialog.h"
+#include "ephy-shell.h"
+#include "ephy-embed-shell.h"
+#include "ephy-gui.h"
+#include "ephy-ellipsizing-label.h"
+
+#include <gtk/gtktreeview.h>
+#include <gtk/gtkliststore.h>
+#include <gtk/gtkcellrenderertext.h>
+#include <bonobo/bonobo-i18n.h>
+
+typedef struct PdmActionInfo PdmActionInfo;
+
+typedef void (* PDM_add) (PdmActionInfo *info, gpointer data);
+typedef void (* PDM_remove) (PdmActionInfo *info, GList *data);
+typedef void (* PDM_free) (PdmActionInfo *info, GList *data);
+
+static void pdm_dialog_class_init (PdmDialogClass *klass);
+static void pdm_dialog_init (PdmDialog *dialog);
+static void pdm_dialog_finalize (GObject *object);
+
+/* Glade callbacks */
+void
+pdm_dialog_close_button_clicked_cb (GtkWidget *button,
+ PdmDialog *dialog);
+void
+pdm_dialog_cookies_properties_button_clicked_cb (GtkWidget *button,
+ PdmDialog *dialog);
+void
+pdm_dialog_cookies_treeview_selection_changed_cb (GtkTreeSelection *selection,
+ PdmDialog *dialog);
+void
+pdm_dialog_passwords_treeview_selection_changed_cb (GtkTreeSelection *selection,
+ PdmDialog *dialog);
+
+static GObjectClass *parent_class = NULL;
+
+struct PdmActionInfo
+{
+ PDM_add add;
+ PDM_remove remove;
+ PDM_free free;
+ GtkWidget *treeview;
+ GList *list;
+ int remove_id;
+ int data_col;
+ PdmDialog *dialog;
+};
+
+struct PdmDialogPrivate
+{
+ GtkTreeModel *model;
+ PdmActionInfo *cookies;
+ PdmActionInfo *passwords;
+};
+
+enum
+{
+ PROP_COOKIES_TREEVIEW,
+ PROP_COOKIES_REMOVE,
+ PROP_PASSWORDS_TREEVIEW,
+ PROP_PASSWORDS_REMOVE,
+ PROP_DIALOG,
+ PROP_COOKIES_PROPERTIES
+};
+
+enum
+{
+ COL_COOKIES_HOST,
+ COL_COOKIES_NAME,
+ COL_COOKIES_DATA
+};
+
+enum
+{
+ COL_PASSWORDS_HOST,
+ COL_PASSWORDS_USER,
+ COL_PASSWORDS_DATA
+};
+
+static const
+EphyDialogProperty properties [] =
+{
+ { PROP_COOKIES_TREEVIEW, "cookies_treeview", NULL, PT_NORMAL, NULL },
+ { PROP_COOKIES_REMOVE, "cookies_remove_button", NULL, PT_NORMAL, NULL },
+ { PROP_PASSWORDS_TREEVIEW, "passwords_treeview", NULL, PT_NORMAL, NULL },
+ { PROP_PASSWORDS_REMOVE, "passwords_remove_button", NULL, PT_NORMAL, NULL },
+ { PROP_DIALOG, "pdm_dialog", NULL, PT_NORMAL, NULL },
+ { PROP_COOKIES_PROPERTIES, "cookies_properties_button", NULL, PT_NORMAL, NULL },
+
+ { -1, NULL, NULL }
+};
+
+GType
+pdm_dialog_get_type (void)
+{
+ static GType pdm_dialog_type = 0;
+
+ if (pdm_dialog_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (PdmDialogClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) pdm_dialog_class_init,
+ NULL,
+ NULL, /* class_data */
+ sizeof (PdmDialog),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) pdm_dialog_init
+ };
+
+ pdm_dialog_type = g_type_register_static (EPHY_DIALOG_TYPE,
+ "PdmDialog",
+ &our_info, 0);
+ }
+
+ return pdm_dialog_type;
+
+}
+
+static void
+pdm_dialog_class_init (PdmDialogClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = pdm_dialog_finalize;
+}
+
+static void
+cookies_treeview_selection_changed_cb (GtkTreeSelection *selection,
+ PdmDialog *dialog)
+{
+ GtkWidget *widget;
+ GList *l;
+ EphyDialog *d = EPHY_DIALOG(dialog);
+ gboolean has_selection;
+ GtkTreeModel *model;
+
+ l = gtk_tree_selection_get_selected_rows
+ (selection, &model);
+
+ has_selection = l != NULL;
+
+ widget = ephy_dialog_get_control (d, PROP_COOKIES_PROPERTIES);
+ gtk_widget_set_sensitive (widget, has_selection);
+
+ g_list_foreach (l, (GFunc)gtk_tree_path_free, NULL);
+ g_list_free (l);
+}
+
+static void
+action_treeview_selection_changed_cb (GtkTreeSelection *selection,
+ PdmActionInfo *action)
+{
+ GtkWidget *widget;
+ GList *l;
+ EphyDialog *d = EPHY_DIALOG(action->dialog);
+ gboolean has_selection;
+ GtkTreeModel *model;
+
+ l = gtk_tree_selection_get_selected_rows
+ (selection, &model);
+
+ has_selection = l != NULL;
+
+ widget = ephy_dialog_get_control (d, action->remove_id);
+ gtk_widget_set_sensitive (widget, has_selection);
+
+ g_list_foreach (l, (GFunc)gtk_tree_path_free, NULL);
+ g_list_free (l);
+}
+
+static GtkWidget *
+setup_passwords_treeview (PdmDialog *dialog)
+{
+
+ GtkTreeView *treeview;
+ GtkListStore *liststore;
+ GtkCellRenderer *renderer;
+ GtkTreeViewColumn *column;
+ GtkTreeSelection *selection;
+
+ treeview = GTK_TREE_VIEW(ephy_dialog_get_control
+ (EPHY_DIALOG(dialog),
+ PROP_PASSWORDS_TREEVIEW));
+
+ /* set tree model */
+ liststore = gtk_list_store_new (3,
+ G_TYPE_STRING,
+ G_TYPE_STRING,
+ G_TYPE_POINTER);
+ gtk_tree_view_set_model (treeview, GTK_TREE_MODEL(liststore));
+ gtk_tree_view_set_headers_visible (treeview, TRUE);
+ selection = gtk_tree_view_get_selection (treeview);
+ gtk_tree_selection_set_mode (selection,
+ GTK_SELECTION_MULTIPLE);
+
+ renderer = gtk_cell_renderer_text_new ();
+
+ gtk_tree_view_insert_column_with_attributes (treeview,
+ COL_PASSWORDS_HOST,
+ _("Host"),
+ renderer,
+ "text", COL_PASSWORDS_HOST,
+ NULL);
+ column = gtk_tree_view_get_column (treeview, COL_PASSWORDS_HOST);
+ gtk_tree_view_column_set_resizable (column, TRUE);
+ gtk_tree_view_column_set_reorderable (column, TRUE);
+ gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
+ gtk_tree_view_column_set_sort_column_id (column, COL_PASSWORDS_HOST);
+
+ gtk_tree_view_insert_column_with_attributes (treeview,
+ COL_PASSWORDS_USER,
+ _("User Name"),
+ renderer,
+ "text", COL_PASSWORDS_USER,
+ NULL);
+ column = gtk_tree_view_get_column (treeview, COL_PASSWORDS_USER);
+ gtk_tree_view_column_set_resizable (column, TRUE);
+ gtk_tree_view_column_set_reorderable (column, TRUE);
+ gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
+ gtk_tree_view_column_set_sort_column_id (column, COL_PASSWORDS_USER);
+
+ return GTK_WIDGET (treeview);
+}
+
+static GtkWidget *
+setup_cookies_treeview (PdmDialog *dialog)
+{
+ GtkTreeView *treeview;
+ GtkListStore *liststore;
+ GtkCellRenderer *renderer;
+ GtkTreeViewColumn *column;
+ GtkTreeSelection *selection;
+
+ treeview = GTK_TREE_VIEW (ephy_dialog_get_control
+ (EPHY_DIALOG(dialog),
+ PROP_COOKIES_TREEVIEW));
+
+ /* set tree model */
+ liststore = gtk_list_store_new (3,
+ G_TYPE_STRING,
+ G_TYPE_STRING,
+ G_TYPE_POINTER);
+ gtk_tree_view_set_model (treeview, GTK_TREE_MODEL(liststore));
+ gtk_tree_view_set_headers_visible (treeview, TRUE);
+ selection = gtk_tree_view_get_selection (treeview);
+ gtk_tree_selection_set_mode (selection,
+ GTK_SELECTION_MULTIPLE);
+
+ g_signal_connect (selection, "changed",
+ G_CALLBACK(cookies_treeview_selection_changed_cb),
+ dialog);
+
+ renderer = gtk_cell_renderer_text_new ();
+
+ gtk_tree_view_insert_column_with_attributes (treeview,
+ COL_COOKIES_HOST,
+ _("Domain"),
+ renderer,
+ "text", COL_COOKIES_HOST,
+ NULL);
+ column = gtk_tree_view_get_column (treeview, COL_COOKIES_HOST);
+ gtk_tree_view_column_set_resizable (column, TRUE);
+ gtk_tree_view_column_set_reorderable (column, TRUE);
+ gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
+ gtk_tree_view_column_set_sort_column_id (column, COL_COOKIES_HOST);
+
+ gtk_tree_view_insert_column_with_attributes (treeview,
+ COL_COOKIES_NAME,
+ _("Name"),
+ renderer,
+ "text", COL_COOKIES_NAME,
+ NULL);
+ column = gtk_tree_view_get_column (treeview, COL_COOKIES_NAME);
+ gtk_tree_view_column_set_resizable (column, TRUE);
+ gtk_tree_view_column_set_reorderable (column, TRUE);
+ gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
+ gtk_tree_view_column_set_sort_column_id (column, COL_COOKIES_NAME);
+
+ return GTK_WIDGET(treeview);
+}
+
+static void
+pdm_dialog_remove_button_clicked_cb (GtkWidget *button,
+ PdmActionInfo *action)
+{
+ GList *l, *r = NULL;
+ GList *remove_list = NULL;
+ GtkTreeModel *model;
+ GtkTreeSelection *selection;
+
+ selection = gtk_tree_view_get_selection
+ (GTK_TREE_VIEW(action->treeview));
+ l = gtk_tree_selection_get_selected_rows
+ (selection, &model);
+ for (;l != NULL; l = l->next)
+ {
+ r = g_list_append (r, gtk_tree_row_reference_new
+ (model, (GtkTreePath *)l->data));
+ }
+
+ for (; r != NULL; r = r->next)
+ {
+ GtkTreeIter iter;
+ gpointer data;
+ GtkTreePath *path;
+ GValue val = {0, };
+
+ path = gtk_tree_row_reference_get_path
+ ((GtkTreeRowReference *)r->data);
+
+ gtk_tree_model_get_iter
+ (model, &iter, path);
+ gtk_tree_model_get_value
+ (model, &iter, action->data_col, &val);
+ data = g_value_get_pointer (&val);
+
+ gtk_list_store_remove (GTK_LIST_STORE(model),
+ &iter);
+
+ action->list = g_list_remove (action->list, data);
+ remove_list = g_list_append (remove_list, data);
+
+ gtk_tree_row_reference_free ((GtkTreeRowReference *)r->data);
+ }
+
+ if (remove_list)
+ {
+ action->remove (action, remove_list);
+ action->free (action, remove_list);
+ }
+
+ l = g_list_first (l);
+ g_list_foreach (l, (GFunc)gtk_tree_path_free, NULL);
+ g_list_free (l);
+ g_list_free (r);
+}
+
+static void
+setup_action (PdmActionInfo *action)
+{
+ GList *l;
+ GtkWidget *widget;
+ GtkTreeSelection *selection;
+
+ for (l = action->list; l != NULL; l = l->next)
+ {
+ action->add (action, l->data);
+ }
+
+ widget = ephy_dialog_get_control (EPHY_DIALOG(action->dialog),
+ action->remove_id);
+ g_signal_connect (widget, "clicked",
+ G_CALLBACK(pdm_dialog_remove_button_clicked_cb),
+ action);
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(action->treeview));
+ g_signal_connect (selection, "changed",
+ G_CALLBACK(action_treeview_selection_changed_cb),
+ action);
+}
+
+static void
+pdm_dialog_cookie_add (PdmActionInfo *info,
+ gpointer cookie)
+{
+ GtkListStore *store;
+ GtkTreeIter iter;
+ CookieInfo *cinfo = (CookieInfo *)cookie;
+
+ store = GTK_LIST_STORE(gtk_tree_view_get_model
+ (GTK_TREE_VIEW(info->treeview)));
+
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store,
+ &iter,
+ COL_COOKIES_HOST, cinfo->base.domain,
+ COL_COOKIES_NAME, cinfo->name,
+ COL_COOKIES_DATA, cinfo,
+ -1);
+}
+
+static void
+pdm_dialog_password_add (PdmActionInfo *info,
+ gpointer password)
+{
+ GtkListStore *store;
+ GtkTreeIter iter;
+ PasswordInfo *pinfo = (PasswordInfo *)password;
+
+ store = GTK_LIST_STORE(gtk_tree_view_get_model
+ (GTK_TREE_VIEW(info->treeview)));
+
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store,
+ &iter,
+ COL_PASSWORDS_HOST, pinfo->host,
+ COL_PASSWORDS_USER, pinfo->username,
+ COL_PASSWORDS_DATA, pinfo,
+ -1);
+}
+
+static void
+pdm_dialog_cookie_remove (PdmActionInfo *info,
+ GList *data)
+{
+ EphyEmbedShell *shell;
+ shell = ephy_shell_get_embed_shell (ephy_shell);
+ ephy_embed_shell_remove_cookies (shell, data);
+}
+
+static void
+pdm_dialog_password_remove (PdmActionInfo *info,
+ GList *data)
+{
+ EphyEmbedShell *shell;
+ shell = ephy_shell_get_embed_shell (ephy_shell);
+ ephy_embed_shell_remove_passwords (shell, data, PASSWORD_PASSWORD);
+}
+
+static void
+pdm_dialog_cookies_free (PdmActionInfo *info,
+ GList *data)
+{
+ EphyEmbedShell *shell;
+ GList *l;
+
+ shell = ephy_shell_get_embed_shell (ephy_shell);
+ l = data ? data : info->list;
+ ephy_embed_shell_free_cookies (shell, l);
+}
+
+static void
+pdm_dialog_passwords_free (PdmActionInfo *info,
+ GList *data)
+{
+ EphyEmbedShell *shell;
+ GList *l;
+
+ shell = ephy_shell_get_embed_shell (ephy_shell);
+ l = data ? data : info->list;
+ ephy_embed_shell_free_passwords (shell, l);
+}
+
+static void
+pdm_dialog_init (PdmDialog *dialog)
+{
+ EphyEmbedShell *shell;
+ PdmActionInfo *cookies;
+ PdmActionInfo *passwords;
+ GtkWidget *cookies_tv;
+ GtkWidget *passwords_tv;
+
+ shell = ephy_shell_get_embed_shell (ephy_shell);
+
+ dialog->priv = g_new0 (PdmDialogPrivate, 1);
+ dialog->priv->cookies = NULL;
+ dialog->priv->passwords = NULL;
+
+ ephy_dialog_construct (EPHY_DIALOG(dialog),
+ properties,
+ "epiphany.glade",
+ "pdm_dialog");
+
+ cookies_tv = setup_cookies_treeview (dialog);
+ passwords_tv = setup_passwords_treeview (dialog);
+
+ cookies = g_new0 (PdmActionInfo, 1);
+ ephy_embed_shell_list_cookies (shell, &cookies->list);
+ cookies->dialog = dialog;
+ cookies->remove_id = PROP_COOKIES_REMOVE;
+ cookies->add = pdm_dialog_cookie_add;
+ cookies->remove = pdm_dialog_cookie_remove;
+ cookies->free = pdm_dialog_cookies_free;
+ cookies->treeview = cookies_tv;
+ cookies->data_col = COL_COOKIES_DATA;
+ setup_action (cookies);
+
+ passwords = g_new0 (PdmActionInfo, 1);
+ ephy_embed_shell_list_passwords (shell, PASSWORD_PASSWORD,
+ &passwords->list);
+ passwords->dialog = dialog;
+ passwords->remove_id = PROP_PASSWORDS_REMOVE;
+ passwords->add = pdm_dialog_password_add;
+ passwords->remove = pdm_dialog_password_remove;
+ passwords->free = pdm_dialog_passwords_free;
+ passwords->treeview = passwords_tv;
+ passwords->data_col = COL_PASSWORDS_DATA;
+ setup_action (passwords);
+
+ dialog->priv->cookies = cookies;
+ dialog->priv->passwords = passwords;
+}
+
+static void
+pdm_dialog_finalize (GObject *object)
+{
+ PdmDialog *dialog;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (IS_PDM_DIALOG (object));
+
+ dialog = PDM_DIALOG (object);
+
+ g_return_if_fail (dialog->priv != NULL);
+
+ pdm_dialog_passwords_free (dialog->priv->passwords, NULL);
+ pdm_dialog_cookies_free (dialog->priv->cookies, NULL);
+
+ g_free (dialog->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+EphyDialog *
+pdm_dialog_new (GtkWidget *window)
+{
+ PdmDialog *dialog;
+
+ dialog = PDM_DIALOG (g_object_new (PDM_DIALOG_TYPE,
+ "ParentWindow", window,
+ NULL));
+
+ return EPHY_DIALOG(dialog);
+}
+
+static void
+show_cookies_properties (PdmDialog *dialog,
+ CookieInfo *info)
+{
+ GtkWidget *gdialog;
+ GtkWidget *table;
+ GtkWidget *label;
+ GtkWidget *parent;
+ GtkWidget *dialog_vbox;
+
+ parent = ephy_dialog_get_control (EPHY_DIALOG(dialog),
+ PROP_DIALOG);
+
+ gdialog = gtk_dialog_new_with_buttons
+ (_("Cookie properties"),
+ GTK_WINDOW(parent),
+ GTK_DIALOG_MODAL,
+ GTK_STOCK_CLOSE, 0, NULL);
+ gtk_dialog_set_has_separator (GTK_DIALOG(gdialog), FALSE);
+ gtk_container_set_border_width (GTK_CONTAINER(gdialog), 6);
+
+ table = gtk_table_new (2, 4, FALSE);
+ gtk_container_set_border_width (GTK_CONTAINER(table), 6);
+ gtk_table_set_row_spacings (GTK_TABLE(table), 10);
+ gtk_table_set_col_spacings (GTK_TABLE(table), 10);
+ gtk_widget_show (table);
+
+ label = gtk_label_new (_("<b>Value</b>"));
+ gtk_label_set_use_markup (GTK_LABEL(label), TRUE);
+ gtk_misc_set_alignment (GTK_MISC(label), 0, 0);
+ gtk_widget_show (label);
+ gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1,
+ GTK_FILL, GTK_FILL, 0, 0);
+
+ label = ephy_ellipsizing_label_new (info->value);
+ gtk_misc_set_alignment (GTK_MISC(label), 0, 0);
+ gtk_widget_show (label);
+ gtk_table_attach_defaults (GTK_TABLE (table), label, 1, 2, 0, 1);
+
+ label = gtk_label_new (_("<b>Path</b>"));
+ gtk_label_set_use_markup (GTK_LABEL(label), TRUE);
+ gtk_misc_set_alignment (GTK_MISC(label), 0, 0);
+ gtk_widget_show (label);
+ gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2,
+ GTK_FILL, GTK_FILL, 0, 0);
+
+ label = gtk_label_new (info->path);
+ gtk_misc_set_alignment (GTK_MISC(label), 0, 0);
+ gtk_widget_show (label);
+ gtk_table_attach_defaults (GTK_TABLE (table), label, 1, 2, 1, 2);
+
+ label = gtk_label_new (_("<b>Secure</b>"));
+ gtk_label_set_use_markup (GTK_LABEL(label), TRUE);
+ gtk_misc_set_alignment (GTK_MISC(label), 0, 0);
+ gtk_widget_show (label);
+ gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3,
+ GTK_FILL, GTK_FILL, 0, 0);
+
+ label = gtk_label_new (info->secure);
+ gtk_misc_set_alignment (GTK_MISC(label), 0, 0);
+ gtk_widget_show (label);
+ gtk_table_attach_defaults (GTK_TABLE (table), label, 1, 2, 2, 3);
+
+ label = gtk_label_new (_("<b>Expire</b>"));
+ gtk_label_set_use_markup (GTK_LABEL(label), TRUE);
+ gtk_misc_set_alignment (GTK_MISC(label), 0, 0);
+ gtk_widget_show (label);
+ gtk_table_attach (GTK_TABLE (table), label, 0, 1, 3, 4,
+ GTK_FILL, GTK_FILL, 0, 0);
+
+ label = gtk_label_new (info->expire);
+ gtk_misc_set_alignment (GTK_MISC(label), 0, 0.5);
+ gtk_widget_show (label);
+ gtk_table_attach_defaults (GTK_TABLE (table), label, 1, 2, 3, 4);
+
+ dialog_vbox = GTK_DIALOG(gdialog)->vbox;
+ gtk_box_pack_start (GTK_BOX(dialog_vbox),
+ table,
+ FALSE, FALSE, 0);
+
+ gtk_dialog_run (GTK_DIALOG(gdialog));
+
+ gtk_widget_destroy (gdialog);
+}
+
+void
+pdm_dialog_cookies_properties_button_clicked_cb (GtkWidget *button,
+ PdmDialog *dialog)
+{
+ GtkTreeModel *model;
+ GValue val = {0, };
+ GtkTreeIter iter;
+ GtkTreePath *path;
+ CookieInfo *info;
+ GList *l;
+ GtkWidget *treeview = dialog->priv->cookies->treeview;
+ GtkTreeSelection *selection;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
+ l = gtk_tree_selection_get_selected_rows
+ (selection, &model);
+
+ path = (GtkTreePath *)l->data;
+ gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_model_get_value
+ (model, &iter, COL_COOKIES_DATA, &val);
+ info = (CookieInfo *)g_value_get_pointer (&val);
+
+ show_cookies_properties (dialog, info);
+
+ g_list_foreach (l, (GFunc)gtk_tree_path_free, NULL);
+ g_list_free (l);
+}
+
+void
+pdm_dialog_close_button_clicked_cb (GtkWidget *button,
+ PdmDialog *dialog)
+{
+ g_object_unref (dialog);
+}
diff --git a/src/pdm-dialog.h b/src/pdm-dialog.h
new file mode 100644
index 000000000..7216d4ac0
--- /dev/null
+++ b/src/pdm-dialog.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef PDM_DIALOG_H
+#define PDM_DIALOG_H
+
+#include "ephy-dialog.h"
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef struct PdmDialog PdmDialog;
+typedef struct PdmDialogClass PdmDialogClass;
+
+#define PDM_DIALOG_TYPE (pdm_dialog_get_type ())
+#define PDM_DIALOG(obj) (GTK_CHECK_CAST ((obj), PDM_DIALOG_TYPE, PdmDialog))
+#define PDM_DIALOG_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), PDM_DIALOG, PdmDialogClass))
+#define IS_PDM_DIALOG(obj) (GTK_CHECK_TYPE ((obj), PDM_DIALOG_TYPE))
+#define IS_PDM_DIALOG_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), PDM_DIALOG))
+
+typedef struct PdmDialogPrivate PdmDialogPrivate;
+
+struct PdmDialog
+{
+ EphyDialog parent;
+ PdmDialogPrivate *priv;
+};
+
+struct PdmDialogClass
+{
+ EphyDialogClass parent_class;
+};
+
+GType pdm_dialog_get_type (void);
+
+EphyDialog *pdm_dialog_new (GtkWidget *window);
+
+G_END_DECLS
+
+#endif
+
diff --git a/src/popup-commands.c b/src/popup-commands.c
new file mode 100644
index 000000000..bf187d981
--- /dev/null
+++ b/src/popup-commands.c
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "popup-commands.h"
+#include "ephy-shell.h"
+
+static EphyWindow *
+get_window_from_popup (EphyEmbedPopup *popup)
+{
+ return EPHY_WINDOW (g_object_get_data(G_OBJECT(popup), "EphyWindow"));
+}
+
+void popup_cmd_new_window (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname)
+{
+ EphyEmbedEvent *info;
+ EphyTab *tab;
+ GValue *value;
+
+ tab = ephy_window_get_active_tab (get_window_from_popup (popup));
+
+ info = ephy_embed_popup_get_event (popup);
+
+ ephy_embed_event_get_property (info, "link", &value);
+
+ ephy_shell_new_tab (ephy_shell, NULL, tab,
+ g_value_get_string (value),
+ EPHY_NEW_TAB_IN_NEW_WINDOW);
+}
+
+void popup_cmd_new_tab (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname)
+{
+ EphyEmbedEvent *info;
+ EphyTab *tab;
+ EphyWindow *window;
+ GValue *value;
+
+ window = get_window_from_popup (popup);
+ g_return_if_fail (window != NULL);
+
+ tab = ephy_window_get_active_tab (window);
+
+ info = ephy_embed_popup_get_event (popup);
+
+ ephy_embed_event_get_property (info, "link", &value);
+
+ ephy_shell_new_tab (ephy_shell, window, tab,
+ g_value_get_string (value),
+ EPHY_NEW_TAB_IN_EXISTING_WINDOW);
+}
+
+void popup_cmd_image_in_new_tab (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname)
+{
+ EphyEmbedEvent *info;
+ EphyTab *tab;
+ EphyWindow *window;
+ GValue *value;
+
+ window = get_window_from_popup (popup);
+ g_return_if_fail (window != NULL);
+
+ tab = ephy_window_get_active_tab (window);
+
+ info = ephy_embed_popup_get_event (popup);
+
+ ephy_embed_event_get_property (info, "image", &value);
+
+ ephy_shell_new_tab (ephy_shell, window, tab,
+ g_value_get_string (value),
+ EPHY_NEW_TAB_IN_EXISTING_WINDOW);
+}
+
+void popup_cmd_image_in_new_window (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname)
+{
+ EphyEmbedEvent *info;
+ EphyTab *tab;
+ GValue *value;
+
+ tab = ephy_window_get_active_tab (get_window_from_popup (popup));
+
+ info = ephy_embed_popup_get_event (popup);
+
+ ephy_embed_event_get_property (info, "image", &value);
+
+ ephy_shell_new_tab (ephy_shell, NULL, tab,
+ g_value_get_string (value),
+ EPHY_NEW_TAB_IN_NEW_WINDOW);
+}
+
+void popup_cmd_add_bookmark (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname)
+{
+ GtkWidget *new_bookmark;
+ EphyBookmarks *bookmarks;
+ EphyEmbedEvent *info = ephy_embed_popup_get_event (popup);
+ EphyEmbed *embed;
+ GtkWidget *window;
+ GValue *link_title;
+ GValue *link_rel;
+ GValue *link;
+ GValue *link_is_smart;
+ const char *title;
+ const char *location;
+ const char *rel;
+ gboolean is_smart;
+
+ embed = ephy_embed_popup_get_embed (popup);
+ window = gtk_widget_get_toplevel (GTK_WIDGET (embed));
+
+ ephy_embed_event_get_property (info, "link_is_smart", &link_is_smart);
+ ephy_embed_event_get_property (info, "link", &link);
+ ephy_embed_event_get_property (info, "link_title", &link_title);
+ ephy_embed_event_get_property (info, "link_rel", &link_rel);
+
+ title = g_value_get_string (link_title);
+ location = g_value_get_string (link);
+ rel = g_value_get_string (link_rel);
+ is_smart = g_value_get_int (link_is_smart);
+
+ g_return_if_fail (location);
+
+ if (!title || !title[0])
+ {
+ title = location;
+ }
+
+ bookmarks = ephy_shell_get_bookmarks (ephy_shell);
+ new_bookmark = ephy_new_bookmark_new
+ (bookmarks, GTK_WINDOW (window), location);
+ ephy_new_bookmark_set_title
+ (EPHY_NEW_BOOKMARK (new_bookmark), title);
+ ephy_new_bookmark_set_smarturl
+ (EPHY_NEW_BOOKMARK (new_bookmark), rel);
+ gtk_widget_show (new_bookmark);
+}
+
+void popup_cmd_frame_in_new_tab (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname)
+{
+ EphyTab *tab;
+ EphyWindow *window;
+ EphyEmbed *embed;
+ char *location;
+
+ window = get_window_from_popup (popup);
+ g_return_if_fail (window != NULL);
+
+ tab = ephy_window_get_active_tab (window);
+
+ embed = ephy_window_get_active_embed (window);
+
+ ephy_embed_get_location (embed, FALSE, FALSE, &location);
+
+ ephy_shell_new_tab (ephy_shell, window, tab,
+ location,
+ EPHY_NEW_TAB_IN_EXISTING_WINDOW);
+
+ g_free (location);
+}
+
+void popup_cmd_frame_in_new_window (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname)
+{
+ EphyTab *tab;
+ EphyEmbed *embed;
+ EphyWindow *window;
+ char *location;
+
+ window = get_window_from_popup (popup);
+ g_return_if_fail (window != NULL);
+
+ tab = ephy_window_get_active_tab (window);
+
+ embed = ephy_window_get_active_embed (window);
+
+ ephy_embed_get_location (embed, FALSE, FALSE, &location);
+
+ ephy_shell_new_tab (ephy_shell, NULL, tab,
+ location,
+ EPHY_NEW_TAB_IN_NEW_WINDOW);
+
+ g_free (location);
+}
+
+void popup_cmd_add_frame_bookmark (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname)
+{
+ /* FIXME implement */
+}
+
+void popup_cmd_view_source (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname)
+{
+ /* FIXME implement */
+}
diff --git a/src/popup-commands.h b/src/popup-commands.h
new file mode 100644
index 000000000..e5b369c76
--- /dev/null
+++ b/src/popup-commands.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "ephy-embed-popup.h"
+#include "ephy-new-bookmark.h"
+
+#include <bonobo/bonobo-ui-component.h>
+
+void popup_cmd_new_window (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname);
+
+void popup_cmd_new_tab (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname);
+
+void popup_cmd_image_in_new_tab (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname);
+
+void popup_cmd_image_in_new_window (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname);
+
+void popup_cmd_add_bookmark (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname);
+
+void popup_cmd_frame_in_new_tab (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname);
+
+void popup_cmd_frame_in_new_window (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname);
+
+void popup_cmd_add_frame_bookmark (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname);
+
+void popup_cmd_view_source (BonoboUIComponent *uic,
+ EphyEmbedPopup *popup,
+ const char* verbname);
diff --git a/src/ppview-toolbar.c b/src/ppview-toolbar.c
new file mode 100755
index 000000000..06b2cbb6e
--- /dev/null
+++ b/src/ppview-toolbar.c
@@ -0,0 +1,388 @@
+/*
+ * Copyright (C) 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+
+#include "ppview-toolbar.h"
+#include "ephy-window.h"
+#include "ephy-bonobo-extensions.h"
+#include "ephy-string.h"
+#include "ephy-gui.h"
+
+#include <string.h>
+#include <bonobo/bonobo-i18n.h>
+#include <bonobo/bonobo-window.h>
+#include <bonobo/bonobo-control.h>
+#include <bonobo/bonobo-ui-toolbar-button-item.h>
+#include <bonobo/bonobo-property-bag.h>
+#include <gtk/gtkentry.h>
+#include <gtk/gtkmenu.h>
+
+#define PPV_GOTO_FIRST_PATH "/commands/PPVGotoFirst"
+#define PPV_GOTO_LAST_PATH "/commands/PPVGotoLast"
+#define PPV_GO_BACK_PATH "/commands/PPVGoBack"
+#define PPV_GO_FORWARD_PATH "/commands/PPVGoForward"
+
+static void ppview_toolbar_class_init (PPViewToolbarClass *klass);
+static void ppview_toolbar_init (PPViewToolbar *t);
+static void ppview_toolbar_finalize (GObject *object);
+static void ppview_toolbar_set_window (PPViewToolbar *t, EphyWindow *window);
+static void
+ppview_toolbar_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void
+ppview_toolbar_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+enum
+{
+ PROP_0,
+ PROP_EPHY_WINDOW
+};
+
+static GObjectClass *parent_class = NULL;
+
+struct PPViewToolbarPrivate
+{
+ EphyWindow *window;
+ BonoboUIComponent *ui_component;
+ gboolean visibility;
+ EmbedChromeMask old_chrome;
+ int current_page;
+};
+
+static void
+toolbar_cmd_ppv_goto_first (BonoboUIComponent *uic,
+ PPViewToolbar *t,
+ const char* verbname);
+
+static void
+toolbar_cmd_ppv_goto_last (BonoboUIComponent *uic,
+ PPViewToolbar *t,
+ const char* verbname);
+
+static void
+toolbar_cmd_ppv_go_back (BonoboUIComponent *uic,
+ PPViewToolbar *t,
+ const char* verbname);
+
+static void
+toolbar_cmd_ppv_go_forward (BonoboUIComponent *uic,
+ PPViewToolbar *t,
+ const char* verbname);
+
+static void
+toolbar_cmd_ppv_close (BonoboUIComponent *uic,
+ PPViewToolbar *t,
+ const char* verbname);
+
+BonoboUIVerb ppview_toolbar_verbs [] = {
+ BONOBO_UI_VERB ("PPVGotoFirst", (BonoboUIVerbFn)toolbar_cmd_ppv_goto_first),
+ BONOBO_UI_VERB ("PPVGotoLast", (BonoboUIVerbFn)toolbar_cmd_ppv_goto_last),
+ BONOBO_UI_VERB ("PPVGoBack", (BonoboUIVerbFn)toolbar_cmd_ppv_go_back),
+ BONOBO_UI_VERB ("PPVGoForward", (BonoboUIVerbFn)toolbar_cmd_ppv_go_forward),
+ BONOBO_UI_VERB ("PPVClose", (BonoboUIVerbFn)toolbar_cmd_ppv_close),
+
+ BONOBO_UI_VERB_END
+};
+
+GType
+ppview_toolbar_get_type (void)
+{
+ static GType ppview_toolbar_type = 0;
+
+ if (ppview_toolbar_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (PPViewToolbarClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) ppview_toolbar_class_init,
+ NULL,
+ NULL, /* class_data */
+ sizeof (PPViewToolbar),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) ppview_toolbar_init
+ };
+
+ ppview_toolbar_type = g_type_register_static (G_TYPE_OBJECT,
+ "PPViewToolbar",
+ &our_info, 0);
+ }
+
+ return ppview_toolbar_type;
+
+}
+
+static void
+ppview_toolbar_class_init (PPViewToolbarClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = ppview_toolbar_finalize;
+
+ object_class->set_property = ppview_toolbar_set_property;
+ object_class->get_property = ppview_toolbar_get_property;
+
+ g_object_class_install_property (object_class,
+ PROP_EPHY_WINDOW,
+ g_param_spec_object ("EphyWindow",
+ "EphyWindow",
+ "Parent window",
+ EPHY_WINDOW_TYPE,
+ G_PARAM_READWRITE));
+}
+
+static void
+ppview_toolbar_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ PPViewToolbar *t = PPVIEW_TOOLBAR (object);
+
+ switch (prop_id)
+ {
+ case PROP_EPHY_WINDOW:
+ ppview_toolbar_set_window (t, g_value_get_object (value));
+ break;
+ }
+}
+
+static void
+ppview_toolbar_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ PPViewToolbar *t = PPVIEW_TOOLBAR (object);
+
+ switch (prop_id)
+ {
+ case PROP_EPHY_WINDOW:
+ g_value_set_object (value, t->priv->window);
+ break;
+ }
+}
+
+static void
+ppview_toolbar_set_window (PPViewToolbar *t, EphyWindow *window)
+{
+ g_return_if_fail (t->priv->window == NULL);
+
+ t->priv->window = window;
+ t->priv->ui_component = BONOBO_UI_COMPONENT
+ (t->priv->window->ui_component);
+
+ bonobo_ui_component_add_verb_list_with_data (t->priv->ui_component,
+ ppview_toolbar_verbs,
+ t);
+}
+
+static void
+ppview_toolbar_init (PPViewToolbar *t)
+{
+ t->priv = g_new0 (PPViewToolbarPrivate, 1);
+
+ t->priv->window = NULL;
+ t->priv->ui_component = NULL;
+ t->priv->visibility = TRUE;
+}
+
+static void
+ppview_toolbar_finalize (GObject *object)
+{
+ PPViewToolbar *t;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (IS_PPVIEW_TOOLBAR (object));
+
+ t = PPVIEW_TOOLBAR (object);
+
+ g_return_if_fail (t->priv != NULL);
+
+ g_free (t->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+PPViewToolbar *
+ppview_toolbar_new (EphyWindow *window)
+{
+ PPViewToolbar *t;
+
+ t = PPVIEW_TOOLBAR (g_object_new (PPVIEW_TOOLBAR_TYPE,
+ "EphyWindow", window,
+ NULL));
+
+ g_return_val_if_fail (t->priv != NULL, NULL);
+
+ return t;
+}
+
+void
+ppview_toolbar_set_old_chrome (PPViewToolbar *t,
+ EmbedChromeMask chrome)
+{
+ t->priv->old_chrome = chrome;
+}
+
+static void
+toolbar_update_sensitivity (PPViewToolbar *t)
+{
+ int pages, c_page;
+ EphyWindow *window = t->priv->window;
+ EphyEmbed *embed;
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+
+ ephy_embed_print_preview_num_pages (embed, &pages);
+ c_page = t->priv->current_page;
+
+ ephy_bonobo_set_sensitive (t->priv->ui_component,
+ PPV_GO_BACK_PATH, c_page > 1);
+ ephy_bonobo_set_sensitive (t->priv->ui_component,
+ PPV_GOTO_FIRST_PATH, c_page > 1);
+ ephy_bonobo_set_sensitive (t->priv->ui_component,
+ PPV_GO_FORWARD_PATH, c_page < pages);
+ ephy_bonobo_set_sensitive (t->priv->ui_component,
+ PPV_GOTO_LAST_PATH, c_page < pages);
+}
+
+void
+ppview_toolbar_set_visibility (PPViewToolbar *t, gboolean visibility)
+{
+ if (visibility == t->priv->visibility) return;
+
+ t->priv->visibility = visibility;
+
+ if (visibility)
+ {
+ t->priv->current_page = 1;
+ toolbar_update_sensitivity (t);
+ }
+
+ ephy_bonobo_set_hidden (BONOBO_UI_COMPONENT(t->priv->ui_component),
+ "/PrintPreview",
+ !visibility);
+}
+
+static void
+toolbar_cmd_ppv_goto_first (BonoboUIComponent *uic,
+ PPViewToolbar *t,
+ const char* verbname)
+{
+ EphyWindow *window = t->priv->window;
+ EphyEmbed *embed;
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+
+ ephy_embed_print_preview_navigate (embed, PRINTPREVIEW_HOME, 0);
+
+ t->priv->current_page = 1;
+
+ toolbar_update_sensitivity (t);
+}
+
+static void
+toolbar_cmd_ppv_goto_last (BonoboUIComponent *uic,
+ PPViewToolbar *t,
+ const char* verbname)
+{
+ EphyWindow *window = t->priv->window;
+ EphyEmbed *embed;
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+
+ ephy_embed_print_preview_navigate (embed,
+ PRINTPREVIEW_END,
+ 0);
+
+ ephy_embed_print_preview_num_pages (embed,
+ &t->priv->current_page);
+
+ toolbar_update_sensitivity (t);
+}
+
+static void
+toolbar_cmd_ppv_go_back (BonoboUIComponent *uic,
+ PPViewToolbar *t,
+ const char* verbname)
+{
+ EphyWindow *window = t->priv->window;
+ EphyEmbed *embed;
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+
+ ephy_embed_print_preview_navigate (embed,
+ PRINTPREVIEW_PREV_PAGE,
+ 0);
+
+ t->priv->current_page --;
+
+ toolbar_update_sensitivity (t);
+}
+
+static void
+toolbar_cmd_ppv_go_forward (BonoboUIComponent *uic,
+ PPViewToolbar *t,
+ const char* verbname)
+{
+ EphyWindow *window = t->priv->window;
+ EphyEmbed *embed;
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+
+ ephy_embed_print_preview_navigate (embed,
+ PRINTPREVIEW_NEXT_PAGE,
+ 0);
+
+ t->priv->current_page ++;
+
+ toolbar_update_sensitivity (t);
+}
+
+static void
+toolbar_cmd_ppv_close (BonoboUIComponent *uic,
+ PPViewToolbar *t,
+ const char* verbname)
+{
+ EphyWindow *window = t->priv->window;
+ EphyEmbed *embed;
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+
+ ephy_window_set_chrome (window, t->priv->old_chrome);
+
+ ephy_embed_print_preview_close (embed);
+
+ toolbar_update_sensitivity (t);
+}
+
diff --git a/src/ppview-toolbar.h b/src/ppview-toolbar.h
new file mode 100644
index 000000000..3e6a4b504
--- /dev/null
+++ b/src/ppview-toolbar.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef PPVIEW_TOOLBAR_H
+#define PPVIEW_TOOLBAR_H
+
+#include "ephy-window.h"
+#include <glib-object.h>
+#include <glib.h>
+#include <gtk/gtkbutton.h>
+
+G_BEGIN_DECLS
+
+typedef struct PPViewToolbar PPViewToolbar;
+typedef struct PPViewToolbarClass PPViewToolbarClass;
+
+#define PPVIEW_TOOLBAR_TYPE (ppview_toolbar_get_type ())
+#define PPVIEW_TOOLBAR(obj) (GTK_CHECK_CAST ((obj), PPVIEW_TOOLBAR_TYPE, PPViewToolbar))
+#define PPVIEW_TOOLBAR_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), PPVIEW_TOOLBAR, PPViewToolbarClass))
+#define IS_PPVIEW_TOOLBAR(obj) (GTK_CHECK_TYPE ((obj), PPVIEW_TOOLBAR_TYPE))
+#define IS_PPVIEW_TOOLBAR_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), PPVIEW_TOOLBAR))
+
+typedef struct PPViewToolbarPrivate PPViewToolbarPrivate;
+
+struct PPViewToolbar
+{
+ GObject parent;
+ PPViewToolbarPrivate *priv;
+};
+
+struct PPViewToolbarClass
+{
+ GObjectClass parent_class;
+};
+
+GType ppview_toolbar_get_type (void);
+
+PPViewToolbar *ppview_toolbar_new (EphyWindow *window);
+
+void ppview_toolbar_set_visibility (PPViewToolbar *t,
+ gboolean visibility);
+
+void ppview_toolbar_set_old_chrome (PPViewToolbar *t,
+ EmbedChromeMask chrome);
+
+G_END_DECLS
+
+#endif
diff --git a/src/prefs-dialog.c b/src/prefs-dialog.c
new file mode 100644
index 000000000..8f010420c
--- /dev/null
+++ b/src/prefs-dialog.c
@@ -0,0 +1,335 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "prefs-dialog.h"
+#include "general-prefs.h"
+#include "appearance-prefs.h"
+#include "ui-prefs.h"
+#include "ephy-dialog.h"
+#include "ephy-prefs.h"
+#include "ephy-embed-prefs.h"
+#include "ephy-shell.h"
+#include "ephy-state.h"
+
+#include <bonobo/bonobo-i18n.h>
+#include <gtk/gtkframe.h>
+#include <gtk/gtkhbox.h>
+#include <gtk/gtkvbox.h>
+#include <gtk/gtkradiobutton.h>
+#include <gtk/gtktogglebutton.h>
+#include <gtk/gtkimage.h>
+#include <gtk/gtklabel.h>
+#include <gtk/gtkstock.h>
+
+static void
+prefs_dialog_class_init (PrefsDialogClass *klass);
+static void
+prefs_dialog_init (PrefsDialog *pd);
+static void
+prefs_dialog_finalize (GObject *object);
+
+/* Glade callbacks */
+void
+prefs_proxy_auto_url_reload_cb (GtkWidget *button,
+ EphyDialog *dialog);
+void
+prefs_clear_memory_cache_button_clicked_cb (GtkWidget *button,
+ gpointer data);
+void
+prefs_clear_disk_cache_button_clicked_cb (GtkWidget *button,
+ gpointer data);
+
+
+/* Proxy page */
+
+enum
+{
+ CACHE_COMPARE_PROP,
+ DISK_CACHE_PROP,
+ MEMORY_CACHE_PROP
+};
+
+static const
+EphyDialogProperty network_properties [] =
+{
+ { CACHE_COMPARE_PROP, "cache_compare_radiobutton", CONF_NETWORK_CACHE_COMPARE, PT_AUTOAPPLY, NULL },
+ { DISK_CACHE_PROP, "disk_cache_spin", CONF_NETWORK_DISK_CACHE, PT_AUTOAPPLY, NULL },
+ { MEMORY_CACHE_PROP, "memory_cache_spin", CONF_NETWORK_MEMORY_CACHE, PT_AUTOAPPLY, NULL },
+
+ { -1, NULL, NULL }
+};
+
+struct PrefsDialogPrivate
+{
+ GtkWidget *notebook;
+};
+
+static GObjectClass *parent_class = NULL;
+
+GType
+prefs_dialog_get_type (void)
+{
+ static GType prefs_dialog_type = 0;
+
+ if (prefs_dialog_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (PrefsDialogClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) prefs_dialog_class_init,
+ NULL,
+ NULL, /* class_data */
+ sizeof (PrefsDialog),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) prefs_dialog_init
+ };
+
+ prefs_dialog_type = g_type_register_static (GTK_TYPE_DIALOG,
+ "PrefsDialog",
+ &our_info, 0);
+ }
+
+ return prefs_dialog_type;
+
+}
+
+GtkDialog *
+prefs_dialog_new (void)
+{
+ GtkDialog *dialog;
+
+ dialog = GTK_DIALOG (g_object_new (PREFS_DIALOG_TYPE, NULL));
+
+ return dialog;
+}
+
+static void
+prefs_dialog_class_init (PrefsDialogClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = prefs_dialog_finalize;
+}
+
+static void
+prefs_dialog_finalize (GObject *object)
+{
+ PrefsDialog *pd;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (IS_PREFS_DIALOG (object));
+
+ pd = PREFS_DIALOG (object);
+
+ g_return_if_fail (pd->priv != NULL);
+
+ g_free (pd->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static EphyDialog *
+create_page (PrefsPageID id,
+ const char *page_widget,
+ const EphyDialogProperty *prop)
+{
+ EphyDialog *page = NULL;
+
+ switch (id)
+ {
+ case PREFS_PAGE_GENERAL:
+ page = general_prefs_new ();
+ break;
+ case PREFS_PAGE_APPEARANCE:
+ page = appearance_prefs_new ();
+ break;
+ case PREFS_PAGE_UI:
+ page = ui_prefs_new ();
+ break;
+ case PREFS_PAGE_ADVANCED:
+ page = ephy_dialog_new ();
+ ephy_dialog_construct (EPHY_DIALOG(page),
+ prop,
+ "prefs-dialog.glade",
+ page_widget);
+ break;
+ }
+
+ return page;
+}
+
+static EphyDialog *
+prefs_dialog_get_page (PrefsDialog *pd,
+ PrefsPageID id)
+{
+ const char *page_widget = NULL;
+ EphyDialog *page;
+ const EphyDialogProperty *prop = NULL;
+
+ switch (id)
+ {
+ case PREFS_PAGE_APPEARANCE:
+ page_widget = "appearance_page_box";
+ break;
+ case PREFS_PAGE_GENERAL:
+ page_widget = "general_page_box";
+ break;
+ case PREFS_PAGE_UI:
+ page_widget = "ui_page_box";
+ break;
+ case PREFS_PAGE_ADVANCED:
+ page_widget = "network_page_box";
+ prop = network_properties;
+ break;
+ }
+
+ g_assert (page_widget != NULL);
+
+ page = create_page (id, page_widget, prop);
+ g_assert (page != NULL);
+
+ return page;
+}
+
+void
+prefs_dialog_show_page (PrefsDialog *pd,
+ PrefsPageID id)
+{
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (pd->priv->notebook), id);
+}
+
+static void
+prefs_dialog_response_cb (GtkDialog *dialog, gint response_id, gpointer data)
+{
+ if (response_id == GTK_RESPONSE_CLOSE)
+ {
+ gtk_widget_destroy (GTK_WIDGET(dialog));
+ }
+}
+
+static void
+prefs_build_notebook (PrefsDialog *pd)
+{
+ int i;
+ GtkWidget *nb;
+
+ struct
+ {
+ char *name;
+ int id;
+ }
+ pages[] =
+ {
+ { _("General"), PREFS_PAGE_GENERAL },
+ { _("Appearance"), PREFS_PAGE_APPEARANCE },
+ { _("User Interface"), PREFS_PAGE_UI },
+ { _("Advanced"), PREFS_PAGE_ADVANCED },
+
+ { NULL, 0 }
+ };
+
+ gtk_dialog_add_button (GTK_DIALOG (pd), GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE);
+
+ g_signal_connect (pd, "response",
+ G_CALLBACK (prefs_dialog_response_cb),
+ NULL);
+
+ gtk_container_set_border_width (GTK_CONTAINER (pd), 5);
+
+ nb = gtk_notebook_new ();
+ gtk_container_set_border_width (GTK_CONTAINER (nb), 5);
+ gtk_widget_show (nb);
+ gtk_container_add (GTK_CONTAINER (GTK_DIALOG (pd)->vbox), nb);
+ gtk_notebook_set_show_tabs (GTK_NOTEBOOK (nb), TRUE);
+ pd->priv->notebook = nb;
+
+ for (i = 0; pages[i].name != NULL; i++)
+ {
+ GtkWidget *label, *child;
+ EphyDialog *page;
+
+ page = prefs_dialog_get_page (pd, pages[i].id);
+
+ child = gtk_hbox_new (FALSE, 0);
+ gtk_widget_show (child);
+ label = gtk_label_new (pages[i].name);
+ gtk_notebook_append_page (GTK_NOTEBOOK (nb),
+ child, label);
+
+ ephy_dialog_show_embedded (page, child);
+ }
+}
+
+static gboolean
+prefs_dialog_configure_event_cb (GtkWidget *widget,
+ GdkEventConfigure *event,
+ gpointer data)
+{
+ ephy_state_save_window (widget, "prefs_dialog");
+
+ return FALSE;
+}
+
+static void
+prefs_dialog_init (PrefsDialog *pd)
+{
+ pd->priv = g_new0 (PrefsDialogPrivate, 1);
+
+ gtk_window_set_title (GTK_WINDOW(pd), _("Preferences"));
+ gtk_dialog_set_has_separator (GTK_DIALOG(pd), FALSE);
+
+ ephy_state_load_window (GTK_WIDGET(pd),
+ "prefs_dialog", -1, -1, FALSE);
+
+ g_signal_connect (pd,
+ "configure_event",
+ G_CALLBACK (prefs_dialog_configure_event_cb),
+ NULL);
+
+ prefs_build_notebook (pd);
+}
+
+/* Network page callbacks */
+
+void
+prefs_clear_memory_cache_button_clicked_cb (GtkWidget *button,
+ gpointer data)
+{
+ EphyEmbedShell *shell;
+
+ shell = ephy_shell_get_embed_shell (ephy_shell);
+ ephy_embed_shell_clear_cache (shell, MEMORY_CACHE);
+}
+
+void
+prefs_clear_disk_cache_button_clicked_cb (GtkWidget *button,
+ gpointer data)
+{
+ EphyEmbedShell *shell;
+
+ shell = ephy_shell_get_embed_shell (ephy_shell);
+ ephy_embed_shell_clear_cache (shell, DISK_CACHE);
+}
diff --git a/src/prefs-dialog.h b/src/prefs-dialog.h
new file mode 100644
index 000000000..3c5528b2f
--- /dev/null
+++ b/src/prefs-dialog.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef PREFS_DIALOG_H
+#define PREFS_DIALOG_H
+
+#include <gtk/gtkdialog.h>
+#include <glib-object.h>
+#include <glib.h>
+
+typedef struct PrefsDialog PrefsDialog;
+typedef struct PrefsDialogClass PrefsDialogClass;
+
+#define PREFS_DIALOG_TYPE (prefs_dialog_get_type ())
+#define PREFS_DIALOG(obj) (GTK_CHECK_CAST ((obj), PREFS_DIALOG_TYPE, PrefsDialog))
+#define PREFS_DIALOG_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), PREFS_DIALOG, PrefsDialogClass))
+#define IS_PREFS_DIALOG(obj) (GTK_CHECK_TYPE ((obj), PREFS_DIALOG_TYPE))
+#define IS_PREFS_DIALOG_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), PREFS_DIALOG))
+
+typedef struct PrefsDialogPrivate PrefsDialogPrivate;
+
+typedef enum
+{
+ PREFS_PAGE_GENERAL,
+ PREFS_PAGE_APPEARANCE,
+ PREFS_PAGE_UI,
+ PREFS_PAGE_ADVANCED
+} PrefsPageID;
+
+struct PrefsDialog
+{
+ GtkDialog parent;
+ PrefsDialogPrivate *priv;
+};
+
+struct PrefsDialogClass
+{
+ GtkDialogClass parent_class;
+};
+
+GType prefs_dialog_get_type (void);
+
+GtkDialog *prefs_dialog_new (void);
+
+void prefs_dialog_show_page (PrefsDialog *pd,
+ PrefsPageID id);
+
+#endif
diff --git a/src/session.c b/src/session.c
new file mode 100644
index 000000000..920b49df9
--- /dev/null
+++ b/src/session.c
@@ -0,0 +1,690 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "session.h"
+#include "ephy-shell.h"
+#include "ephy-tab.h"
+#include "ephy-window.h"
+#include "ephy-prefs.h"
+#include "ephy-string.h"
+#include "ephy-file-helpers.h"
+#include "eel-gconf-extensions.h"
+
+#include <libgnome/gnome-i18n.h>
+#include <string.h>
+#include <gtk/gtkdialog.h>
+#include <gtk/gtkimage.h>
+#include <gtk/gtklabel.h>
+#include <gtk/gtkstock.h>
+#include <gtk/gtkhbox.h>
+#include <gtk/gtkvbox.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/xmlmemory.h>
+#include <libgnomevfs/gnome-vfs-ops.h>
+#include <libgnomeui/gnome-client.h>
+
+enum
+{
+ RESTORE_TYPE_PROP
+};
+
+enum
+{
+ RESTORE_SESSION,
+ RESTORE_AS_BOOKMARKS,
+ DISCARD_SESSION
+};
+
+static void session_class_init (SessionClass *klass);
+static void session_init (Session *t);
+static void session_finalize (GObject *object);
+static void session_dispose (GObject *object);
+
+static GObjectClass *parent_class = NULL;
+
+struct SessionPrivate
+{
+ GList *windows;
+ gboolean dont_remove_crashed;
+};
+
+enum
+{
+ NEW_WINDOW,
+ CLOSE_WINDOW,
+ LAST_SIGNAL
+};
+
+static guint session_signals[LAST_SIGNAL] = { 0 };
+
+GType
+session_get_type (void)
+{
+ static GType session_type = 0;
+
+ if (session_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (SessionClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) session_class_init,
+ NULL,
+ NULL, /* class_data */
+ sizeof (Session),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) session_init
+ };
+
+ session_type = g_type_register_static (G_TYPE_OBJECT,
+ "Session",
+ &our_info, 0);
+ }
+
+ return session_type;
+
+}
+
+static void
+session_class_init (SessionClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = session_finalize;
+ object_class->dispose = session_dispose;
+
+ session_signals[NEW_WINDOW] =
+ g_signal_new ("new_window",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (SessionClass, new_window),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_OBJECT);
+
+ session_signals[CLOSE_WINDOW] =
+ g_signal_new ("close_window",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (SessionClass, close_window),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+}
+
+static char *
+get_session_filename (const char *filename)
+{
+ char *save_to;
+
+ g_return_val_if_fail (filename != NULL, NULL);
+
+ if (strcmp (filename, SESSION_CRASHED) == 0)
+ {
+ save_to = g_build_filename (ephy_dot_dir (),
+ "session_crashed.xml",
+ NULL);
+ }
+ else if (strcmp (filename, SESSION_GNOME) == 0)
+ {
+ char *tmp;
+
+ save_to = g_build_filename (ephy_dot_dir (),
+ "session_gnome-XXXXXX",
+ NULL);
+ tmp = ephy_file_tmp_filename (save_to, "xml");
+ g_free (save_to);
+ save_to = tmp;
+ }
+ else
+ {
+ save_to = g_strdup (filename);
+ }
+
+ return save_to;
+}
+
+static void
+do_session_resume (Session *session)
+{
+ const char *crashed_session;
+
+ crashed_session = get_session_filename (SESSION_CRASHED);
+ session_load (session, crashed_session);
+}
+
+static void
+crashed_resume_dialog (Session *session)
+{
+ GtkWidget *dialog;
+ GtkWidget *label;
+ GtkWidget *vbox;
+ GtkWidget *hbox;
+ GtkWidget *image;
+
+ dialog = gtk_dialog_new_with_buttons
+ (_("Crash Recovery"), NULL,
+ GTK_DIALOG_NO_SEPARATOR,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ _("_Recover"), GTK_RESPONSE_OK,
+ NULL);
+ gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
+ gtk_container_set_border_width (GTK_CONTAINER (dialog), 6);
+ gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->vbox), 12);
+
+ hbox = gtk_hbox_new (FALSE, 6);
+ gtk_widget_show (hbox);
+ gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox,
+ TRUE, TRUE, 0);
+
+ image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING,
+ GTK_ICON_SIZE_DIALOG);
+ gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0.0);
+ gtk_widget_show (image);
+ gtk_box_pack_start (GTK_BOX (hbox), image,
+ TRUE, TRUE, 0);
+
+ vbox = gtk_vbox_new (FALSE, 6);
+ gtk_widget_show (vbox);
+ gtk_box_pack_start (GTK_BOX (hbox), vbox,
+ TRUE, TRUE, 0);
+
+ label = gtk_label_new (NULL);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+ gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
+ gtk_widget_show (label);
+ gtk_label_set_markup (GTK_LABEL (label),
+ _("<b>Epiphany appears to have crashed or been killed the last time it was run.</b>"));
+ gtk_box_pack_start (GTK_BOX (vbox), label,
+ TRUE, TRUE, 0);
+
+ label = gtk_label_new (_("You can recover the opened tabs and windows."));
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+ gtk_widget_show (label);
+ gtk_box_pack_start (GTK_BOX (vbox), label,
+ TRUE, TRUE, 0);
+
+ if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK)
+ {
+ do_session_resume (session);
+ }
+
+ gtk_widget_destroy (dialog);
+}
+
+/**
+ * session_autoresume:
+ * @session: a #Session
+ *
+ * Resume a crashed session when necessary (interactive)
+ *
+ * Return value: return false if no window has been opened
+ **/
+gboolean
+session_autoresume (Session *session)
+{
+ char *saved_session;
+ gboolean loaded = FALSE;
+
+ saved_session = get_session_filename (SESSION_CRASHED);
+
+ if (g_file_test (saved_session, G_FILE_TEST_EXISTS))
+ {
+ crashed_resume_dialog (session);
+ loaded = TRUE;
+ }
+
+ g_free (saved_session);
+
+ /* return false if no window has been opened */
+ return (session->priv->windows != NULL);
+}
+
+static void
+create_session_directory (void)
+{
+ char *dir;
+
+ dir = g_build_filename (ephy_dot_dir (),
+ "/sessions",
+ NULL);
+
+ if (!g_file_test (dir, G_FILE_TEST_EXISTS))
+ {
+ if (mkdir (dir, 488) != 0)
+ {
+ g_error ("couldn't make %s' directory", dir);
+ }
+ }
+
+ g_free (dir);
+}
+
+static gboolean
+save_yourself_cb (GnomeClient *client,
+ gint phase,
+ GnomeSaveStyle save_style,
+ gboolean shutdown,
+ GnomeInteractStyle interact_style,
+ gboolean fast,
+ Session *session)
+{
+ char *argv[] = { "ephy", "--load-session", NULL };
+ char *discard_argv[] = { "rm", "-r", NULL };
+
+ argv[2] = get_session_filename (SESSION_GNOME);
+ gnome_client_set_restart_command
+ (client, 3, argv);
+
+ discard_argv[2] = argv[2];
+ gnome_client_set_discard_command (client, 3,
+ discard_argv);
+
+ session_save (session, argv[2]);
+
+ g_free (argv[2]);
+
+ return TRUE;
+}
+
+static void
+session_die_cb (GnomeClient* client,
+ Session *session)
+{
+ session_close (session);
+}
+
+static void
+gnome_session_init (Session *session)
+{
+ GnomeClient *client;
+
+ client = gnome_master_client ();
+
+ g_signal_connect (G_OBJECT (client),
+ "save_yourself",
+ G_CALLBACK (save_yourself_cb),
+ session);
+
+ g_signal_connect (G_OBJECT (client),
+ "die",
+ G_CALLBACK (session_die_cb),
+ session);
+}
+
+static void
+session_init (Session *session)
+{
+ session->priv = g_new0 (SessionPrivate, 1);
+ session->priv->windows = NULL;
+ session->priv->dont_remove_crashed = FALSE;
+
+ create_session_directory ();
+
+ gnome_session_init (session);
+}
+
+/*
+ * session_close:
+ * @session: a #Session
+ *
+ * Close the session and all the owned windows
+ **/
+void
+session_close (Session *session)
+{
+ GList *l;
+
+ /* close all windows */
+ l = g_list_copy (session->priv->windows);
+ for (; l != NULL; l = l->next)
+ {
+ EphyWindow *window = EPHY_WINDOW(l->data);
+ gtk_widget_destroy (GTK_WIDGET(window));
+ }
+}
+
+static void
+session_delete (Session *session,
+ const char *filename)
+{
+ char *save_to;
+
+ save_to = get_session_filename (filename);
+
+ gnome_vfs_unlink (save_to);
+
+ g_free (save_to);
+}
+
+static void
+session_dispose (GObject *object)
+{
+ Session *session = SESSION(object);
+
+ if (!session->priv->dont_remove_crashed)
+ {
+ session_delete (session, SESSION_CRASHED);
+ }
+}
+
+static void
+session_finalize (GObject *object)
+{
+ Session *t;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (IS_SESSION (object));
+
+ t = SESSION (object);
+
+ g_return_if_fail (t->priv != NULL);
+
+ g_list_free (t->priv->windows);
+
+ g_free (t->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+/**
+ * session_new:
+ *
+ * Create a #Session. A session hold the information
+ * about the windows currently opened and is able to persist
+ * and restore his status.
+ **/
+Session *
+session_new (void)
+{
+ Session *t;
+
+ t = SESSION (g_object_new (SESSION_TYPE, NULL));
+
+ g_return_val_if_fail (t->priv != NULL, NULL);
+
+ return t;
+}
+
+static void
+save_tab (EphyWindow *window,
+ EphyTab *tab,
+ xmlDocPtr doc,
+ xmlNodePtr window_node)
+{
+ EmbedChromeMask chrome;
+ const char *location;
+ const char *title;
+ xmlNodePtr embed_node;
+
+ chrome = ephy_window_get_chrome (window);
+
+ /* skip if it's a XUL dialog */
+ if (chrome & EMBED_CHROME_OPENASCHROME) return;
+
+ /* make a new XML node */
+ embed_node = xmlNewDocNode (doc, NULL,
+ "embed", NULL);
+
+ /* store title in the node */
+ title = ephy_tab_get_title (tab);
+ xmlSetProp (embed_node, "title", title);
+
+ /* otherwise, use the actual location. */
+ location = ephy_tab_get_location (tab);
+ xmlSetProp (embed_node, "url", location);
+
+ /* insert node into the tree */
+ xmlAddChild (window_node, embed_node);
+}
+
+/*
+ * session_save:
+ * @session: a #Session
+ * @filename: path of the xml file where the session is saved.
+ *
+ * Save the session on disk. Keep information about window size,
+ * opened urls ...
+ **/
+void
+session_save (Session *session,
+ const char *filename)
+{
+ GList *w;
+ xmlNodePtr root_node;
+ xmlNodePtr window_node;
+ xmlDocPtr doc;
+ gchar buffer[32];
+ char *save_to;
+
+ save_to = get_session_filename (filename);
+
+ doc = xmlNewDoc ("1.0");
+
+ /* create and set the root node for the session */
+ root_node = xmlNewDocNode (doc, NULL, "session", NULL);
+ xmlDocSetRootElement (doc, root_node);
+
+ w = session_get_windows (session);
+
+ /* iterate through all the windows */
+ for (; w != NULL; w = w->next)
+ {
+ const GList *tabs;
+ int x = 0, y = 0, width = 0, height = 0;
+ EphyWindow *window = EPHY_WINDOW(w->data);
+ GtkWidget *wmain;
+
+ tabs = ephy_window_get_tabs (window);
+ g_return_if_fail (tabs != NULL);
+
+ /* make a new XML node */
+ window_node = xmlNewDocNode (doc, NULL, "window", NULL);
+
+ /* get window geometry */
+ wmain = GTK_WIDGET (window);
+ gtk_window_get_size (GTK_WINDOW(wmain), &width, &height);
+ gtk_window_get_position (GTK_WINDOW(wmain), &x, &y);
+
+ /* set window properties */
+ snprintf(buffer, 32, "%d", x);
+ xmlSetProp (window_node, "x", buffer);
+ snprintf(buffer, 32, "%d", y);
+
+ xmlSetProp (window_node, "y", buffer);
+ snprintf(buffer, 32, "%d", width);
+ xmlSetProp (window_node, "width", buffer);
+ snprintf(buffer, 32, "%d", height);
+ xmlSetProp (window_node, "height", buffer);
+
+ for (; tabs != NULL; tabs = tabs->next)
+ {
+ EphyTab *tab = EPHY_TAB(tabs->data);
+ save_tab (window, tab, doc, window_node);
+ }
+
+ xmlAddChild (root_node, window_node);
+ }
+
+ /* save it all out to disk */
+ xmlSaveFile (save_to, doc);
+ xmlFreeDoc (doc);
+
+ g_free (save_to);
+}
+
+static void
+parse_embed (xmlNodePtr child, EphyWindow *window)
+{
+ EphyTab *tab;
+ EphyEmbed *embed;
+
+ while (child != NULL)
+ {
+ if (strcmp (child->name, "embed") == 0)
+ {
+ char *url;
+ char *title;
+
+ g_return_if_fail (window != NULL);
+
+ url = xmlGetProp (child, "url");
+ title = xmlGetProp (child, "title");
+
+ tab = ephy_tab_new ();
+ embed = ephy_tab_get_embed (tab);
+
+ gtk_widget_show (GTK_WIDGET(embed));
+
+ ephy_window_add_tab (window, tab, FALSE);
+
+ ephy_embed_load_url (embed, url);
+
+ xmlFree (url);
+ xmlFree (title);
+ }
+
+ child = child->next;
+ }
+}
+
+/*
+ * session_load:
+ * @session: a #Session
+ * @filename: the path of the source file
+ *
+ * Load a session from disk, restoring the windows and their state
+ **/
+void
+session_load (Session *session,
+ const char *filename)
+{
+ xmlDocPtr doc;
+ xmlNodePtr child;
+ GtkWidget *wmain;
+ EphyWindow *window;
+ char *save_to;
+
+ save_to = get_session_filename (filename);
+
+ doc = xmlParseFile (save_to);
+
+ child = xmlDocGetRootElement (doc);
+
+ /* skip the session node */
+ child = child->children;
+
+ while (child != NULL)
+ {
+ if (strcmp (child->name, "window") == 0)
+ {
+ gint x = 0, y = 0, width = 0, height = 0;
+ xmlChar *tmp;
+
+ tmp = xmlGetProp (child, "x");
+ ephy_str_to_int (tmp, &x);
+ xmlFree (tmp);
+ tmp = xmlGetProp (child, "y");
+ ephy_str_to_int (tmp, &y);
+ xmlFree (tmp);
+ tmp = xmlGetProp (child, "width");
+ ephy_str_to_int (tmp, &width);
+ xmlFree (tmp);
+ tmp = xmlGetProp (child, "height");
+ ephy_str_to_int (tmp, &height);
+ xmlFree (tmp);
+
+ window = ephy_window_new ();
+ wmain = GTK_WIDGET (window);
+ gtk_widget_show (GTK_WIDGET(window));
+
+ gtk_window_move (GTK_WINDOW(wmain), x, y);
+ gtk_window_set_default_size (GTK_WINDOW (wmain),
+ width, height);
+
+ parse_embed (child->children, window);
+ }
+
+ child = child->next;
+ }
+
+ xmlFreeDoc (doc);
+
+ g_free (save_to);
+}
+
+GList *
+session_get_windows (Session *session)
+{
+ g_return_val_if_fail (IS_SESSION (session), NULL);
+
+ return session->priv->windows;
+}
+
+/**
+ * session_add_window:
+ * @session: a #Session
+ * @window: a #EphyWindow
+ *
+ * Add a window to the session. #EphyWindow take care of adding
+ * itself to session.
+ **/
+void
+session_add_window (Session *session,
+ EphyWindow *window)
+{
+ session->priv->windows = g_list_append (session->priv->windows, window);
+
+ g_signal_emit (G_OBJECT (session),
+ session_signals[NEW_WINDOW],
+ 0, window);
+}
+
+/**
+ * session_remove_window:
+ * @session: a #Session
+ * @window: a #EphyWindow
+ *
+ * Remove a window from the session. #EphyWindow take care of removing
+ * itself to session.
+ **/
+void
+session_remove_window (Session *session,
+ EphyWindow *window)
+{
+ g_signal_emit (G_OBJECT (session),
+ session_signals[CLOSE_WINDOW],
+ 0);
+
+ session->priv->windows = g_list_remove (session->priv->windows, window);
+
+ /* autodestroy of the session, necessay to avoid
+ * conflicts with the nautilus view */
+ if (session->priv->windows == NULL)
+ {
+ g_object_unref (session);
+ }
+}
+
diff --git a/src/session.h b/src/session.h
new file mode 100644
index 000000000..e2ac6b9b2
--- /dev/null
+++ b/src/session.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef SESSION_H
+#define SESSION_H
+
+#define SESSION_CRASHED "type:session_crashed"
+#define SESSION_GNOME "type:session_gnome"
+
+#include "ephy-window.h"
+
+G_BEGIN_DECLS
+
+#include <glib-object.h>
+#include <glib.h>
+
+typedef struct Session Session;
+typedef struct SessionClass SessionClass;
+
+#define SESSION_TYPE (session_get_type ())
+#define SESSION(obj) (GTK_CHECK_CAST ((obj), SESSION_TYPE, Session))
+#define SESSION_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), SESSION, SessionClass))
+#define IS_SESSION(obj) (GTK_CHECK_TYPE ((obj), SESSION_TYPE))
+#define IS_SESSION_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), SESSION))
+
+typedef struct SessionPrivate SessionPrivate;
+
+struct Session
+{
+ GObject parent;
+ SessionPrivate *priv;
+};
+
+struct SessionClass
+{
+ GObjectClass parent_class;
+
+ void ( *new_window) (Session *session,
+ EphyWindow *window);
+ void ( *close_window) (Session *session);
+};
+
+GType session_get_type (void);
+
+Session *session_new (void);
+
+void session_close (Session *session);
+
+void session_load (Session *session,
+ const char *filename);
+
+void session_save (Session *session,
+ const char *filename);
+
+gboolean session_autoresume (Session *session);
+
+GList *session_get_windows (Session *session);
+
+void session_add_window (Session *session,
+ EphyWindow *window);
+
+void session_remove_window (Session *session,
+ EphyWindow *window);
+
+EphyWindow *session_get_active_window (Session *session);
+
+G_END_DECLS
+
+#endif
diff --git a/src/statusbar.c b/src/statusbar.c
new file mode 100755
index 000000000..8ac84cfb9
--- /dev/null
+++ b/src/statusbar.c
@@ -0,0 +1,321 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "statusbar.h"
+#include "ephy-stock-icons.h"
+#include "ephy-bonobo-extensions.h"
+
+#include <string.h>
+#include <time.h>
+#include <gtk/gtkprogressbar.h>
+#include <gtk/gtkeventbox.h>
+#include <gtk/gtkimage.h>
+#include <gtk/gtkframe.h>
+#include <gtk/gtktooltips.h>
+#include <bonobo/bonobo-window.h>
+#include <bonobo/bonobo-control.h>
+
+static void statusbar_class_init (StatusbarClass *klass);
+static void statusbar_init (Statusbar *t);
+static void statusbar_finalize (GObject *object);
+static void
+statusbar_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void
+statusbar_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void
+statusbar_set_window (Statusbar *t, EphyWindow *window);
+
+enum
+{
+ PROP_0,
+ PROP_EPHY_WINDOW
+};
+
+static GObjectClass *parent_class = NULL;
+
+struct StatusbarPrivate
+{
+ EphyWindow *window;
+ BonoboUIComponent *ui_component;
+ GtkWidget *security_icon;
+ GtkWidget *progress;
+ GtkTooltips *tooltips;
+ GtkWidget *security_evbox;
+ gboolean visibility;
+};
+
+GType
+statusbar_get_type (void)
+{
+ static GType statusbar_type = 0;
+
+ if (statusbar_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (StatusbarClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) statusbar_class_init,
+ NULL,
+ NULL, /* class_data */
+ sizeof (Statusbar),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) statusbar_init
+ };
+
+ statusbar_type = g_type_register_static (G_TYPE_OBJECT,
+ "Statusbar",
+ &our_info, 0);
+ }
+
+ return statusbar_type;
+
+}
+
+static void
+statusbar_class_init (StatusbarClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = statusbar_finalize;
+ object_class->set_property = statusbar_set_property;
+ object_class->get_property = statusbar_get_property;
+
+ g_object_class_install_property (object_class,
+ PROP_EPHY_WINDOW,
+ g_param_spec_object ("EphyWindow",
+ "EphyWindow",
+ "Parent window",
+ EPHY_WINDOW_TYPE,
+ G_PARAM_READWRITE));
+}
+
+static void
+statusbar_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ Statusbar *s = STATUSBAR (object);
+
+ switch (prop_id)
+ {
+ case PROP_EPHY_WINDOW:
+ statusbar_set_window (s, g_value_get_object (value));
+ break;
+ }
+}
+
+static void
+statusbar_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ Statusbar *s = STATUSBAR (object);
+
+ switch (prop_id)
+ {
+ case PROP_EPHY_WINDOW:
+ g_value_set_object (value, s->priv->window);
+ break;
+ }
+}
+
+static void
+create_statusbar_security_icon (Statusbar *s)
+{
+ GtkWidget *security_frame;
+ BonoboControl *control;
+
+ security_frame = gtk_frame_new (NULL);
+ gtk_frame_set_shadow_type (GTK_FRAME (security_frame),
+ GTK_SHADOW_IN);
+
+ s->priv->security_icon = gtk_image_new ();
+ s->priv->security_evbox = gtk_event_box_new ();
+ gtk_container_add (GTK_CONTAINER (security_frame),
+ GTK_WIDGET (s->priv->security_evbox));
+ gtk_container_add (GTK_CONTAINER (s->priv->security_evbox),
+ GTK_WIDGET (s->priv->security_icon));
+ /*
+ g_signal_connect (G_OBJECT (security_eventbox),
+ "button_release_event",
+ GTK_SIGNAL_FUNC
+ (security_icon_button_release_cb), t);
+ */
+
+ control = bonobo_control_new (security_frame);
+ bonobo_ui_component_object_set (s->priv->ui_component,
+ "/status/SecurityIconWrapper",
+ BONOBO_OBJREF (control),
+ NULL);
+ bonobo_object_unref (control);
+
+ statusbar_set_security_state (s, FALSE, NULL);
+
+ gtk_widget_show_all (security_frame);
+}
+
+static void
+create_statusbar_progress (Statusbar *s)
+{
+ BonoboControl *control;
+
+ s->priv->progress = gtk_progress_bar_new ();
+
+ control = bonobo_control_new (s->priv->progress);
+ bonobo_ui_component_object_set (s->priv->ui_component,
+ "/status/ProgressWrapper",
+ BONOBO_OBJREF (control),
+ NULL);
+
+ gtk_widget_show_all (s->priv->progress);
+}
+
+static void
+statusbar_set_window (Statusbar *s, EphyWindow *window)
+{
+ g_return_if_fail (s->priv->window == NULL);
+
+ s->priv->window = window;
+ s->priv->ui_component = BONOBO_UI_COMPONENT
+ (s->priv->window->ui_component);
+
+ create_statusbar_progress (s);
+ create_statusbar_security_icon (s);
+}
+
+static void
+statusbar_init (Statusbar *t)
+{
+ t->priv = g_new0 (StatusbarPrivate, 1);
+ t->priv->visibility = TRUE;
+
+ t->priv->tooltips = gtk_tooltips_new ();
+}
+
+static void
+statusbar_finalize (GObject *object)
+{
+ Statusbar *t;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (IS_STATUSBAR (object));
+
+ t = STATUSBAR (object);
+
+ g_return_if_fail (t->priv != NULL);
+
+ gtk_object_destroy (GTK_OBJECT (t->priv->tooltips));
+
+ g_free (t->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+Statusbar *
+statusbar_new (EphyWindow *window)
+{
+ Statusbar *t;
+
+ t = STATUSBAR (g_object_new (STATUSBAR_TYPE,
+ "EphyWindow", window,
+ NULL));
+
+ g_return_val_if_fail (t->priv != NULL, NULL);
+
+ return t;
+}
+
+void
+statusbar_set_visibility (Statusbar *t,
+ gboolean visibility)
+{
+ if (visibility == t->priv->visibility) return;
+
+ t->priv->visibility = visibility;
+
+ ephy_bonobo_set_hidden (BONOBO_UI_COMPONENT(t->priv->ui_component),
+ "/status",
+ !visibility);
+}
+
+void
+statusbar_set_security_state (Statusbar *t,
+ gboolean state,
+ const char *tooltip)
+{
+ const char *stock;
+
+ stock = state ? EPHY_STOCK_SECURE : EPHY_STOCK_UNSECURE;
+
+ gtk_image_set_from_stock (GTK_IMAGE (t->priv->security_icon), stock,
+ GTK_ICON_SIZE_MENU);
+
+ gtk_tooltips_set_tip (t->priv->tooltips, t->priv->security_evbox,
+ tooltip, NULL);
+}
+
+void
+statusbar_set_progress (Statusbar *t,
+ int progress)
+{
+ if (progress == -1)
+ {
+ gtk_progress_bar_pulse (GTK_PROGRESS_BAR(t->priv->progress));
+ }
+ else
+ {
+ float tmp;
+ tmp = (float)(progress) / 100;
+ gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(t->priv->progress),
+ tmp);
+ }
+}
+
+void
+statusbar_set_message (Statusbar *s,
+ const char *message)
+{
+ g_return_if_fail (BONOBO_IS_UI_COMPONENT(s->priv->ui_component));
+ g_return_if_fail (message != NULL);
+
+ /* Bonobo doesnt like 0 length messages */
+ if (g_utf8_strlen (message, -1) == 0)
+ {
+ message = " ";
+ }
+
+ if (bonobo_ui_component_get_container (s->priv->ui_component)) /* should not do this here... */
+ {
+ bonobo_ui_component_set_status (s->priv->ui_component,
+ message,
+ NULL);
+ }
+}
+
diff --git a/src/statusbar.h b/src/statusbar.h
new file mode 100644
index 000000000..590b89394
--- /dev/null
+++ b/src/statusbar.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef STATUSBAR_H
+#define STATUSBAR_H
+
+#include "ephy-window.h"
+
+G_BEGIN_DECLS
+
+#include <glib-object.h>
+#include <glib.h>
+
+typedef struct Statusbar Statusbar;
+typedef struct StatusbarClass StatusbarClass;
+
+#define STATUSBAR_TYPE (statusbar_get_type ())
+#define STATUSBAR(obj) (GTK_CHECK_CAST ((obj), STATUSBAR_TYPE, Statusbar))
+#define STATUSBAR_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), STATUSBAR, StatusbarClass))
+#define IS_STATUSBAR(obj) (GTK_CHECK_TYPE ((obj), STATUSBAR_TYPE))
+#define IS_STATUSBAR_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), STATUSBAR))
+
+typedef struct StatusbarPrivate StatusbarPrivate;
+
+struct Statusbar
+{
+ GObject parent;
+ StatusbarPrivate *priv;
+};
+
+struct StatusbarClass
+{
+ GObjectClass parent_class;
+};
+
+GType statusbar_get_type (void);
+
+Statusbar *statusbar_new (EphyWindow *window);
+
+void statusbar_set_visibility (Statusbar *s,
+ gboolean visibility);
+
+void statusbar_set_security_state (Statusbar *s,
+ gboolean state,
+ const char *tooltip);
+
+void statusbar_set_progress (Statusbar *s,
+ int progress);
+
+void statusbar_set_message (Statusbar *s,
+ const gchar *message);
+
+G_END_DECLS
+
+#endif
diff --git a/src/toolbar.c b/src/toolbar.c
new file mode 100755
index 000000000..4bff4615e
--- /dev/null
+++ b/src/toolbar.c
@@ -0,0 +1,982 @@
+/*
+ * Copyright (C) 2000 Marco Pesenti Gritti
+ * (C) 2001, 2002 Jorn Baayen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+//#define DEBUG_MSG(x) g_print x
+#define DEBUG_MSG(x)
+#define NOT_IMPLEMENTED g_warning ("not implemented: " G_STRLOC);
+
+#include "toolbar.h"
+#include "ephy-spinner.h"
+#include "ephy-window.h"
+#include "ephy-bonobo-extensions.h"
+#include "ephy-string.h"
+#include "ephy-gui.h"
+#include "ephy-location-entry.h"
+#include "ephy-shell.h"
+#include "ephy-embed-favicon.h"
+#include "ephy-dnd.h"
+#include "ephy-toolbar-bonobo-view.h"
+#include "ephy-prefs.h"
+#include "eel-gconf-extensions.h"
+
+#include <string.h>
+#include <bonobo/bonobo-i18n.h>
+#include <bonobo/bonobo-window.h>
+#include <bonobo/bonobo-control.h>
+#include <bonobo/bonobo-ui-toolbar-button-item.h>
+#include <bonobo/bonobo-property-bag.h>
+#include <gtk/gtkentry.h>
+#include <gtk/gtkmenu.h>
+
+#define DEFAULT_TOOLBAR_SETUP \
+ "back=std_toolitem(item=back);" \
+ "back_history=navigation_history(direction=back);" \
+ "up=std_toolitem(item=up);" \
+ "up_history=navigation_history(direction=up);" \
+ "forward=std_toolitem(item=forward);" \
+ "forward_history=navigation_history(direction=forward);" \
+ "stop=std_toolitem(item=stop);" \
+ "reload=std_toolitem(item=reload);" \
+ "home=std_toolitem(item=home);" \
+ "favicon=favicon;" \
+ "location=location;" \
+ "zoom=zoom;" \
+ "spinner=spinner;"
+
+#define ZOOM_DELAY 50
+
+static void toolbar_class_init (ToolbarClass *klass);
+static void toolbar_init (Toolbar *t);
+static void toolbar_finalize (GObject *object);
+static void toolbar_set_window (Toolbar *t, EphyWindow *window);
+static void toolbar_get_widgets (Toolbar *t);
+static void toolbar_changed_cb (EphyToolbar *gt, Toolbar *t);
+static void
+toolbar_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void
+toolbar_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+
+enum
+{
+ PROP_0,
+ PROP_EPHY_WINDOW
+};
+
+enum
+{
+ TOOLBAR_ITEM_STYLE_PROP,
+ TOOLBAR_ITEM_ORIENTATION_PROP,
+ TOOLBAR_ITEM_PRIORITY_PROP
+};
+
+static GObjectClass *parent_class = NULL;
+
+struct ToolbarPrivate
+{
+ EphyWindow *window;
+ BonoboUIComponent *ui_component;
+ EphyTbBonoboView *bview;
+
+ GtkWidget *spinner;
+ gboolean visibility;
+ /* This field is unused... what is it?
+ GdkPixbufAnimation *animation;
+ */
+ GtkWidget *back_button;
+ GtkWidget *forward_button;
+ GtkWidget *up_button;
+ GtkWidget *location_entry;
+ GtkTooltips *tooltips;
+ GtkWidget *favicon;
+ GtkWidget *favicon_ebox;
+ GtkWidget *zoom_spinbutton;
+ guint zoom_timeout_id;
+ gboolean zoom_lock;
+};
+
+GType
+toolbar_get_type (void)
+{
+ static GType toolbar_type = 0;
+
+ if (toolbar_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (ToolbarClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) toolbar_class_init,
+ NULL,
+ NULL, /* class_data */
+ sizeof (Toolbar),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) toolbar_init
+ };
+
+ toolbar_type = g_type_register_static (EPHY_TYPE_TOOLBAR,
+ "Toolbar",
+ &our_info, 0);
+ }
+
+ return toolbar_type;
+
+}
+
+static void
+toolbar_class_init (ToolbarClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = toolbar_finalize;
+
+ object_class->set_property = toolbar_set_property;
+ object_class->get_property = toolbar_get_property;
+
+ g_object_class_install_property (object_class,
+ PROP_EPHY_WINDOW,
+ g_param_spec_object ("EphyWindow",
+ "EphyWindow",
+ "Parent window",
+ EPHY_WINDOW_TYPE,
+ G_PARAM_READWRITE));
+}
+
+static void
+toolbar_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ Toolbar *t = TOOLBAR (object);
+
+ switch (prop_id)
+ {
+ case PROP_EPHY_WINDOW:
+ toolbar_set_window (t, g_value_get_object (value));
+ break;
+ }
+}
+
+static void
+toolbar_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ Toolbar *t = TOOLBAR (object);
+
+ switch (prop_id)
+ {
+ case PROP_EPHY_WINDOW:
+ g_value_set_object (value, t->priv->window);
+ break;
+ }
+}
+
+static GtkWidget *
+new_history_menu_item (gint num, gchar *origtext, gboolean lettersok,
+ GtkWidget *menu, const GdkPixbuf *ico)
+{
+ GtkWidget *item = gtk_image_menu_item_new ();
+ GtkWidget *hb = gtk_hbox_new (FALSE, 0);
+ GtkWidget *label = gtk_label_new (origtext);
+
+ gtk_box_pack_start (GTK_BOX (hb), label, FALSE, FALSE, 0);
+ gtk_container_add (GTK_CONTAINER (item), hb);
+
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item),
+ gtk_image_new_from_pixbuf ((GdkPixbuf *) ico));
+
+ gtk_widget_show_all (item);
+
+ return item;
+}
+
+static void
+activate_back_or_forward_menu_item_cb (GtkWidget *menu, EphyWindow *window)
+{
+ EphyEmbed *embed;
+ int go_nth;
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+
+ go_nth = (int)g_object_get_data (G_OBJECT(menu), "go_nth");
+
+ ephy_embed_shistory_go_nth (embed, go_nth);
+}
+
+static void
+activate_up_menu_item_cb (GtkWidget *menu, EphyWindow *window)
+{
+ EphyEmbed *embed;
+ int go_nth;
+ GSList *l;
+ gchar *url;
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+
+ go_nth = (int)g_object_get_data (G_OBJECT(menu), "go_nth");
+
+ ephy_embed_get_go_up_list (embed, &l);
+
+ url = g_slist_nth_data (l, go_nth);
+ if (url)
+ {
+ ephy_embed_load_url (embed, url);
+ }
+
+ g_slist_foreach (l, (GFunc) g_free, NULL);
+ g_slist_free (l);
+}
+
+static gboolean
+back_or_forward_button_pressed_callback (GtkWidget *widget,
+ GdkEventButton *event,
+ gpointer *user_data)
+{
+ Toolbar *t;
+ GtkWidget *menu;
+ int pos, count;
+ EphyEmbed *embed;
+ int start, end, accell_count = 0;
+
+ g_return_val_if_fail (GTK_IS_BUTTON (widget), FALSE);
+
+ t = TOOLBAR (user_data);
+
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE);
+
+ embed = ephy_window_get_active_embed (t->priv->window);
+ g_return_val_if_fail (embed != NULL, FALSE);
+
+ ephy_embed_shistory_get_pos (embed, &pos);
+ ephy_embed_shistory_count (embed, &count);
+
+ if (count == 0) return FALSE;
+
+ if (widget == t->priv->back_button)
+ {
+ start = pos - 1;
+ end = -1;
+ }
+ else
+ {
+ start = pos + 1;
+ end = count;
+ }
+
+ menu = gtk_menu_new ();
+
+ while (start != end)
+ {
+ char *title, *url;
+ GtkWidget *item;
+ ephy_embed_shistory_get_nth (embed, start, FALSE,
+ &url, &title);
+ item = new_history_menu_item (accell_count, url, TRUE,
+ menu, NULL);
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+ g_object_set_data (G_OBJECT(item), "go_nth", GINT_TO_POINTER (start));
+ g_signal_connect (item, "activate",
+ G_CALLBACK (activate_back_or_forward_menu_item_cb),
+ t->priv->window);
+ gtk_widget_show_all (item);
+
+ g_free (url);
+ g_free (title);
+
+ accell_count++;
+ if (start < end) start++;
+ else start--;
+ }
+
+
+ gnome_popup_menu_do_popup_modal (menu,
+ ephy_gui_menu_position_under_widget, widget, event, widget, widget);
+
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), FALSE);
+
+ return TRUE;
+}
+
+static gboolean
+up_button_pressed_callback (GtkWidget *widget,
+ GdkEventButton *event,
+ gpointer *user_data)
+{
+ Toolbar *t;
+ GtkWidget *menu;
+ EphyEmbed *embed;
+ int accell_count = 0;
+ GSList *l;
+ GSList *li;
+
+ g_return_val_if_fail (GTK_IS_BUTTON (widget), FALSE);
+
+ t = TOOLBAR (user_data);
+
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE);
+
+ embed = ephy_window_get_active_embed (t->priv->window);
+ g_return_val_if_fail (embed != NULL, FALSE);
+
+ ephy_embed_get_go_up_list (embed, &l);
+
+ if (l == NULL) return FALSE;
+
+ menu = gtk_menu_new ();
+
+ for (li = l; li; li = li->next)
+ {
+ char *url = li->data;
+ GtkWidget *item;
+ item = new_history_menu_item (accell_count, url, TRUE,
+ menu, NULL);
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+ g_object_set_data (G_OBJECT(item), "go_nth", GINT_TO_POINTER (accell_count));
+ g_signal_connect (item, "activate",
+ G_CALLBACK (activate_up_menu_item_cb),
+ t->priv->window);
+ gtk_widget_show_all (item);
+
+ accell_count++;
+ }
+
+ g_slist_foreach (l, (GFunc) g_free, NULL);
+ g_slist_free (l);
+
+ gnome_popup_menu_do_popup_modal (menu,
+ ephy_gui_menu_position_under_widget, widget, event, widget, widget);
+
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), FALSE);
+
+ return TRUE;
+}
+
+static gboolean
+back_or_forward_key_pressed_callback (GtkWidget *widget,
+ GdkEventKey *event,
+ gpointer *user_data)
+{
+ if (event->keyval == GDK_space ||
+ event->keyval == GDK_KP_Space ||
+ event->keyval == GDK_Return ||
+ event->keyval == GDK_KP_Enter)
+ {
+ back_or_forward_button_pressed_callback (widget, NULL, user_data);
+ }
+
+ return FALSE;
+}
+
+static gboolean
+up_key_pressed_callback (GtkWidget *widget,
+ GdkEventKey *event,
+ gpointer *user_data)
+{
+ if (event->keyval == GDK_space ||
+ event->keyval == GDK_KP_Space ||
+ event->keyval == GDK_Return ||
+ event->keyval == GDK_KP_Enter)
+ {
+ up_button_pressed_callback (widget, NULL, user_data);
+ }
+
+ return FALSE;
+}
+
+static void
+toolbar_setup_navigation_button (Toolbar *t, GtkWidget *w, const char *tooltip)
+{
+ g_signal_connect_object (w, "key_press_event",
+ G_CALLBACK (back_or_forward_key_pressed_callback),
+ t, 0);
+ g_signal_connect_object (w, "button_press_event",
+ G_CALLBACK (back_or_forward_button_pressed_callback),
+ t, 0);
+
+ gtk_tooltips_set_tip (t->priv->tooltips, w, tooltip, NULL);
+}
+
+static void
+toolbar_setup_up_button (Toolbar *t, GtkWidget *w, const char *tooltip)
+{
+ g_signal_connect_object (w, "key_press_event",
+ G_CALLBACK (up_key_pressed_callback),
+ t, 0);
+ g_signal_connect_object (w, "button_press_event",
+ G_CALLBACK (up_button_pressed_callback),
+ t, 0);
+
+ gtk_tooltips_set_tip (t->priv->tooltips, w, tooltip, NULL);
+}
+
+
+static void
+toolbar_location_url_activate_cb (EphyLocationEntry *entry,
+ const char *content,
+ const char *target,
+ EphyWindow *window)
+{
+ EphyBookmarks *bookmarks;
+
+ bookmarks = ephy_shell_get_bookmarks (ephy_shell);
+
+ if (!content)
+ {
+ ephy_window_load_url (window, target);
+ }
+ else
+ {
+ char *url;
+
+ url = ephy_bookmarks_solve_smart_url
+ (bookmarks, target, content);
+ g_return_if_fail (url != NULL);
+ ephy_window_load_url (window, url);
+ g_free (url);
+ }
+}
+
+static void
+each_url_get_data_binder (EphyDragEachSelectedItemDataGet iteratee,
+ gpointer iterator_context, gpointer data)
+{
+ const char *location;
+ EphyTab *tab;
+ EphyWindow *window = EPHY_WINDOW(iterator_context);
+
+ tab = ephy_window_get_active_tab (window);
+ location = ephy_tab_get_location (tab);
+
+ iteratee (location, -1, -1, -1, -1, data);
+}
+
+static void
+favicon_drag_data_get_cb (GtkWidget *widget,
+ GdkDragContext *context,
+ GtkSelectionData *selection_data,
+ guint info,
+ guint32 time,
+ EphyWindow *window)
+{
+ g_assert (widget != NULL);
+ g_return_if_fail (context != NULL);
+
+ ephy_dnd_drag_data_get (widget, context, selection_data,
+ info, time, window, each_url_get_data_binder);
+}
+
+static void
+toolbar_setup_favicon_ebox (Toolbar *t, GtkWidget *w)
+{
+ ToolbarPrivate *p = t->priv;
+
+ g_return_if_fail (w == p->favicon_ebox);
+
+ p->favicon = g_object_ref (ephy_embed_favicon_new
+ (ephy_window_get_active_embed (p->window)));
+ gtk_container_add (GTK_CONTAINER (p->favicon_ebox), p->favicon);
+ gtk_container_set_border_width (GTK_CONTAINER (p->favicon_ebox), 2);
+
+ ephy_dnd_url_drag_source_set (p->favicon_ebox);
+
+ g_signal_connect (G_OBJECT (p->favicon_ebox),
+ "drag_data_get",
+ G_CALLBACK (favicon_drag_data_get_cb),
+ p->window);
+ gtk_widget_show_all (p->favicon_ebox);
+}
+
+static gboolean
+toolbar_zoom_timeout_cb (gpointer data)
+{
+ Toolbar *t = data;
+ gint zoom = toolbar_get_zoom (t);
+
+ g_return_val_if_fail (IS_EPHY_WINDOW (t->priv->window), FALSE);
+
+ ephy_window_set_zoom (t->priv->window, zoom);
+
+ return FALSE;
+}
+
+static void
+toolbar_zoom_spinbutton_value_changed_cb (GtkSpinButton *sb, Toolbar *t)
+{
+ ToolbarPrivate *p = t->priv;
+ if (p->zoom_timeout_id != 0)
+ {
+ g_source_remove (p->zoom_timeout_id);
+ }
+ if (!p->zoom_lock)
+ {
+ p->zoom_timeout_id = g_timeout_add (ZOOM_DELAY, toolbar_zoom_timeout_cb, t);
+ }
+}
+
+static void
+toolbar_setup_zoom_spinbutton (Toolbar *t, GtkWidget *w)
+{
+ g_signal_connect (w, "value_changed",
+ G_CALLBACK (toolbar_zoom_spinbutton_value_changed_cb), t);
+ gtk_tooltips_set_tip (t->priv->tooltips, w, _("Zoom"), NULL);
+}
+
+static void
+toolbar_setup_location_entry (Toolbar *t, GtkWidget *w)
+{
+ EphyAutocompletion *ac = ephy_shell_get_autocompletion (ephy_shell);
+ EphyLocationEntry *e;
+
+ g_return_if_fail (w == t->priv->location_entry);
+ g_return_if_fail (EPHY_IS_LOCATION_ENTRY (w));
+
+ e = EPHY_LOCATION_ENTRY (w);
+ ephy_location_entry_set_autocompletion (e, ac);
+
+ g_signal_connect (e, "activated",
+ GTK_SIGNAL_FUNC(toolbar_location_url_activate_cb),
+ t->priv->window);
+}
+
+static void
+toolbar_setup_spinner (Toolbar *t, GtkWidget *w)
+{
+ ToolbarPrivate *p = t->priv;
+ GtkWidget *spinner;
+
+ g_return_if_fail (w == p->spinner);
+
+ /* build the spinner and insert it into the box */
+ spinner = ephy_spinner_new ();
+ ephy_spinner_set_small_mode (EPHY_SPINNER (spinner), TRUE);
+ gtk_container_add (GTK_CONTAINER (p->spinner), spinner);
+ gtk_widget_show (spinner);
+
+ /* don't care about the box anymore */
+ g_object_unref (p->spinner);
+ p->spinner = g_object_ref (spinner);
+}
+
+
+static void
+toolbar_set_window (Toolbar *t, EphyWindow *window)
+{
+ g_return_if_fail (t->priv->window == NULL);
+
+ t->priv->window = window;
+ t->priv->ui_component = g_object_ref (t->priv->window->ui_component);
+
+ ephy_tb_bonobo_view_set_path (t->priv->bview, t->priv->ui_component, "/Toolbar");
+
+ toolbar_get_widgets (t);
+}
+
+static void
+toolbar_get_widgets (Toolbar *t)
+{
+ ToolbarPrivate *p;
+ EphyToolbar *gt;
+ EphyTbItem *it;
+
+ DEBUG_MSG (("in toolbar_get_widgets\n"));
+
+ g_return_if_fail (IS_TOOLBAR (t));
+ p = t->priv;
+ g_return_if_fail (IS_EPHY_WINDOW (p->window));
+ g_return_if_fail (BONOBO_IS_UI_COMPONENT (p->ui_component));
+
+ /* release all the widgets */
+
+ if (p->back_button)
+ {
+ g_object_unref (p->back_button);
+ p->back_button = NULL;
+ }
+
+ if (p->forward_button)
+ {
+ g_object_unref (p->forward_button);
+ p->forward_button = NULL;
+ }
+
+ if (p->up_button)
+ {
+ g_object_unref (p->up_button);
+ p->up_button = NULL;
+ }
+
+ if (p->favicon_ebox)
+ {
+ g_object_unref (p->favicon_ebox);
+ p->favicon_ebox = NULL;
+ }
+
+ if (p->favicon)
+ {
+ g_object_unref (p->favicon);
+ p->favicon = NULL;
+ }
+
+ if (p->location_entry)
+ {
+ g_object_unref (p->location_entry);
+ p->location_entry = NULL;
+ }
+
+ if (p->spinner)
+ {
+ g_object_unref (p->spinner);
+ p->spinner = NULL;
+ }
+
+ if (p->zoom_spinbutton)
+ {
+ g_object_unref (p->zoom_spinbutton);
+ p->zoom_spinbutton = NULL;
+ }
+
+ gt = EPHY_TOOLBAR (t);
+
+ it = ephy_toolbar_get_item_by_id (gt, "back_history");
+ if (it)
+ {
+ p->back_button = ephy_tb_item_get_widget (it);
+ g_object_ref (p->back_button);
+ toolbar_setup_navigation_button (t, p->back_button, _("Go back a number of pages"));
+
+ DEBUG_MSG ((" got a back_history button\n"));
+ }
+
+ it = ephy_toolbar_get_item_by_id (gt, "forward_history");
+ if (it)
+ {
+ p->forward_button = ephy_tb_item_get_widget (it);
+ g_object_ref (p->forward_button);
+ toolbar_setup_navigation_button (t, p->forward_button, _("Go forward a number of pages"));
+
+ DEBUG_MSG ((" got a forward_history button\n"));
+ }
+
+ it = ephy_toolbar_get_item_by_id (gt, "up_history");
+ if (it)
+ {
+ p->up_button = ephy_tb_item_get_widget (it);
+ g_object_ref (p->up_button);
+ toolbar_setup_up_button (t, p->up_button, _("Go up a number of levels"));
+
+ DEBUG_MSG ((" got a up_history button\n"));
+ }
+
+ it = ephy_toolbar_get_item_by_id (gt, "location");
+ if (it)
+ {
+ p->location_entry = ephy_tb_item_get_widget (it);
+ g_object_ref (p->location_entry);
+ toolbar_setup_location_entry (t, p->location_entry);
+
+ DEBUG_MSG ((" got a location entry\n"));
+ }
+
+ it = ephy_toolbar_get_item_by_id (gt, "favicon");
+ if (it)
+ {
+ p->favicon_ebox = ephy_tb_item_get_widget (it);
+ g_object_ref (p->favicon_ebox);
+ toolbar_setup_favicon_ebox (t, p->favicon_ebox);
+
+ DEBUG_MSG ((" got a favicon ebox\n"));
+ }
+
+ it = ephy_toolbar_get_item_by_id (gt, "spinner");
+ if (it)
+ {
+ p->spinner = ephy_tb_item_get_widget (it);
+ g_object_ref (p->spinner);
+ toolbar_setup_spinner (t, p->spinner);
+
+ DEBUG_MSG ((" got a spinner\n"));
+ }
+
+ it = ephy_toolbar_get_item_by_id (gt, "zoom");
+ if (it)
+ {
+ p->zoom_spinbutton = ephy_tb_item_get_widget (it);
+ g_object_ref (p->zoom_spinbutton);
+ toolbar_setup_zoom_spinbutton (t, p->zoom_spinbutton);
+
+ DEBUG_MSG ((" got a zoom control\n"));
+ }
+
+ /* update the controls */
+ ephy_window_update_all_controls (p->window);
+}
+
+static void
+toolbar_init (Toolbar *t)
+{
+ t->priv = g_new0 (ToolbarPrivate, 1);
+
+ t->priv->window = NULL;
+ t->priv->ui_component = NULL;
+ t->priv->visibility = TRUE;
+ t->priv->tooltips = gtk_tooltips_new ();
+ g_object_ref (t->priv->tooltips);
+ gtk_object_sink (GTK_OBJECT (t->priv->tooltips));
+
+ if (!ephy_toolbar_listen_to_gconf (EPHY_TOOLBAR (t), CONF_TOOLBAR_SETUP))
+ {
+ /* FIXME: make this a dialog? */
+ g_warning ("An incorrect toolbar configuration has been found, resetting to the default");
+
+ /* this is to make sure we get a toolbar, even if the
+ setup is wrong or there is no schema */
+ eel_gconf_set_string (CONF_TOOLBAR_SETUP, DEFAULT_TOOLBAR_SETUP);
+ }
+
+ g_signal_connect (t, "changed", G_CALLBACK (toolbar_changed_cb), t);
+
+ t->priv->bview = ephy_tb_bonobo_view_new ();
+ ephy_tb_bonobo_view_set_toolbar (t->priv->bview, EPHY_TOOLBAR (t));
+}
+
+static void
+toolbar_changed_cb (EphyToolbar *gt, Toolbar *t)
+{
+ g_return_if_fail (gt == EPHY_TOOLBAR (t));
+
+ if (t->priv->window)
+ {
+ toolbar_get_widgets (t);
+ }
+}
+
+static void
+toolbar_finalize (GObject *object)
+{
+ Toolbar *t;
+ ToolbarPrivate *p;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (IS_TOOLBAR (object));
+
+ t = TOOLBAR (object);
+ p = t->priv;
+
+ g_return_if_fail (p != NULL);
+
+ if (p->location_entry) g_object_unref (p->location_entry);
+ if (p->back_button) g_object_unref (p->back_button);
+ if (p->forward_button) g_object_unref (p->forward_button);
+ if (p->up_button) g_object_unref (p->up_button);
+ if (p->favicon_ebox) g_object_unref (p->favicon_ebox);
+ if (p->favicon) g_object_unref (p->favicon);
+ if (p->spinner) g_object_unref (p->spinner);
+ if (p->tooltips) g_object_unref (p->tooltips);
+ if (p->zoom_spinbutton) g_object_unref (p->zoom_spinbutton);
+ if (p->zoom_timeout_id != 0)
+ {
+ g_source_remove (p->zoom_timeout_id);
+ }
+
+ g_object_unref (t->priv->bview);
+
+ g_free (t->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+Toolbar *
+toolbar_new (EphyWindow *window)
+{
+ Toolbar *t;
+
+ t = TOOLBAR (g_object_new (TOOLBAR_TYPE,
+ "EphyWindow", window,
+ NULL));
+
+ g_return_val_if_fail (t->priv != NULL, NULL);
+
+ return t;
+}
+
+void
+toolbar_set_visibility (Toolbar *t, gboolean visibility)
+{
+ if (visibility == t->priv->visibility) return;
+
+ t->priv->visibility = visibility;
+
+ ephy_bonobo_set_hidden (BONOBO_UI_COMPONENT(t->priv->ui_component),
+ "/Toolbar",
+ !visibility);
+}
+
+void
+toolbar_activate_location (Toolbar *t)
+{
+ if (t->priv->location_entry)
+ {
+ ephy_location_entry_activate
+ (EPHY_LOCATION_ENTRY(t->priv->location_entry));
+ }
+}
+
+void
+toolbar_spinner_start (Toolbar *t)
+{
+ if (t->priv->spinner)
+ {
+ ephy_spinner_start (EPHY_SPINNER(t->priv->spinner));
+ }
+}
+
+void
+toolbar_spinner_stop (Toolbar *t)
+{
+ if (t->priv->spinner)
+ {
+ ephy_spinner_stop (EPHY_SPINNER(t->priv->spinner));
+ }
+}
+
+void
+toolbar_button_set_sensitive (Toolbar *t,
+ ToolbarButtonID id,
+ gboolean sensitivity)
+{
+ switch (id)
+ {
+ case TOOLBAR_BACK_BUTTON:
+ ephy_bonobo_set_sensitive (t->priv->ui_component,
+ "/commands/GoBack",
+ sensitivity);
+ if (t->priv->back_button)
+ {
+ gtk_widget_set_sensitive (t->priv->back_button,
+ sensitivity);
+ }
+ break;
+ case TOOLBAR_FORWARD_BUTTON:
+ ephy_bonobo_set_sensitive (t->priv->ui_component,
+ "/commands/GoForward",
+ sensitivity);
+ if (t->priv->forward_button)
+ {
+ gtk_widget_set_sensitive (t->priv->forward_button,
+ sensitivity);
+ }
+ break;
+ case TOOLBAR_STOP_BUTTON:
+ ephy_bonobo_set_sensitive (t->priv->ui_component,
+ "/commands/GoStop",
+ sensitivity);
+ break;
+ case TOOLBAR_UP_BUTTON:
+ ephy_bonobo_set_sensitive (t->priv->ui_component,
+ "/commands/GoUp",
+ sensitivity);
+ if (t->priv->up_button)
+ {
+ gtk_widget_set_sensitive (t->priv->up_button,
+ sensitivity);
+ }
+ break;
+ }
+}
+
+void
+toolbar_set_location (Toolbar *t,
+ const char *location)
+{
+ g_return_if_fail (location != NULL);
+
+ if (t->priv->location_entry)
+ {
+ ephy_location_entry_set_location
+ (EPHY_LOCATION_ENTRY (t->priv->location_entry), location);
+ }
+}
+
+void
+toolbar_update_favicon (Toolbar *t)
+{
+ if (t->priv->favicon)
+ {
+ ephy_embed_favicon_set_embed (EPHY_EMBED_FAVICON (t->priv->favicon),
+ ephy_window_get_active_embed (t->priv->window));
+ }
+}
+
+char *
+toolbar_get_location (Toolbar *t)
+{
+ gchar *location;
+ if (t->priv->location_entry)
+ {
+ location = ephy_location_entry_get_location
+ (EPHY_LOCATION_ENTRY (t->priv->location_entry));
+ }
+ else
+ {
+ location = g_strdup ("");
+ }
+ return location;
+}
+
+gint
+toolbar_get_zoom (Toolbar *t)
+{
+ gint zoom;
+ if (t->priv->zoom_spinbutton)
+ {
+ zoom = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (t->priv->zoom_spinbutton));
+ }
+ else
+ {
+ zoom = 100;
+ }
+ return zoom;
+}
+
+void
+toolbar_set_zoom (Toolbar *t, gint zoom)
+{
+ ToolbarPrivate *p = t->priv;
+ if (p->zoom_spinbutton)
+ {
+ p->zoom_lock = TRUE;
+ gtk_spin_button_set_value (GTK_SPIN_BUTTON (p->zoom_spinbutton), zoom);
+ p->zoom_lock = FALSE;
+ }
+}
+
diff --git a/src/toolbar.h b/src/toolbar.h
new file mode 100644
index 000000000..5764c14e1
--- /dev/null
+++ b/src/toolbar.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef TOOLBAR_H
+#define TOOLBAR_H
+
+#include "ephy-window.h"
+#include <glib-object.h>
+#include <glib.h>
+#include "ephy-toolbar.h"
+
+G_BEGIN_DECLS
+
+typedef struct ToolbarClass ToolbarClass;
+
+#define TOOLBAR_TYPE (toolbar_get_type ())
+#define TOOLBAR(obj) (GTK_CHECK_CAST ((obj), TOOLBAR_TYPE, Toolbar))
+#define TOOLBAR_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), TOOLBAR, ToolbarClass))
+#define IS_TOOLBAR(obj) (GTK_CHECK_TYPE ((obj), TOOLBAR_TYPE))
+#define IS_TOOLBAR_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), TOOLBAR))
+
+typedef struct ToolbarPrivate ToolbarPrivate;
+
+typedef enum
+{
+ TOOLBAR_BACK_BUTTON,
+ TOOLBAR_FORWARD_BUTTON,
+ TOOLBAR_STOP_BUTTON,
+ TOOLBAR_UP_BUTTON
+} ToolbarButtonID;
+
+struct Toolbar
+{
+ EphyToolbar parent_object;
+ ToolbarPrivate *priv;
+};
+
+struct ToolbarClass
+{
+ EphyToolbarClass parent_class;
+};
+
+GType toolbar_get_type (void);
+
+Toolbar *toolbar_new (EphyWindow *window);
+
+void toolbar_set_visibility (Toolbar *t,
+ gboolean visibility);
+
+void toolbar_button_set_sensitive (Toolbar *t,
+ ToolbarButtonID id,
+ gboolean sensitivity);
+
+void toolbar_spinner_start (Toolbar *t);
+
+void toolbar_spinner_stop (Toolbar *t);
+
+char *toolbar_get_location (Toolbar *t);
+
+void toolbar_set_location (Toolbar *t,
+ const char *location);
+
+gint toolbar_get_zoom (Toolbar *t);
+
+void toolbar_set_zoom (Toolbar *t, gint zoom);
+
+void toolbar_activate_location (Toolbar *t);
+
+void toolbar_update_favicon (Toolbar *t);
+
+G_END_DECLS
+
+#endif
diff --git a/src/ui-prefs.c b/src/ui-prefs.c
new file mode 100755
index 000000000..e461bf7e6
--- /dev/null
+++ b/src/ui-prefs.c
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "ui-prefs.h"
+#include "ephy-shell.h"
+#include "ephy-prefs.h"
+#include "eel-gconf-extensions.h"
+#include "ephy-spinner.h"
+
+#include <string.h>
+#include <libgnome/gnome-util.h>
+#include <libgnomeui/gnome-icon-list.h>
+
+static void ui_prefs_class_init (UIPrefsClass *klass);
+static void ui_prefs_init (UIPrefs *dialog);
+static void ui_prefs_finalize (GObject *object);
+
+/* Glade callbacks */
+void
+spinners_iconlist_select_icon_cb (GtkWidget *iconlist, gint num,
+ GdkEvent *event, UIPrefs *dialog);
+
+static GObjectClass *parent_class = NULL;
+
+struct UIPrefsPrivate
+{
+ gpointer dummy;
+ GList *spinner_list;
+};
+
+enum
+{
+ SPINNERS_PROP,
+ OPEN_IN_TABS_PROP,
+ JUMP_TO_PROP,
+ POPUPS_PROP
+};
+
+static const
+EphyDialogProperty properties [] =
+{
+ { SPINNERS_PROP, "spinners_iconlist", NULL, PT_NORMAL, NULL },
+ { OPEN_IN_TABS_PROP, "open_in_tabs_checkbutton", CONF_TABS_TABBED, PT_AUTOAPPLY, NULL },
+ { JUMP_TO_PROP, "jump_to_checkbutton", CONF_TABS_TABBED_AUTOJUMP, PT_AUTOAPPLY, NULL },
+ { POPUPS_PROP, "popups_checkbutton", CONF_TABS_TABBED_POPUPS, PT_AUTOAPPLY, NULL },
+
+ { -1, NULL, NULL }
+};
+
+GType
+ui_prefs_get_type (void)
+{
+ static GType ui_prefs_type = 0;
+
+ if (ui_prefs_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (UIPrefsClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) ui_prefs_class_init,
+ NULL,
+ NULL, /* class_data */
+ sizeof (UIPrefs),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) ui_prefs_init
+ };
+
+ ui_prefs_type = g_type_register_static (EPHY_DIALOG_TYPE,
+ "UIPrefs",
+ &our_info, 0);
+ }
+
+ return ui_prefs_type;
+
+}
+
+static void
+ui_prefs_class_init (UIPrefsClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = ui_prefs_finalize;
+}
+
+/**
+ * Free any existing spinner list.
+ */
+static void
+free_spinner_list (UIPrefs *dialog)
+{
+ GList *node;
+
+ for (node = dialog->priv->spinner_list; node; node = node->next)
+ g_free(node->data);
+
+ g_list_free(dialog->priv->spinner_list);
+ dialog->priv->spinner_list = NULL;
+}
+
+/**
+ * spinner_get_path_from_index: used in prefs_callbacks.c to get the
+ * path of selected icon
+ */
+static const gchar *
+spinner_get_path_from_index (UIPrefs *dialog, gint index)
+{
+ gchar *path;
+
+ path = g_list_nth_data (dialog->priv->spinner_list, index);
+
+ return path;
+}
+
+/*
+ * spinner_fill_iconlist: fill a gnome icon list with icons of available spinners
+ */
+static void
+spinner_fill_iconlist (UIPrefs *dialog, GnomeIconList *icon_list)
+{
+ GList *spinners, *tmp;
+ gchar *pref_spinner_path;
+ gint index;
+
+ /* clear spinner list */
+ free_spinner_list (dialog);
+ gnome_icon_list_clear (GNOME_ICON_LIST (icon_list));
+
+ pref_spinner_path =
+ eel_gconf_get_string (CONF_TOOLBAR_SPINNER_THEME);
+ index = gnome_icon_list_get_num_icons (icon_list);
+
+ spinners = ephy_spinner_list_spinners ();
+ for (tmp = spinners; tmp != NULL; tmp = g_list_next (tmp))
+ {
+ EphySpinnerInfo *info = tmp->data;
+
+ dialog->priv->spinner_list =
+ g_list_append (dialog->priv->spinner_list,
+ g_strdup (info->name));
+
+ gnome_icon_list_append (icon_list, info->filename, info->name);
+
+ /* Select the icon configured in prefs */
+ if (pref_spinner_path &&
+ strcmp (pref_spinner_path, info->name) == 0)
+ {
+ gnome_icon_list_select_icon (icon_list, index);
+ }
+ index++;
+ }
+ g_list_foreach (spinners, (GFunc)ephy_spinner_info_free, NULL);
+ g_list_free (spinners);
+
+ g_free (pref_spinner_path);
+}
+
+static void
+ui_prefs_init (UIPrefs *dialog)
+{
+ GtkWidget *icon_list;
+
+ dialog->priv = g_new0 (UIPrefsPrivate, 1);
+ dialog->priv->spinner_list = NULL;
+
+ ephy_dialog_construct (EPHY_DIALOG(dialog),
+ properties,
+ "prefs-dialog.glade",
+ "ui_page_box");
+
+ icon_list = ephy_dialog_get_control (EPHY_DIALOG(dialog),
+ SPINNERS_PROP);
+
+ spinner_fill_iconlist (dialog, GNOME_ICON_LIST (icon_list));
+}
+
+static void
+ui_prefs_finalize (GObject *object)
+{
+ UIPrefs *dialog;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (IS_UI_PREFS (object));
+
+ dialog = UI_PREFS (object);
+
+ g_return_if_fail (dialog->priv != NULL);
+
+ free_spinner_list (dialog);
+
+ g_free (dialog->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+EphyDialog *
+ui_prefs_new (void)
+{
+ UIPrefs *dialog;
+
+ dialog = UI_PREFS (g_object_new (UI_PREFS_TYPE,
+ NULL));
+
+ return EPHY_DIALOG(dialog);
+}
+
+void
+spinners_iconlist_select_icon_cb (GtkWidget *iconlist, gint num,
+ GdkEvent *event, UIPrefs *dialog)
+{
+ const char *path;
+ path = spinner_get_path_from_index (dialog, num);
+ eel_gconf_set_string (CONF_TOOLBAR_SPINNER_THEME, path);
+}
diff --git a/src/ui-prefs.h b/src/ui-prefs.h
new file mode 100644
index 000000000..bbd3dbe75
--- /dev/null
+++ b/src/ui-prefs.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2002 Jorn Baayen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef UI_PREFS_H
+#define UI_PREFS_H
+
+#include "ephy-dialog.h"
+
+#include <glib-object.h>
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef struct UIPrefs UIPrefs;
+typedef struct UIPrefsClass UIPrefsClass;
+
+#define UI_PREFS_TYPE (ui_prefs_get_type ())
+#define UI_PREFS(obj) (GTK_CHECK_CAST ((obj), UI_PREFS_TYPE, UIPrefs))
+#define UI_PREFS_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), UI_PREFS, UIPrefsClass))
+#define IS_UI_PREFS(obj) (GTK_CHECK_TYPE ((obj), UI_PREFS_TYPE))
+#define IS_UI_PREFS_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), UI_PREFS))
+
+typedef struct UIPrefsPrivate UIPrefsPrivate;
+
+struct UIPrefs
+{
+ EphyDialog parent;
+ UIPrefsPrivate *priv;
+};
+
+struct UIPrefsClass
+{
+ EphyDialogClass parent_class;
+};
+
+GType ui_prefs_get_type (void);
+
+EphyDialog *ui_prefs_new (void);
+
+G_END_DECLS
+
+#endif
+
diff --git a/src/window-commands.c b/src/window-commands.c
new file mode 100644
index 000000000..cef1d675c
--- /dev/null
+++ b/src/window-commands.c
@@ -0,0 +1,917 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+
+#include "ephy-shell.h"
+#include "window-commands.h"
+#include "find-dialog.h"
+#include "print-dialog.h"
+#include "eel-gconf-extensions.h"
+#include "ephy-prefs.h"
+#include "ephy-embed-utils.h"
+#include "pdm-dialog.h"
+#include "toolbar.h"
+#include "ephy-toolbar-editor.h"
+#include "ephy-bookmarks-editor.h"
+#include "ephy-new-bookmark.h"
+
+#include <string.h>
+#include <libgnomevfs/gnome-vfs-uri.h>
+#include <libgnomevfs/gnome-vfs-utils.h>
+#include <bonobo/bonobo-i18n.h>
+#include <libgnomeui/gnome-about.h>
+#include <libgnome/gnome-help.h>
+#include <gtk/gtkmessagedialog.h>
+#include <gtk/gtkeditable.h>
+
+#define AVAILABLE_TOOLBAR_ITEMS \
+ "new=std_toolitem(item=new);" \
+ "back=std_toolitem(item=back);" \
+ "back_history=navigation_history(direction=back);" \
+ "up=std_toolitem(item=up);" \
+ "up_history=navigation_history(direction=up);" \
+ "forward=std_toolitem(item=forward);" \
+ "forward_history=navigation_history(direction=forward);" \
+ "stop=std_toolitem(item=stop);" \
+ "reload=std_toolitem(item=reload);" \
+ "home=std_toolitem(item=home);" \
+ "favicon=favicon;" \
+ "location=location;" \
+ "go=std_toolitem(item=go);" \
+ "zoom=zoom;" \
+ "spinner=spinner;" \
+ "separator;"
+
+
+
+void
+window_cmd_edit_find (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ EphyDialog *dialog;
+ dialog = ephy_window_get_find_dialog (window);
+
+ g_object_ref (dialog);
+
+ ephy_dialog_show (dialog);
+}
+
+static void
+print_dialog_preview_cb (PrintDialog *dialog,
+ EphyWindow *window)
+{
+ ephy_window_set_chrome (window, EMBED_CHROME_PPVIEWTOOLBARON);
+}
+
+void
+window_cmd_file_print (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ EphyDialog *dialog;
+ EphyEmbed *embed;
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+
+ dialog = print_dialog_new_with_parent (GTK_WIDGET(window),
+ embed, NULL);
+ g_signal_connect (G_OBJECT(dialog),
+ "preview",
+ G_CALLBACK (print_dialog_preview_cb),
+ window);
+ ephy_dialog_set_modal (dialog, TRUE);
+ ephy_dialog_show (dialog);
+}
+
+void
+window_cmd_go_back (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ EphyEmbed *embed;
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+
+ ephy_embed_go_back (embed);
+}
+
+void
+window_cmd_go_up (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ EphyEmbed *embed;
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+
+ ephy_embed_go_up (embed);
+}
+
+void
+window_cmd_file_send_to (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ char *url;
+ EphyTab *tab;
+ EphyEmbed *embed;
+ char *location;
+ char *title;
+
+ tab = ephy_window_get_active_tab (window);
+ g_return_if_fail (tab);
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (tab);
+
+ location = gnome_vfs_escape_string (ephy_tab_get_location (tab));
+ if (ephy_embed_get_title (embed, &title) == G_OK)
+ {
+ char *tmp = gnome_vfs_escape_string (title);
+ g_free (title);
+ title = tmp;
+ }
+ else
+ {
+ title = gnome_vfs_escape_string (_("Check this out!"));
+ }
+
+ url = g_strconcat ("mailto:",
+ "?Subject=", title,
+ "&Body=", location, NULL);
+
+ ephy_embed_load_url (embed, url);
+
+ g_free (title);
+ g_free (location);
+ g_free (url);
+}
+
+void
+window_cmd_go_forward (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ EphyEmbed *embed;
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+
+ ephy_embed_go_forward (embed);
+}
+
+void
+window_cmd_go_go (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ Toolbar *tb;
+
+ g_return_if_fail (IS_EPHY_WINDOW (window));
+
+ tb = ephy_window_get_toolbar (window);
+
+ if (tb)
+ {
+ char *location = toolbar_get_location (tb);
+ ephy_window_load_url (window, location);
+ g_free (location);
+ }
+}
+
+void
+window_cmd_go_home (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ EphyEmbed *embed;
+ char *location;
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+
+ location = eel_gconf_get_string (CONF_GENERAL_HOMEPAGE);
+ g_return_if_fail (location != NULL);
+
+ ephy_embed_load_url (embed, location);
+
+ g_free (location);
+}
+
+void
+window_cmd_go_myportal (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ EphyEmbed *embed;
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+
+ ephy_embed_load_url (embed, "myportal:");
+}
+
+void
+window_cmd_go_location (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ ephy_window_activate_location (window);
+}
+
+void
+window_cmd_go_stop (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ EphyEmbed *embed;
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+
+ ephy_embed_stop_load (embed);
+}
+
+void
+window_cmd_go_reload (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ EphyEmbed *embed;
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+
+ ephy_embed_reload (embed, EMBED_RELOAD_NORMAL);
+}
+
+void
+window_cmd_new (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ EphyTab *tab;
+
+ tab = ephy_window_get_active_tab (window);
+
+ ephy_shell_new_tab (ephy_shell, window, tab, NULL,
+ EPHY_NEW_TAB_HOMEPAGE |
+ EPHY_NEW_TAB_JUMP);
+}
+
+void
+window_cmd_new_window (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ EphyTab *tab;
+
+ tab = ephy_window_get_active_tab (window);
+
+ ephy_shell_new_tab (ephy_shell, NULL, tab, NULL,
+ EPHY_NEW_TAB_HOMEPAGE |
+ EPHY_NEW_TAB_IN_NEW_WINDOW |
+ EPHY_NEW_TAB_JUMP);
+}
+
+void
+window_cmd_new_tab (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ EphyTab *tab;
+
+ tab = ephy_window_get_active_tab (window);
+
+ ephy_shell_new_tab (ephy_shell, window, tab, NULL,
+ EPHY_NEW_TAB_HOMEPAGE |
+ EPHY_NEW_TAB_IN_EXISTING_WINDOW |
+ EPHY_NEW_TAB_JUMP);
+}
+
+void
+window_cmd_bookmarks_edit (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ GtkWidget *dialog;
+ EphyBookmarks *bookmarks;
+
+ bookmarks = ephy_shell_get_bookmarks (ephy_shell);
+ g_assert (bookmarks != NULL);
+ dialog = ephy_bookmarks_editor_new (bookmarks, GTK_WINDOW (window));
+ gtk_widget_show (dialog);
+}
+
+void
+window_cmd_bookmarks_add_default (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ EphyTab *tab;
+ EphyEmbed *embed;
+ EphyBookmarks *bookmarks;
+ GtkWidget *new_bookmark;
+ const char *location;
+ char *title;
+
+ tab = ephy_window_get_active_tab (window);
+ g_return_if_fail (tab);
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (tab);
+
+ location = ephy_tab_get_location (tab);
+ if (ephy_embed_get_title (embed, &title) != G_OK)
+ {
+ title = _("Untitled");
+ }
+
+ bookmarks = ephy_shell_get_bookmarks (ephy_shell);
+ new_bookmark = ephy_new_bookmark_new
+ (bookmarks, GTK_WINDOW (window), location);
+ ephy_new_bookmark_set_title
+ (EPHY_NEW_BOOKMARK (new_bookmark), title);
+ gtk_widget_show (new_bookmark);
+}
+
+void
+window_cmd_file_open (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ gchar *dir, *retDir;
+ gchar *file = NULL;
+ GnomeVFSURI *uri;
+ GtkWidget *wmain;
+ EphyEmbedShell *embed_shell;
+ gresult result;
+
+ embed_shell = ephy_shell_get_embed_shell (ephy_shell);
+ g_return_if_fail (embed_shell != NULL);
+
+ wmain = GTK_WIDGET (window);
+ g_return_if_fail (wmain != NULL);
+
+ dir = eel_gconf_get_string (CONF_STATE_OPEN_DIR);
+
+ result = ephy_embed_shell_show_file_picker
+ (embed_shell, wmain,
+ _("Select the file to open"),
+ dir, NULL, modeOpen,
+ &file, NULL, NULL, NULL);
+
+ if (result == G_OK)
+ {
+ uri = gnome_vfs_uri_new (file);
+ if (uri)
+ {
+
+ ephy_window_load_url(window, file);
+
+ retDir = gnome_vfs_uri_extract_dirname (uri);
+
+ /* set default open dir */
+ eel_gconf_set_string (CONF_STATE_OPEN_DIR,
+ retDir);
+
+ g_free (retDir);
+ gnome_vfs_uri_unref (uri);
+ }
+ }
+
+ g_free (dir);
+ g_free (file);
+}
+
+void
+window_cmd_file_save_as (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ EphyEmbed *embed;
+ EphyEmbedPersist *persist;
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+
+ persist = ephy_embed_persist_new (embed);
+ ephy_embed_persist_set_flags (persist,
+ EMBED_PERSIST_MAINDOC);
+
+ ephy_embed_utils_save (GTK_WIDGET(window),
+ CONF_STATE_SAVE_DIR,
+ TRUE,
+ TRUE,
+ persist);
+
+ g_object_unref (G_OBJECT(persist));
+}
+
+void
+window_cmd_file_close_tab (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ EphyTab *tab;
+
+ tab = ephy_window_get_active_tab (window);
+ g_return_if_fail (tab != NULL);
+
+ ephy_window_remove_tab (window, tab);
+}
+
+void
+window_cmd_file_close_window (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ gtk_widget_destroy (GTK_WIDGET(window));
+}
+
+void
+window_cmd_edit_cut (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ GtkWidget *widget = gtk_window_get_focus (GTK_WINDOW (window));
+
+ if (GTK_IS_EDITABLE (widget))
+ {
+ gtk_editable_cut_clipboard (GTK_EDITABLE (widget));
+ }
+ else
+ {
+ EphyEmbed *embed;
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+
+ ephy_embed_selection_cut (embed);
+ }
+}
+
+void
+window_cmd_edit_copy (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ GtkWidget *widget = gtk_window_get_focus (GTK_WINDOW (window));
+
+ if (GTK_IS_EDITABLE (widget))
+ {
+ gtk_editable_copy_clipboard (GTK_EDITABLE (widget));
+ }
+ else
+ {
+ EphyEmbed *embed;
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+
+ ephy_embed_selection_copy (embed);
+ }
+}
+
+void
+window_cmd_edit_paste (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ GtkWidget *widget = gtk_window_get_focus (GTK_WINDOW (window));
+
+ if (GTK_IS_EDITABLE (widget))
+ {
+ gtk_editable_paste_clipboard (GTK_EDITABLE (widget));
+ }
+ else
+ {
+ EphyEmbed *embed;
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+
+ ephy_embed_paste (embed);
+ }
+}
+
+void
+window_cmd_edit_select_all (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ GtkWidget *widget = gtk_window_get_focus (GTK_WINDOW (window));
+
+ if (GTK_IS_EDITABLE (widget))
+ {
+ gtk_editable_select_region (GTK_EDITABLE (widget), 0, -1);
+ }
+ else
+ {
+ EphyEmbed *embed;
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+
+ ephy_embed_select_all (embed);
+ }
+}
+
+void
+window_cmd_edit_find_next (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ EphyDialog *dialog;
+
+ dialog = ephy_window_get_find_dialog (window);
+
+ find_dialog_go_next (FIND_DIALOG(dialog), FALSE);
+
+ ephy_window_update_control (window, FindControl);
+}
+
+void
+window_cmd_edit_find_prev (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ EphyDialog *dialog;
+
+ dialog = ephy_window_get_find_dialog (window);
+
+ find_dialog_go_prev (FIND_DIALOG(dialog), FALSE);
+
+ ephy_window_update_control (window, FindControl);
+}
+
+void
+window_cmd_view_zoom_in (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char *verbname)
+{
+ EphyEmbed *embed;
+ int zoom;
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+
+ ephy_embed_zoom_get (embed, &zoom);
+ ephy_window_set_zoom (window, zoom + 10);
+}
+
+void
+window_cmd_view_zoom_out (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ EphyEmbed *embed;
+ int zoom;
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+
+ ephy_embed_zoom_get (embed, &zoom);
+ if (zoom >= 10)
+ {
+ ephy_window_set_zoom (window, zoom - 10);
+ }
+}
+
+void
+window_cmd_view_zoom_normal (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ ephy_window_set_zoom (window, 100);
+}
+
+void
+window_cmd_view_page_source (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ EphyTab *tab;
+
+ tab = ephy_window_get_active_tab (window);
+ g_return_if_fail (tab != NULL);
+
+ ephy_shell_new_tab (ephy_shell, window, tab, NULL,
+ EPHY_NEW_TAB_VIEW_SOURCE);
+}
+
+void
+window_cmd_tools_history (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ ephy_window_show_history (window);
+}
+
+void
+window_cmd_tools_pdm (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ EphyDialog *dialog;
+
+ dialog = pdm_dialog_new (GTK_WIDGET(window));
+
+ ephy_dialog_show (dialog);
+}
+
+void
+window_cmd_edit_prefs (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ GtkDialog *dialog;
+
+ dialog = prefs_dialog_new ();
+ prefs_dialog_show_page (PREFS_DIALOG(dialog),
+ PREFS_PAGE_GENERAL);
+ gtk_window_set_transient_for (GTK_WINDOW (dialog),
+ GTK_WINDOW (window));
+ gtk_widget_show (GTK_WIDGET(dialog));
+}
+
+static void
+window_cmd_settings_toolbar_editor_revert_clicked_cb (GtkButton *b, EphyTbEditor *tbe)
+{
+ gchar *def;
+
+ g_return_if_fail (EPHY_IS_TB_EDITOR (tbe));
+
+ eel_gconf_unset (CONF_TOOLBAR_SETUP);
+ def = eel_gconf_get_string (CONF_TOOLBAR_SETUP);
+ if (def)
+ {
+ EphyToolbar *current;
+ EphyToolbar *avail;
+ current = ephy_tb_editor_get_toolbar (tbe);
+ ephy_toolbar_parse (current, def);
+ g_free (def);
+
+ avail = ephy_tb_editor_get_available (tbe);
+ g_object_ref (avail);
+ ephy_toolbar_parse (avail, AVAILABLE_TOOLBAR_ITEMS);
+ ephy_tb_editor_set_available (tbe, avail);
+ g_object_unref (avail);
+ }
+
+}
+
+static void
+window_cmd_settings_toolbar_editor_current_changed_cb (EphyToolbar *tb, gpointer data)
+{
+ gchar *current_str;
+
+ g_return_if_fail (EPHY_IS_TOOLBAR (tb));
+
+ current_str = ephy_toolbar_to_string (tb);
+ eel_gconf_set_string (CONF_TOOLBAR_SETUP, current_str);
+ g_free (current_str);
+}
+
+void
+window_cmd_settings_toolbar_editor (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ static EphyTbEditor *tbe = NULL;
+ EphyToolbar *avail;
+ EphyToolbar *current;
+ gchar *current_str;
+ GtkButton *revert_button;
+
+ avail = ephy_toolbar_new ();
+ ephy_toolbar_parse (avail, AVAILABLE_TOOLBAR_ITEMS);
+
+ current_str = eel_gconf_get_string (CONF_TOOLBAR_SETUP);
+ current = ephy_toolbar_new ();
+ if (current_str)
+ {
+ ephy_toolbar_parse (current, current_str);
+ g_free (current_str);
+ }
+
+ if (!tbe)
+ {
+ tbe = ephy_tb_editor_new ();
+ g_object_add_weak_pointer (G_OBJECT (tbe),
+ (void **)&tbe);
+ ephy_tb_editor_set_parent (tbe,
+ GTK_WIDGET(window));
+ }
+ else
+ {
+ ephy_tb_editor_show (tbe);
+ return;
+ }
+
+ ephy_tb_editor_set_toolbar (tbe, current);
+ ephy_tb_editor_set_available (tbe, avail);
+ g_object_unref (avail);
+ g_object_unref (current);
+
+ g_signal_connect (current, "changed",
+ G_CALLBACK (window_cmd_settings_toolbar_editor_current_changed_cb), NULL);
+
+ revert_button = ephy_tb_editor_get_revert_button (tbe);
+ gtk_widget_show (GTK_WIDGET (revert_button));
+
+ g_signal_connect (revert_button, "clicked",
+ G_CALLBACK (window_cmd_settings_toolbar_editor_revert_clicked_cb), tbe);
+
+ ephy_tb_editor_show (tbe);
+}
+
+void
+window_cmd_help_about (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ static GtkWidget *about = NULL;
+
+ static gchar *authors[] = {
+ "Marco Pesenti Gritti <mpeseng@tin.it>",
+ NULL
+ };
+
+ gchar *documenters[] = {
+ NULL
+ };
+
+ /* Translator credits */
+ gchar *translator_credits = _("translator_credits");
+
+ if (about != NULL)
+ {
+ gdk_window_show(about->window);
+ gdk_window_raise(about->window);
+ return;
+ }
+
+ about = gnome_about_new(
+ _("Epiphany"), VERSION,
+ /* Translators: Please change the (C) to a real
+ * copyright character if your character set allows it
+ * (Hint: iso-8859-1 is one of the character sets that
+ * has this symbol). */
+ _("Copyright (C) 2002 Marco Pesenti Gritti"),
+ _("A GNOME browser based on Mozilla"),
+ (const char **)authors,
+ (const char **)documenters,
+ strcmp (translator_credits, "translator_credits") != 0 ? translator_credits : NULL,
+ NULL);
+
+ gtk_window_set_transient_for (GTK_WINDOW (about),
+ GTK_WINDOW (window));
+ g_object_add_weak_pointer (G_OBJECT (about), (gpointer *)&about);
+ gtk_widget_show (about);
+}
+
+void
+window_cmd_set_charset (BonoboUIComponent *uic,
+ EncodingMenuData *data,
+ const char* verbname)
+{
+ EphyWindow *window = data->data;
+ EphyEmbed *embed;
+
+ embed = ephy_window_get_active_embed (window);
+ g_return_if_fail (embed != NULL);
+
+ g_print (data->encoding);
+ ephy_embed_set_charset (embed, data->encoding);
+}
+
+void
+window_cmd_tabs_next (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ GList *tabs;
+ EphyTab *tab;
+
+ tab = ephy_window_get_active_tab (window);
+ tabs = ephy_window_get_tabs (window);
+ g_return_if_fail (tab != NULL);
+
+ tabs = g_list_find (tabs, (gpointer)tab);
+ tabs = tabs->next;
+
+ if (tabs)
+ {
+ tab = EPHY_TAB (tabs->data);
+ ephy_window_jump_to_tab (window, tab);
+ g_list_free (tabs);
+ }
+}
+
+void
+window_cmd_tabs_previous (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ GList *tabs;
+ EphyTab *tab;
+
+ tab = ephy_window_get_active_tab (window);
+ tabs = ephy_window_get_tabs (window);
+ g_return_if_fail (tab != NULL);
+
+ tabs = g_list_find (tabs, (gpointer)tab);
+ tabs = tabs->prev;
+
+ if (tabs)
+ {
+ tab = EPHY_TAB (tabs->data);
+ ephy_window_jump_to_tab (window, tab);
+ g_list_free (tabs);
+ }
+}
+
+void
+window_cmd_tabs_move_left (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+}
+
+void window_cmd_tabs_move_right (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+}
+
+void
+window_cmd_tabs_detach (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname)
+{
+ EphyTab *tab;
+ GtkWidget *src_page;
+ EphyWindow *new_win;
+
+ if (g_list_length (ephy_window_get_tabs (window)) <= 1) {
+ return;
+ }
+
+ tab = ephy_window_get_active_tab (window);
+ src_page = GTK_WIDGET (ephy_tab_get_embed (tab));
+ new_win = ephy_window_new ();
+ ephy_notebook_move_page (EPHY_NOTEBOOK (ephy_window_get_notebook (window)),
+ EPHY_NOTEBOOK (ephy_window_get_notebook (new_win)),
+ src_page, 0);
+ ephy_tab_set_window (tab, new_win);
+ gtk_widget_show (GTK_WIDGET (new_win));
+}
+
+void
+window_cmd_help_manual (BonoboUIComponent *uic,
+ char *filename,
+ const char* verbname)
+{
+ GError *error;
+ GtkWidget *dialog;
+
+ error = NULL;
+ gnome_help_display ("Ephy.xml", NULL, &error);
+
+ if (error)
+ {
+ dialog = gtk_message_dialog_new (NULL,
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE,
+ _("There was an error displaying help: \n%s"),
+ error->message);
+ g_signal_connect (G_OBJECT (dialog), "response",
+ G_CALLBACK (gtk_widget_destroy),
+ NULL);
+
+ gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
+ gtk_widget_show (dialog);
+ g_error_free (error);
+ }
+}
diff --git a/src/window-commands.h b/src/window-commands.h
new file mode 100644
index 000000000..df05a4d50
--- /dev/null
+++ b/src/window-commands.h
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "ephy-window.h"
+#include "ephy-embed-utils.h"
+
+#include <bonobo/bonobo-ui-component.h>
+
+void window_cmd_edit_find (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_file_print (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_go_stop (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_go_back (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_go_forward (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_go_go (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_go_up (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_go_home (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_go_myportal (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_go_location (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_go_reload (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_new (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_new_window (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_new_tab (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_bookmarks_add_default (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_bookmarks_edit (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_file_open (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_file_save_as (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_file_send_to (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_file_close_tab (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_file_close_window (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_edit_cut (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_edit_copy (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_edit_paste (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_edit_select_all (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_edit_find_next (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_edit_find_prev (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_view_zoom_in (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_view_zoom_out (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_view_zoom_normal(BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_view_page_source(BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_tools_history (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_tools_pdm (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_edit_prefs (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void
+window_cmd_settings_toolbar_editor (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_help_about (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_set_charset (BonoboUIComponent *uic,
+ EncodingMenuData *data,
+ const char* verbname);
+
+void window_cmd_tabs_next (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_tabs_previous (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_tabs_move_left (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_tabs_move_right (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_tabs_detach (BonoboUIComponent *uic,
+ EphyWindow *window,
+ const char* verbname);
+
+void window_cmd_help_manual (BonoboUIComponent *uic,
+ char *filename,
+ const char* verbname);
+