From 6876ede98282c7db318089bfefb292aa59e55d48 Mon Sep 17 00:00:00 2001 From: Marco Pesenti Gritti Date: Mon, 30 Dec 2002 19:29:24 +0000 Subject: Initial revision --- .cvsignore | 14 + AUTHORS | 0 COPYING | 340 +++ ChangeLog | 875 ++++++++ HACKING | 16 + INSTALL | 182 ++ Makefile.am | 8 + NEWS | 0 README | 121 + TODO | 17 + acconfig.h | 6 + autogen.sh | 19 + configure.in | 171 ++ data/.cvsignore | 5 + data/GNOME_Epiphany_Automation.server.in | 20 + data/GNOME_Epiphany_NautilusView.server.in | 30 + data/Makefile.am | 29 + data/art/.cvsignore | 2 + data/art/Makefile.am | 7 + data/art/epiphany-secure.png | Bin 0 -> 332 bytes data/art/epiphany-unsecure.png | Bin 0 -> 332 bytes data/epiphany.schemas.in | 627 ++++++ data/glade/.cvsignore | 3 + data/glade/Makefile.am | 10 + data/glade/epiphany.glade | 1582 +++++++++++++ data/glade/prefs-dialog.glade | 3083 ++++++++++++++++++++++++++ data/glade/print.glade | 1573 +++++++++++++ data/glade/prompts.glade | 722 ++++++ data/glade/toolbar-editor.glade | 418 ++++ data/start_here.html | 23 + data/ui/.cvsignore | 4 + data/ui/Makefile.am | 11 + data/ui/epiphany-ui.xml.in | 454 ++++ data/ui/nautilus-epiphany-view.xml.in | 130 ++ embed/.cvsignore | 6 + embed/Makefile.am | 57 + embed/downloader-view.c | 1100 +++++++++ embed/downloader-view.h | 100 + embed/ephy-embed-dialog.c | 194 ++ embed/ephy-embed-dialog.h | 69 + embed/ephy-embed-event.c | 179 ++ embed/ephy-embed-event.h | 100 + embed/ephy-embed-favicon.c | 252 +++ embed/ephy-embed-favicon.h | 63 + embed/ephy-embed-persist.c | 491 ++++ embed/ephy-embed-persist.h | 129 ++ embed/ephy-embed-popup-bw.c | 187 ++ embed/ephy-embed-popup-bw.h | 58 + embed/ephy-embed-popup-control.c | 188 ++ embed/ephy-embed-popup-control.h | 61 + embed/ephy-embed-popup.c | 623 ++++++ embed/ephy-embed-popup.h | 73 + embed/ephy-embed-prefs.h | 46 + embed/ephy-embed-shell.c | 507 +++++ embed/ephy-embed-shell.h | 307 +++ embed/ephy-embed-types.h | 47 + embed/ephy-embed-utils.c | 321 +++ embed/ephy-embed-utils.h | 50 + embed/ephy-embed.c | 608 +++++ embed/ephy-embed.h | 443 ++++ embed/ephy-favicon-cache.c | 367 +++ embed/ephy-favicon-cache.h | 68 + embed/ephy-favicon.c | 280 +++ embed/ephy-favicon.h | 64 + embed/ephy-history.c | 644 ++++++ embed/ephy-history.h | 92 + embed/find-dialog.c | 431 ++++ embed/find-dialog.h | 74 + embed/mozilla/.cvsignore | 6 + embed/mozilla/BaseProtocolContentHandler.cpp | 104 + embed/mozilla/BaseProtocolContentHandler.h | 43 + embed/mozilla/BaseProtocolHandler.cpp | 106 + embed/mozilla/BaseProtocolHandler.h | 39 + embed/mozilla/ContentHandler.cpp | 671 ++++++ embed/mozilla/ContentHandler.h | 102 + embed/mozilla/EphyEventListener.cpp | 114 + embed/mozilla/EphyEventListener.h | 46 + embed/mozilla/EphyWrapper.cpp | 1384 ++++++++++++ embed/mozilla/EphyWrapper.h | 147 ++ embed/mozilla/EventContext.cpp | 669 ++++++ embed/mozilla/EventContext.h | 65 + embed/mozilla/ExternalProtocolService.cpp | 176 ++ embed/mozilla/ExternalProtocolService.h | 50 + embed/mozilla/FilePicker.cpp | 505 +++++ embed/mozilla/FilePicker.h | 94 + embed/mozilla/FtpProtocolHandler.cpp | 58 + embed/mozilla/FtpProtocolHandler.h | 52 + embed/mozilla/GlobalHistory.cpp | 169 ++ embed/mozilla/GlobalHistory.h | 31 + embed/mozilla/IRCProtocolHandler.cpp | 58 + embed/mozilla/IRCProtocolHandler.h | 43 + embed/mozilla/MailtoProtocolHandler.cpp | 64 + embed/mozilla/MailtoProtocolHandler.h | 43 + embed/mozilla/Makefile.am | 108 + embed/mozilla/MozRegisterComponents.cpp | 226 ++ embed/mozilla/MozRegisterComponents.h | 33 + embed/mozilla/MozillaPrivate.cpp | 105 + embed/mozilla/MozillaPrivate.h | 9 + embed/mozilla/PrintProgressListener.cpp | 116 + embed/mozilla/PrintProgressListener.h | 38 + embed/mozilla/PrintingPromptService.cpp | 129 ++ embed/mozilla/PrintingPromptService.h | 38 + embed/mozilla/ProgressListener.cpp | 718 ++++++ embed/mozilla/ProgressListener.h | 139 ++ embed/mozilla/PromptService.cpp | 769 +++++++ embed/mozilla/PromptService.h | 39 + embed/mozilla/StartHereProtocolHandler.cpp | 162 ++ embed/mozilla/StartHereProtocolHandler.h | 38 + embed/mozilla/mozilla-embed-persist.cpp | 244 ++ embed/mozilla/mozilla-embed-persist.h | 56 + embed/mozilla/mozilla-embed-shell.cpp | 1106 +++++++++ embed/mozilla/mozilla-embed-shell.h | 55 + embed/mozilla/mozilla-embed.cpp | 1585 +++++++++++++ embed/mozilla/mozilla-embed.h | 61 + embed/mozilla/mozilla-i18n.c | 162 ++ embed/mozilla/mozilla-i18n.h | 60 + embed/mozilla/mozilla-notifiers.cpp | 710 ++++++ embed/mozilla/mozilla-notifiers.h | 30 + embed/mozilla/mozilla-prefs.cpp | 185 ++ embed/mozilla/mozilla-prefs.h | 44 + embed/mozilla/nsUnicharUtils.cpp | 344 +++ embed/mozilla/nsUnicharUtils.h | 96 + embed/print-dialog.c | 402 ++++ embed/print-dialog.h | 73 + idl/EphyAutomation.idl | 27 + lib/.cvsignore | 6 + lib/Makefile.am | 73 + lib/eel-gconf-extensions.c | 556 +++++ lib/eel-gconf-extensions.h | 87 + lib/ephy-autocompletion-source.c | 85 + lib/ephy-autocompletion-source.h | 80 + lib/ephy-autocompletion.c | 664 ++++++ lib/ephy-autocompletion.h | 107 + lib/ephy-bonobo-extensions.c | 679 ++++++ lib/ephy-bonobo-extensions.h | 121 + lib/ephy-dialog.c | 943 ++++++++ lib/ephy-dialog.h | 119 + lib/ephy-dnd.c | 109 + lib/ephy-dnd.h | 67 + lib/ephy-file-helpers.c | 326 +++ lib/ephy-file-helpers.h | 48 + lib/ephy-filesystem-autocompletion.c | 343 +++ lib/ephy-filesystem-autocompletion.h | 70 + lib/ephy-glade.c | 134 ++ lib/ephy-glade.h | 41 + lib/ephy-gobject-misc.h | 77 + lib/ephy-gui.c | 352 +++ lib/ephy-gui.h | 79 + lib/ephy-marshal.list | 16 + lib/ephy-node-filter.c | 461 ++++ lib/ephy-node-filter.h | 102 + lib/ephy-node.c | 1439 ++++++++++++ lib/ephy-node.h | 144 ++ lib/ephy-prefs-utils.c | 285 +++ lib/ephy-prefs-utils.h | 61 + lib/ephy-prefs.h | 58 + lib/ephy-state.c | 157 ++ lib/ephy-state.h | 44 + lib/ephy-stock-icons.c | 62 + lib/ephy-stock-icons.h | 33 + lib/ephy-string.c | 446 ++++ lib/ephy-string.h | 63 + lib/ephy-thread-helpers.c | 35 + lib/ephy-thread-helpers.h | 34 + lib/ephy-types.h | 35 + lib/toolbar/.cvsignore | 6 + lib/toolbar/Makefile.am | 41 + lib/toolbar/ephy-tbi-favicon.c | 188 ++ lib/toolbar/ephy-tbi-favicon.h | 66 + lib/toolbar/ephy-tbi-location.c | 205 ++ lib/toolbar/ephy-tbi-location.h | 66 + lib/toolbar/ephy-tbi-navigation-history.c | 342 +++ lib/toolbar/ephy-tbi-navigation-history.h | 81 + lib/toolbar/ephy-tbi-separator.c | 179 ++ lib/toolbar/ephy-tbi-separator.h | 68 + lib/toolbar/ephy-tbi-spinner.c | 188 ++ lib/toolbar/ephy-tbi-spinner.h | 66 + lib/toolbar/ephy-tbi-std-toolitem.c | 467 ++++ lib/toolbar/ephy-tbi-std-toolitem.h | 86 + lib/toolbar/ephy-tbi-zoom.c | 304 +++ lib/toolbar/ephy-tbi-zoom.h | 66 + lib/toolbar/ephy-toolbar-bonobo-view.c | 193 ++ lib/toolbar/ephy-toolbar-bonobo-view.h | 75 + lib/toolbar/ephy-toolbar-editor.c | 634 ++++++ lib/toolbar/ephy-toolbar-editor.h | 80 + lib/toolbar/ephy-toolbar-item-factory.c | 158 ++ lib/toolbar/ephy-toolbar-item-factory.h | 31 + lib/toolbar/ephy-toolbar-item.c | 142 ++ lib/toolbar/ephy-toolbar-item.h | 91 + lib/toolbar/ephy-toolbar-tree-model.c | 784 +++++++ lib/toolbar/ephy-toolbar-tree-model.h | 74 + lib/toolbar/ephy-toolbar.c | 420 ++++ lib/toolbar/ephy-toolbar.h | 80 + lib/widgets/.cvsignore | 6 + lib/widgets/Makefile.am | 30 + lib/widgets/eggtreemodelfilter.c | 2560 +++++++++++++++++++++ lib/widgets/eggtreemodelfilter.h | 123 + lib/widgets/eggtreemultidnd.c | 415 ++++ lib/widgets/eggtreemultidnd.h | 78 + lib/widgets/ephy-autocompletion-window.c | 854 +++++++ lib/widgets/ephy-autocompletion-window.h | 87 + lib/widgets/ephy-ellipsizing-label.c | 774 +++++++ lib/widgets/ephy-ellipsizing-label.h | 71 + lib/widgets/ephy-location-entry.c | 700 ++++++ lib/widgets/ephy-location-entry.h | 74 + lib/widgets/ephy-notebook.c | 843 +++++++ lib/widgets/ephy-notebook.h | 99 + lib/widgets/ephy-spinner.c | 897 ++++++++ lib/widgets/ephy-spinner.h | 78 + lib/widgets/ephy-tree-model-sort.c | 240 ++ lib/widgets/ephy-tree-model-sort.h | 59 + po/.cvsignore | 6 + po/ChangeLog | 0 po/POTFILES.in | 45 + src/.cvsignore | 6 + src/Makefile.am | 101 + src/appearance-prefs.c | 458 ++++ src/appearance-prefs.h | 58 + src/bookmarks/.cvsignore | 6 + src/bookmarks/Makefile.am | 31 + src/bookmarks/ephy-bookmarks-editor.c | 534 +++++ src/bookmarks/ephy-bookmarks-editor.h | 59 + src/bookmarks/ephy-bookmarks.c | 988 +++++++++ src/bookmarks/ephy-bookmarks.h | 108 + src/bookmarks/ephy-keywords-entry.c | 286 +++ src/bookmarks/ephy-keywords-entry.h | 68 + src/bookmarks/ephy-new-bookmark.c | 340 +++ src/bookmarks/ephy-new-bookmark.h | 65 + src/bookmarks/ephy-node-view.c | 531 +++++ src/bookmarks/ephy-node-view.h | 82 + src/bookmarks/ephy-tree-model-node.c | 702 ++++++ src/bookmarks/ephy-tree-model-node.h | 81 + src/ephy-automation.c | 217 ++ src/ephy-automation.h | 52 + src/ephy-favorites-menu.c | 275 +++ src/ephy-favorites-menu.h | 66 + src/ephy-history-model.c | 838 +++++++ src/ephy-history-model.h | 84 + src/ephy-main.c | 340 +++ src/ephy-nautilus-view.c | 954 ++++++++ src/ephy-nautilus-view.h | 84 + src/ephy-shell.c | 525 +++++ src/ephy-shell.h | 101 + src/ephy-tab.c | 945 ++++++++ src/ephy-tab.h | 105 + src/ephy-window.c | 1428 ++++++++++++ src/ephy-window.h | 140 ++ src/general-prefs.c | 484 ++++ src/general-prefs.h | 58 + src/history-dialog.c | 478 ++++ src/history-dialog.h | 63 + src/language-editor.c | 388 ++++ src/language-editor.h | 67 + src/pdm-dialog.c | 669 ++++++ src/pdm-dialog.h | 56 + src/popup-commands.c | 222 ++ src/popup-commands.h | 58 + src/ppview-toolbar.c | 388 ++++ src/ppview-toolbar.h | 63 + src/prefs-dialog.c | 335 +++ src/prefs-dialog.h | 63 + src/session.c | 690 ++++++ src/session.h | 84 + src/statusbar.c | 321 +++ src/statusbar.h | 70 + src/toolbar.c | 982 ++++++++ src/toolbar.h | 88 + src/ui-prefs.c | 232 ++ src/ui-prefs.h | 58 + src/window-commands.c | 917 ++++++++ src/window-commands.h | 196 ++ 271 files changed, 71076 insertions(+) create mode 100644 .cvsignore create mode 100644 AUTHORS create mode 100644 COPYING create mode 100644 ChangeLog create mode 100644 HACKING create mode 100644 INSTALL create mode 100644 Makefile.am create mode 100644 NEWS create mode 100644 README create mode 100644 TODO create mode 100644 acconfig.h create mode 100755 autogen.sh create mode 100644 configure.in create mode 100644 data/.cvsignore create mode 100644 data/GNOME_Epiphany_Automation.server.in create mode 100644 data/GNOME_Epiphany_NautilusView.server.in create mode 100644 data/Makefile.am create mode 100644 data/art/.cvsignore create mode 100644 data/art/Makefile.am create mode 100644 data/art/epiphany-secure.png create mode 100644 data/art/epiphany-unsecure.png create mode 100644 data/epiphany.schemas.in create mode 100644 data/glade/.cvsignore create mode 100644 data/glade/Makefile.am create mode 100644 data/glade/epiphany.glade create mode 100644 data/glade/prefs-dialog.glade create mode 100644 data/glade/print.glade create mode 100644 data/glade/prompts.glade create mode 100644 data/glade/toolbar-editor.glade create mode 100644 data/start_here.html create mode 100644 data/ui/.cvsignore create mode 100644 data/ui/Makefile.am create mode 100644 data/ui/epiphany-ui.xml.in create mode 100644 data/ui/nautilus-epiphany-view.xml.in create mode 100644 embed/.cvsignore create mode 100644 embed/Makefile.am create mode 100644 embed/downloader-view.c create mode 100644 embed/downloader-view.h create mode 100644 embed/ephy-embed-dialog.c create mode 100644 embed/ephy-embed-dialog.h create mode 100644 embed/ephy-embed-event.c create mode 100644 embed/ephy-embed-event.h create mode 100644 embed/ephy-embed-favicon.c create mode 100644 embed/ephy-embed-favicon.h create mode 100644 embed/ephy-embed-persist.c create mode 100644 embed/ephy-embed-persist.h create mode 100644 embed/ephy-embed-popup-bw.c create mode 100644 embed/ephy-embed-popup-bw.h create mode 100644 embed/ephy-embed-popup-control.c create mode 100644 embed/ephy-embed-popup-control.h create mode 100644 embed/ephy-embed-popup.c create mode 100644 embed/ephy-embed-popup.h create mode 100644 embed/ephy-embed-prefs.h create mode 100644 embed/ephy-embed-shell.c create mode 100644 embed/ephy-embed-shell.h create mode 100644 embed/ephy-embed-types.h create mode 100644 embed/ephy-embed-utils.c create mode 100644 embed/ephy-embed-utils.h create mode 100644 embed/ephy-embed.c create mode 100644 embed/ephy-embed.h create mode 100644 embed/ephy-favicon-cache.c create mode 100644 embed/ephy-favicon-cache.h create mode 100644 embed/ephy-favicon.c create mode 100644 embed/ephy-favicon.h create mode 100644 embed/ephy-history.c create mode 100644 embed/ephy-history.h create mode 100755 embed/find-dialog.c create mode 100644 embed/find-dialog.h create mode 100644 embed/mozilla/.cvsignore create mode 100644 embed/mozilla/BaseProtocolContentHandler.cpp create mode 100644 embed/mozilla/BaseProtocolContentHandler.h create mode 100644 embed/mozilla/BaseProtocolHandler.cpp create mode 100644 embed/mozilla/BaseProtocolHandler.h create mode 100644 embed/mozilla/ContentHandler.cpp create mode 100644 embed/mozilla/ContentHandler.h create mode 100644 embed/mozilla/EphyEventListener.cpp create mode 100644 embed/mozilla/EphyEventListener.h create mode 100644 embed/mozilla/EphyWrapper.cpp create mode 100644 embed/mozilla/EphyWrapper.h create mode 100644 embed/mozilla/EventContext.cpp create mode 100644 embed/mozilla/EventContext.h create mode 100644 embed/mozilla/ExternalProtocolService.cpp create mode 100644 embed/mozilla/ExternalProtocolService.h create mode 100644 embed/mozilla/FilePicker.cpp create mode 100644 embed/mozilla/FilePicker.h create mode 100644 embed/mozilla/FtpProtocolHandler.cpp create mode 100644 embed/mozilla/FtpProtocolHandler.h create mode 100644 embed/mozilla/GlobalHistory.cpp create mode 100644 embed/mozilla/GlobalHistory.h create mode 100644 embed/mozilla/IRCProtocolHandler.cpp create mode 100644 embed/mozilla/IRCProtocolHandler.h create mode 100644 embed/mozilla/MailtoProtocolHandler.cpp create mode 100644 embed/mozilla/MailtoProtocolHandler.h create mode 100644 embed/mozilla/Makefile.am create mode 100644 embed/mozilla/MozRegisterComponents.cpp create mode 100644 embed/mozilla/MozRegisterComponents.h create mode 100644 embed/mozilla/MozillaPrivate.cpp create mode 100644 embed/mozilla/MozillaPrivate.h create mode 100644 embed/mozilla/PrintProgressListener.cpp create mode 100644 embed/mozilla/PrintProgressListener.h create mode 100644 embed/mozilla/PrintingPromptService.cpp create mode 100644 embed/mozilla/PrintingPromptService.h create mode 100644 embed/mozilla/ProgressListener.cpp create mode 100644 embed/mozilla/ProgressListener.h create mode 100644 embed/mozilla/PromptService.cpp create mode 100644 embed/mozilla/PromptService.h create mode 100644 embed/mozilla/StartHereProtocolHandler.cpp create mode 100644 embed/mozilla/StartHereProtocolHandler.h create mode 100644 embed/mozilla/mozilla-embed-persist.cpp create mode 100644 embed/mozilla/mozilla-embed-persist.h create mode 100644 embed/mozilla/mozilla-embed-shell.cpp create mode 100644 embed/mozilla/mozilla-embed-shell.h create mode 100644 embed/mozilla/mozilla-embed.cpp create mode 100644 embed/mozilla/mozilla-embed.h create mode 100644 embed/mozilla/mozilla-i18n.c create mode 100644 embed/mozilla/mozilla-i18n.h create mode 100644 embed/mozilla/mozilla-notifiers.cpp create mode 100644 embed/mozilla/mozilla-notifiers.h create mode 100644 embed/mozilla/mozilla-prefs.cpp create mode 100644 embed/mozilla/mozilla-prefs.h create mode 100644 embed/mozilla/nsUnicharUtils.cpp create mode 100644 embed/mozilla/nsUnicharUtils.h create mode 100755 embed/print-dialog.c create mode 100644 embed/print-dialog.h create mode 100644 idl/EphyAutomation.idl create mode 100644 lib/.cvsignore create mode 100644 lib/Makefile.am create mode 100644 lib/eel-gconf-extensions.c create mode 100644 lib/eel-gconf-extensions.h create mode 100644 lib/ephy-autocompletion-source.c create mode 100644 lib/ephy-autocompletion-source.h create mode 100644 lib/ephy-autocompletion.c create mode 100644 lib/ephy-autocompletion.h create mode 100644 lib/ephy-bonobo-extensions.c create mode 100644 lib/ephy-bonobo-extensions.h create mode 100644 lib/ephy-dialog.c create mode 100644 lib/ephy-dialog.h create mode 100644 lib/ephy-dnd.c create mode 100644 lib/ephy-dnd.h create mode 100644 lib/ephy-file-helpers.c create mode 100644 lib/ephy-file-helpers.h create mode 100644 lib/ephy-filesystem-autocompletion.c create mode 100644 lib/ephy-filesystem-autocompletion.h create mode 100644 lib/ephy-glade.c create mode 100644 lib/ephy-glade.h create mode 100644 lib/ephy-gobject-misc.h create mode 100644 lib/ephy-gui.c create mode 100644 lib/ephy-gui.h create mode 100644 lib/ephy-marshal.list create mode 100644 lib/ephy-node-filter.c create mode 100644 lib/ephy-node-filter.h create mode 100644 lib/ephy-node.c create mode 100644 lib/ephy-node.h create mode 100644 lib/ephy-prefs-utils.c create mode 100644 lib/ephy-prefs-utils.h create mode 100644 lib/ephy-prefs.h create mode 100644 lib/ephy-state.c create mode 100644 lib/ephy-state.h create mode 100644 lib/ephy-stock-icons.c create mode 100644 lib/ephy-stock-icons.h create mode 100644 lib/ephy-string.c create mode 100644 lib/ephy-string.h create mode 100644 lib/ephy-thread-helpers.c create mode 100644 lib/ephy-thread-helpers.h create mode 100644 lib/ephy-types.h create mode 100644 lib/toolbar/.cvsignore create mode 100644 lib/toolbar/Makefile.am create mode 100644 lib/toolbar/ephy-tbi-favicon.c create mode 100644 lib/toolbar/ephy-tbi-favicon.h create mode 100644 lib/toolbar/ephy-tbi-location.c create mode 100644 lib/toolbar/ephy-tbi-location.h create mode 100644 lib/toolbar/ephy-tbi-navigation-history.c create mode 100644 lib/toolbar/ephy-tbi-navigation-history.h create mode 100644 lib/toolbar/ephy-tbi-separator.c create mode 100644 lib/toolbar/ephy-tbi-separator.h create mode 100644 lib/toolbar/ephy-tbi-spinner.c create mode 100644 lib/toolbar/ephy-tbi-spinner.h create mode 100644 lib/toolbar/ephy-tbi-std-toolitem.c create mode 100644 lib/toolbar/ephy-tbi-std-toolitem.h create mode 100644 lib/toolbar/ephy-tbi-zoom.c create mode 100644 lib/toolbar/ephy-tbi-zoom.h create mode 100644 lib/toolbar/ephy-toolbar-bonobo-view.c create mode 100644 lib/toolbar/ephy-toolbar-bonobo-view.h create mode 100644 lib/toolbar/ephy-toolbar-editor.c create mode 100644 lib/toolbar/ephy-toolbar-editor.h create mode 100644 lib/toolbar/ephy-toolbar-item-factory.c create mode 100644 lib/toolbar/ephy-toolbar-item-factory.h create mode 100644 lib/toolbar/ephy-toolbar-item.c create mode 100644 lib/toolbar/ephy-toolbar-item.h create mode 100644 lib/toolbar/ephy-toolbar-tree-model.c create mode 100644 lib/toolbar/ephy-toolbar-tree-model.h create mode 100644 lib/toolbar/ephy-toolbar.c create mode 100644 lib/toolbar/ephy-toolbar.h create mode 100644 lib/widgets/.cvsignore create mode 100644 lib/widgets/Makefile.am create mode 100644 lib/widgets/eggtreemodelfilter.c create mode 100644 lib/widgets/eggtreemodelfilter.h create mode 100644 lib/widgets/eggtreemultidnd.c create mode 100644 lib/widgets/eggtreemultidnd.h create mode 100644 lib/widgets/ephy-autocompletion-window.c create mode 100644 lib/widgets/ephy-autocompletion-window.h create mode 100644 lib/widgets/ephy-ellipsizing-label.c create mode 100644 lib/widgets/ephy-ellipsizing-label.h create mode 100644 lib/widgets/ephy-location-entry.c create mode 100644 lib/widgets/ephy-location-entry.h create mode 100644 lib/widgets/ephy-notebook.c create mode 100644 lib/widgets/ephy-notebook.h create mode 100644 lib/widgets/ephy-spinner.c create mode 100644 lib/widgets/ephy-spinner.h create mode 100644 lib/widgets/ephy-tree-model-sort.c create mode 100644 lib/widgets/ephy-tree-model-sort.h create mode 100644 po/.cvsignore create mode 100644 po/ChangeLog create mode 100644 po/POTFILES.in create mode 100644 src/.cvsignore create mode 100644 src/Makefile.am create mode 100755 src/appearance-prefs.c create mode 100644 src/appearance-prefs.h create mode 100644 src/bookmarks/.cvsignore create mode 100644 src/bookmarks/Makefile.am create mode 100644 src/bookmarks/ephy-bookmarks-editor.c create mode 100644 src/bookmarks/ephy-bookmarks-editor.h create mode 100644 src/bookmarks/ephy-bookmarks.c create mode 100644 src/bookmarks/ephy-bookmarks.h create mode 100644 src/bookmarks/ephy-keywords-entry.c create mode 100644 src/bookmarks/ephy-keywords-entry.h create mode 100644 src/bookmarks/ephy-new-bookmark.c create mode 100644 src/bookmarks/ephy-new-bookmark.h create mode 100644 src/bookmarks/ephy-node-view.c create mode 100644 src/bookmarks/ephy-node-view.h create mode 100644 src/bookmarks/ephy-tree-model-node.c create mode 100644 src/bookmarks/ephy-tree-model-node.h create mode 100644 src/ephy-automation.c create mode 100644 src/ephy-automation.h create mode 100644 src/ephy-favorites-menu.c create mode 100644 src/ephy-favorites-menu.h create mode 100644 src/ephy-history-model.c create mode 100644 src/ephy-history-model.h create mode 100644 src/ephy-main.c create mode 100644 src/ephy-nautilus-view.c create mode 100644 src/ephy-nautilus-view.h create mode 100644 src/ephy-shell.c create mode 100644 src/ephy-shell.h create mode 100644 src/ephy-tab.c create mode 100644 src/ephy-tab.h create mode 100644 src/ephy-window.c create mode 100644 src/ephy-window.h create mode 100755 src/general-prefs.c create mode 100644 src/general-prefs.h create mode 100755 src/history-dialog.c create mode 100644 src/history-dialog.h create mode 100644 src/language-editor.c create mode 100644 src/language-editor.h create mode 100755 src/pdm-dialog.c create mode 100644 src/pdm-dialog.h create mode 100644 src/popup-commands.c create mode 100644 src/popup-commands.h create mode 100755 src/ppview-toolbar.c create mode 100644 src/ppview-toolbar.h create mode 100644 src/prefs-dialog.c create mode 100644 src/prefs-dialog.h create mode 100644 src/session.c create mode 100644 src/session.h create mode 100755 src/statusbar.c create mode 100644 src/statusbar.h create mode 100755 src/toolbar.c create mode 100644 src/toolbar.h create mode 100755 src/ui-prefs.c create mode 100644 src/ui-prefs.h create mode 100644 src/window-commands.c create mode 100644 src/window-commands.h 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 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. + + + Copyright (C) + + 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. + + , 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * embed/ephy-embed-favicon.c: (net_state_cb), (favicon_cb): + + fix some bugs + +2002-12-26 Marco Pesenti Gritti + + * 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 + + * 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 + + * 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 + + * src/bookmarks/ephy-bookmarks-editor.c: + (keyword_node_selected_cb), (ephy_bookmarks_editor_construct): + + Regression fixed. + +2002-12-24 Marco Pesenti Gritti + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * embed/find-dialog.c: (impl_show): grab focus on the entry + +2002-12-08 Marco Pesenti Gritti + + * 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 + + * 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 + + * 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 + + * 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 + + * embed/mozilla/EphyWrapper.cpp: + * embed/mozilla/EphyWrapper.h: remove some unused code, + should build with mozilla head again + +2002-12-06 Marco Pesenti Gritti + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 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 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 @@ + + + + + + + + + + + + + + + + + + + + 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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 Binary files /dev/null and b/data/art/epiphany-secure.png differ diff --git a/data/art/epiphany-unsecure.png b/data/art/epiphany-unsecure.png new file mode 100644 index 000000000..5ee7106d9 Binary files /dev/null and b/data/art/epiphany-unsecure.png 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 @@ + + + + /schemas/apps/epiphany/general/start_page + /apps/epiphany/general/start_page + epiphany + string + start-here: + + Home page + URL for the user's home page. Displayed on start up + and when a new window or tab is created + + + + /schemas/apps/epiphany/general/newpage_type + /apps/epiphany/general/newpage_type + epiphany + int + 0 + + New page type + Type of page to show when opening a new window or tab. Possible + values are: 0 (home page), 1 (last page), 2 (blank) + + + + /schemas/apps/epiphany/find/match_case + /apps/epiphany/find/match_case + epiphany + bool + 0 + + Match case for find in page + Match case for find in page. + + + + /schemas/apps/epiphany/find/autowrap + /apps/epiphany/find/autowrap + epiphany + bool + 1 + + Autowrap for find in page + For find in page, whether to start again at the beginning after + reaching the end of the page + + + + /schemas/apps/epiphany/filtering/allow_popups + /apps/epiphany/filtering/allow_popups + epiphany + bool + true + + Allow popups + Allow sites to open new windows using JavaScript (if JavaScript + is enabled). + + + + /schemas/apps/epiphany/rendering/use_own_colors + /apps/epiphany/rendering/use_own_colors + epiphany + bool + false + + Use own colors + Use your own colors instead of the colors the page + requests. + + + + /schemas/apps/epiphany/rendering/use_own_fonts + /apps/epiphany/rendering/use_own_fonts + epiphany + bool + false + + Use own fonts + Use your own fonts instead of the fonts the page + requests. + + + + /schemas/apps/epiphany/rendering/background_color + /apps/epiphany/rendering/background_color + epiphany + string + #FFFFFF + + Default page background color + Default page background color in #RRGGBB hex format. + + + + /schemas/apps/epiphany/rendering/text_color + /apps/epiphany/rendering/text_color + epiphany + string + #000000 + + Default page text color + Default page text color in #RRGGBB hex format. + + + + /schemas/apps/epiphany/rendering/visited_link_color + /apps/epiphany/rendering/visited_link_color + epiphany + string + #FF0000 + + Default visited link color + Default color for visited links in #RRGGBB hex format. + + + + /schemas/apps/epiphany/rendering/unvisited_link_color + /apps/epiphany/rendering/unvisited_link_color + epiphany + string + #0000FF + + Default unvisited link color + Default color for unvisited links in #RRGGBB hex format. + + + + /schemas/apps/epiphany/rendering/underline_links + /apps/epiphany/rendering/underline_links + epiphany + bool + true + + Underline links + Underline links. + + + + /schemas/apps/epiphany/interface/open_in_tab + /apps/epiphany/interface/open_in_tab + epiphany + bool + false + + Use tabs + Open in tabs by default. + + + + /schemas/apps/epiphany/interface/popups_in_tab + /apps/epiphany/interface/popups_in_tab + epiphany + bool + false + + Open popups in tabs + Open popups in tabs instead of new windows. + + + + /schemas/apps/epiphany/interface/jumpto_tab + /apps/epiphany/interface/jumpto_tab + epiphany + bool + false + + Jump to new tabs + Jump to new tabs. + + + + /schemas/apps/epiphany/interface/show_toolbars_in_fullscreen + /apps/epiphany/interface/show_toolbars_in_fullscreen + epiphany + bool + 1 + + Show toolbars in full screen mode + Show toolbars in full screen mode. + + + + /schemas/apps/epiphany/interface/show_statusbar_in_fullscreen + /apps/epiphany/interface/show_statusbar_in_fullscreen + epiphany + bool + 0 + + Show statusbar in full screen mode + Show statusbar in full screen mode. + + + + /schemas/apps/epiphany/interface/show_sidebar_in_fullscreen + /apps/epiphany/interface/show_sidebar_in_fullscreen + epiphany + bool + 0 + + Show sidebar in full screen mode + Show sidebar in full screen mode. + + + + /schemas/apps/epiphany/interface/show_sidebar + /apps/epiphany/interface/show_sidebar + epiphany + bool + 0 + + Show sidebar by default + Show sidebar by default. + + + + /schemas/apps/epiphany/interface/sidebar_size + /apps/epiphany/interface/sidebar_size + epiphany + int + 100 + + Default sidebar size + Default sidebar size. + + + + /schemas/apps/epiphany/interface/sidebar_page + /apps/epiphany/interface/sidebar_page + epiphany + string + history + + Default sidebar page + Default sidebar page. + + + + /schemas/apps/epiphany/interface/show_toolbars + /apps/epiphany/interface/show_toolbars + epiphany + bool + 1 + + Show toolbars by default + Show toolbars by default. + + + + /schemas/apps/epiphany/interface/show_statusbar + /apps/epiphany/interface/show_statusbar + epiphany + bool + 1 + + Show statusbar by default + Show statusbar by default. + + + + /schemas/apps/epiphany/filtering/image_loading_type + /apps/epiphany/filtering/image_loading_type + epiphany + int + 0 + + When to load images + When to load images. Possible values are 0 (always), 1 (from + current server only), 2 (never) + + + + /schemas/apps/epiphany/filtering/animate_type + /apps/epiphany/filtering/animate_type + epiphany + int + 0 + + Image animation type + Image animation type. Possible values are 0 (continuously), 1 + (once through), 2 (never) + + + + /schemas/apps/epiphany/rendering/default_charset + /apps/epiphany/rendering/default_charset + epiphany + string + Western (ISO-8859-1) + + Default charset + Default charset. + + + + /schemas/apps/epiphany/rendering/default_font + /apps/epiphany/rendering/default_font + epiphany + int + 0 + + Default font type + Default font type. Possible values are 0 (serif), 1 + (sans-serif) + + + + /schemas/apps/epiphany/interface/spinner_theme + /apps/epiphany/interface/spinner_theme + epiphany + string + gnome + + Default spinner theme + Default spinner theme + + + + /schemas/apps/epiphany/interface/toolbar_setup + /apps/epiphany/interface/toolbar_setup + epiphany + string + 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; + + Toolbar setup + 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. + + + + /schemas/apps/epiphany/downloader/keep_open + /apps/epiphany/downloader/keep_open + epiphany + bool + true + + Keep downloader open after download finished + Keep downloader open after all downloads have finished. + + + + /schemas/apps/epiphany/filtering/java_enabled + /apps/epiphany/filtering/java_enabled + epiphany + bool + 1 + + Allow Java + Allow Java. + + + + /schemas/apps/epiphany/filtering/javascript_enabled + /apps/epiphany/filtering/javascript_enabled + epiphany + bool + 1 + + Allow JavaScript + Allow JavaScript. + + + + /schemas/apps/epiphany/network/no_proxies_for + /apps/epiphany/network/no_proxies_for + epiphany + string + + + No proxy for + List of domains for wherefore not to use the proxy, comma + delimited + + + + /schemas/apps/epiphany/network/disk_cache_size + /apps/epiphany/network/disk_cache_size + epiphany + int + 50000 + + Size of disk cache + Size of disk cache, in KB. + + + + /schemas/apps/epiphany/network/mem_cache_size + /apps/epiphany/network/mem_cache_size + epiphany + int + 4096 + + Size of memory cache + Size of memory cache, in KB. + + + + /schemas/apps/epiphany/network/cache_compare + /apps/epiphany/network/cache_compare + epiphany + int + 3 + + When to compare cached copy + When to compare cached copy to web copy. Possible values are 0 + (once per session), 1 (every time), 2 (never), 3 (automatic). + + + + /schemas/apps/epiphany/rendering/lang + /apps/epiphany/rendering/lang + epiphany + list + string + [en] + + Languages + Preferred languages, two letter codes. + + + + /schemas/apps/epiphany/filterin/passwords_save + /apps/epiphany/filtering/passwords_save + epiphany + bool + true + + Save passwords + Save passwords. + + + + /schemas/apps/epiphany/history/expire + /apps/epiphany/history/expire + epiphany + int + 30 + + Expire history + Expire history after how many days. + + + + /schemas/apps/epiphany/history/search_time + /apps/epiphany/history/search_time + epiphany + int + 1 + + History search time + 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). + + + + /schemas/apps/epiphany/print/top_margin + /apps/epiphany/print/top_margin + epiphany + float + 0.5 + + Printing top margin + Printing top margin (in inches). + + + + /schemas/apps/epiphany/print/bottom_margin + /apps/epiphany/print/bottom_margin + epiphany + float + 0.5 + + Printing bottom margin + Printing bottom margin (in inches). + + + + /schemas/apps/epiphany/print/left_margin + /apps/epiphany/print/left_margin + epiphany + float + 0.5 + + Printing left margin + Printing left margin (in inches). + + + + /schemas/apps/epiphany/print/right_margin + /apps/epiphany/print/right_margin + epiphany + float + 0.5 + + Printing right margin + Printing right margin (in inches). + + + + /schemas/apps/epiphany/print/page_title_toggle + /apps/epiphany/print/page_title_toggle + epiphany + bool + true + + Whether to print the page title in the header. + Whether to print the page title in the header. + + + + /schemas/apps/epiphany/print/page_url_toggle + /apps/epiphany/print/page_url_toggle + epiphany + bool + true + + Whether to print the page URL in the header + Whether to print the page URL in the header + + + + /schemas/apps/epiphany/print/date_toggle + /apps/epiphany/print/date_toggle + epiphany + bool + true + + Whether to print the date in the footer. + Whether to print the date in the footer. + + + + /schemas/apps/epiphany/print/page_numbers_toggle + /apps/epiphany/print/page_numbers_toggle + epiphany + bool + true + + Whether to print the page numbers (x of total) in the footer. + Whether to print the page numbers (x of total) in the footer. + + + + /schemas/apps/epiphany/print/printer + /apps/epiphany/print/printer + epiphany + string + lpr + + Printer name + Printer name. + + + + /schemas/apps/epiphany/print/file + /apps/epiphany/print/file + epiphany + string + + Filename to print to + Filename to print to. + + + + /schemas/apps/epiphany/print/printon + /apps/epiphany/print/printon + epiphany + int + 0 + + Print range + Print range: 0 (all pages), 1 (specific range). + + + + /schemas/apps/epiphany/print/paper + /apps/epiphany/print/paper + epiphany + int + 0 + + Paper type + Paper type: 0 (Letter), 1 (Legal), 2 (Executive), 3 (A4). + + + + /schemas/apps/epiphany/directories/opendir + /apps/epiphany/directories/opendir + epiphany + string + ~ + + + + + /schemas/apps/epiphany/directories/savedir + /apps/epiphany/directories/savedir + epiphany + string + ~ + + + + + /schemas/apps/epiphany/directories/saveimagedir + /apps/epiphany/directories/saveimagedir + epiphany + string + ~ + + + + + /schemas/apps/epiphany/rendering/autodetect_charset + /apps/epiphany/rendering/autodetect_charset + epiphany + int + 0 + + + + + + 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 @@ + + + + + + + + 6 + 400 + History + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + False + + + + True + False + 0 + + + + True + GTK_BUTTONBOX_END + + + + True + True + True + GTK_RELIEF_NORMAL + 0 + + + + + True + 0.5 + 0.5 + 0 + 0 + + + + True + False + 2 + + + + True + gtk-clear + 4 + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + C_lear + True + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + + + + + + + True + True + True + True + gtk-close + True + GTK_RELIEF_NORMAL + -7 + + + + + + 0 + False + True + GTK_PACK_END + + + + + + 6 + True + False + 5 + + + + 6 + True + False + 6 + + + + True + _Find: + True + False + GTK_JUSTIFY_CENTER + False + False + 0.5 + 0.5 + 0 + 0 + history_entry + + + 0 + False + False + + + + + + True + True + True + True + True + 0 + + True + * + False + + + + 0 + True + True + + + + + + True + _Time: + True + False + GTK_JUSTIFY_CENTER + False + False + 1 + 0.5 + 0 + 0 + history_time_optionmenu + + + 0 + False + False + + + + + + True + True + 0 + + + + + True + + + + True + Ever + True + + + + + + True + Today + True + + + + + + True + Last two days + True + + + + + + True + Last three days + True + + + + + + True + Week + True + + + + + + True + Month + True + + + + + + + 0 + False + False + + + + + 0 + False + False + + + + + + True + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + True + True + False + False + True + + + + + 0 + True + True + + + + + 0 + True + True + + + + + + + + 6 + Find text... + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + False + + + + True + False + 0 + + + + True + GTK_BUTTONBOX_END + + + + True + True + True + gtk-close + True + GTK_RELIEF_NORMAL + 0 + + + + + + + True + True + True + GTK_RELIEF_NORMAL + 0 + + + + + True + 0.5 + 0.5 + 0 + 0 + + + + True + False + 2 + + + + True + gtk-go-back + 4 + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + _Previous + True + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + + + + + + + True + True + True + True + GTK_RELIEF_NORMAL + 0 + + + + + True + 0.5 + 0.5 + 0 + 0 + + + + True + False + 2 + + + + True + gtk-go-forward + 4 + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + _Next + True + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + + + + + + 0 + False + True + GTK_PACK_END + + + + + + 6 + True + False + 0 + + + + True + False + 6 + + + + True + False + 6 + + + + True + <b>Find text in the document:</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 7.45058e-09 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + 0 + False + False + + + + + + True + FindEntry + 10 + + + + True + True + True + True + True + 0 + + True + * + False + + + + + + + 0 + False + False + + + + + + True + True + _Match upper/lower case + True + GTK_RELIEF_NORMAL + False + False + True + + + + 0 + False + False + + + + + + True + True + Automatically _wrap around + True + GTK_RELIEF_NORMAL + False + False + True + + + + 0 + False + False + + + + + 0 + True + True + + + + + 2 + False + False + + + + + + + + 12 + Downloading + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + + + + + True + False + 12 + + + + True + GTK_BUTTONBOX_END + 8 + + + + True + False + True + True + gtk-open + True + GTK_RELIEF_NORMAL + + + + + + + True + False + True + True + _Pause + True + GTK_RELIEF_NORMAL + + + + + + + True + True + True + _Resume + True + GTK_RELIEF_NORMAL + + + + + + + True + True + True + gtk-stop + True + GTK_RELIEF_NORMAL + + + + + + 0 + False + True + GTK_PACK_END + + + + + + True + False + 6 + + + + 100 + True + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + True + True + False + False + True + + + + + 0 + True + True + + + + + + True + False + 6 + + + + True + True + _Keep the dialog open + True + GTK_RELIEF_NORMAL + False + False + True + + + 0 + True + True + + + + + + True + True + GTK_RELIEF_NORMAL + False + False + + + + + True + 0.5 + 0.5 + 0 + 0 + + + + True + False + 2 + + + + True + gtk-dialog-info + 4 + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + Download _details... + True + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + + + + 0 + False + False + + + + + 0 + False + False + + + + + + + + 0 + False + False + + + + + + True + False + 0 + + + + True + 6 + 2 + False + 6 + 6 + + + + True + <b>Location:</b> + False + True + GTK_JUSTIFY_RIGHT + False + False + 0 + 0.5 + 0 + 0 + + + 0 + 1 + 0 + 1 + fill + + + + + + + True + <b>File:</b> + False + True + GTK_JUSTIFY_RIGHT + False + False + 0 + 0.5 + 0 + 0 + + + 0 + 1 + 1 + 2 + fill + + + + + + + True + <b>Status:</b> + False + True + GTK_JUSTIFY_CENTER + False + False + 0 + 0.5 + 0 + 0 + + + 0 + 1 + 2 + 3 + fill + + + + + + + True + <b>Time Elapsed:</b> + False + True + GTK_JUSTIFY_CENTER + False + False + 0 + 0.5 + 0 + 0 + + + 0 + 1 + 3 + 4 + fill + + + + + + + True + <b>Time Remaining:</b> + False + True + GTK_JUSTIFY_CENTER + False + False + 0 + 0.5 + 0 + 0 + + + 0 + 1 + 4 + 5 + fill + + + + + + + True + + False + False + GTK_JUSTIFY_CENTER + False + False + 0 + 0.5 + 0 + 0 + + + 1 + 2 + 3 + 4 + fill + + + + + + + True + + False + False + GTK_JUSTIFY_CENTER + False + False + 0 + 0.5 + 0 + 0 + + + 1 + 2 + 4 + 5 + fill + + + + + + + True + + False + False + GTK_JUSTIFY_CENTER + False + False + 0 + 0.5 + 0 + 0 + + + 1 + 2 + 2 + 3 + fill + + + + + + + True + GTK_PROGRESS_LEFT_TO_RIGHT + 0 + 0.1 + + + 0 + 2 + 5 + 6 + fill + + + + + 0 + True + True + + + + + 0 + False + True + + + + + 0 + True + True + + + + + + + + 7 + 400 + 300 + Personal data manager + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + False + + + + True + False + 0 + + + + True + GTK_BUTTONBOX_END + + + + True + True + True + gtk-close + True + GTK_RELIEF_NORMAL + -7 + + + + + + 0 + False + True + GTK_PACK_END + + + + + + 5 + True + True + True + True + GTK_POS_TOP + False + False + + + + 12 + True + False + 6 + + + + True + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + True + True + False + False + True + + + + + 0 + True + True + + + + + + True + GTK_BUTTONBOX_START + 6 + + + + True + False + True + True + gtk-remove + True + GTK_RELIEF_NORMAL + + + + + + True + False + True + True + gtk-properties + True + GTK_RELIEF_NORMAL + + + + + + 0 + False + False + + + + + False + True + + + + + + True + Cookies + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + tab + + + + + + 6 + True + False + 6 + + + + True + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + True + True + False + False + True + + + + + 0 + True + True + + + + + + True + GTK_BUTTONBOX_START + 6 + + + + True + False + True + True + gtk-remove + True + GTK_RELIEF_NORMAL + + + + + 0 + False + False + + + + + False + True + + + + + + True + Passwords + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + tab + + + + + 0 + True + True + + + + + + + + 6 + Choose the file type action + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + False + False + False + + + + True + False + 12 + + + + True + GTK_BUTTONBOX_END + + + + True + True + True + gtk-save + True + GTK_RELIEF_NORMAL + 0 + + + + + + + True + True + True + gtk-cancel + True + GTK_RELIEF_NORMAL + -6 + + + + + + + True + True + True + True + gtk-open + True + GTK_RELIEF_NORMAL + 0 + + + + + + 0 + False + True + GTK_PACK_END + + + + + + True + False + 6 + + + + True + False + 5 + + + + True + gtk-dialog-question + 6 + 0.5 + 0.5 + 0 + 0 + + + 0 + True + True + + + + + + True + False + 5 + + + + True + <span weight="bold" size="larger">What do you want to do with this file? +</span> +It's not possible to view this file type directly in the browser: + False + True + GTK_JUSTIFY_LEFT + True + False + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + False + 12 + + + + True + + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + gtk-justify-center + 4 + 0.5 + 0.5 + 0 + 0 + + + 0 + False + True + + + + + + True + DYNAMIC + False + True + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + 0 + True + True + + + + + + True + You can open it with another application or save it on disk. + False + True + GTK_JUSTIFY_LEFT + True + False + 0 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + 0 + False + False + + + + + 0 + False + False + + + + + 0 + True + True + + + + + + + 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 @@ + + + + + + + + True + window1 + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + + + + 12 + True + False + 18 + + + + True + False + 6 + + + + True + <b>Home page</b> + True + True + GTK_JUSTIFY_CENTER + False + False + 0 + 0.5 + 0 + 0 + homepage_entry + + + 0 + False + False + + + + + + True + False + 0 + + + + True + + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + False + 6 + + + + True + False + 12 + + + + True + _Location: + True + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + homepage_entry + + + 0 + False + False + + + + + + True + True + True + True + 0 + + True + * + False + + + 0 + True + True + + + + + 0 + False + False + + + + + + True + GTK_BUTTONBOX_END + 6 + + + + True + True + True + Set to _Current Page + True + GTK_RELIEF_NORMAL + + + + + + + True + True + True + Set to _Blank Page + True + GTK_RELIEF_NORMAL + + + + + + 0 + True + True + + + + + 0 + True + True + + + + + 0 + True + True + + + + + 0 + False + False + + + + + + True + False + 6 + + + + True + <b>On New Page</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + False + 0 + + + + True + + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + False + 6 + + + + True + True + Show hom_e page + True + GTK_RELIEF_NORMAL + False + False + True + + + 0 + False + False + + + + + + True + True + Show la_st page + True + GTK_RELIEF_NORMAL + False + False + True + new_page_show_homepage + + + 0 + False + False + + + + + + True + True + Show blan_k page + True + GTK_RELIEF_NORMAL + False + False + True + new_page_show_homepage + + + 0 + False + False + + + + + 0 + True + True + + + + + 0 + True + True + + + + + 0 + False + False + + + + + + True + False + 0 + + + + True + <b>Language</b> + True + True + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + 12 + True + 3 + 3 + False + 6 + 12 + + + + True + Autodetec_t encoding: + True + False + GTK_JUSTIFY_CENTER + False + False + 1 + 0.5 + 0 + 0 + autocharset_optionmenu + + + 0 + 1 + 0 + 1 + fill + + + + + + + True + _Default encoding: + True + False + GTK_JUSTIFY_CENTER + False + False + 0 + 0.5 + 0 + 0 + default_charset_optionmenu + + + 0 + 1 + 1 + 2 + fill + + + + + + + True + Lan_guage: + True + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + language_optionmenu + + + 0 + 1 + 2 + 3 + fill + + + + + + + True + True + -1 + + + 1 + 2 + 2 + 3 + fill + + + + + + + True + True + -1 + + + 1 + 2 + 1 + 2 + fill + + + + + + + True + True + 0 + + + + True + + + + True + Off + True + + + + + + True + Chinese + True + + + + + + True + East asian + True + + + + + + True + Japanese + True + + + + + + True + Korean + True + + + + + + True + Russian + True + + + + + + True + Simplified Chinese + True + + + + + + True + Traditional Chinese + True + + + + + + True + Ukrainian + True + + + + + + + 1 + 2 + 0 + 1 + + + + + + + True + gtk-select-font + 6 + 0.5 + 0.5 + 0 + 0 + + + 2 + 3 + 0 + 2 + fill + fill + + + + + + True + GTK_BUTTONBOX_DEFAULT_STYLE + 0 + + + + True + True + True + _More... + True + GTK_RELIEF_NORMAL + + + + + + 2 + 3 + 2 + 3 + fill + fill + + + + + 0 + True + True + + + + + 0 + False + False + + + + + + + + True + window2 + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + + + + 12 + True + False + 18 + + + + True + False + 6 + + + + True + <b>Fonts</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + False + 0 + + + + True + + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + 7 + 4 + False + 6 + 12 + + + + True + Siz_e: + True + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + fixed_size_spinbutton + + + 2 + 3 + 4 + 5 + fill + + + + + + + True + True + 1 + 0 + False + GTK_UPDATE_ALWAYS + False + False + 1 0 100 1 10 10 + + + 3 + 4 + 4 + 5 + + + + + + + + True + Si_ze: + True + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + variable_size_spinbutton + + + 2 + 3 + 1 + 2 + fill + + + + + + + True + True + 1 + 0 + False + GTK_UPDATE_ALWAYS + False + False + 0 0 100 1 10 10 + + + 3 + 4 + 1 + 2 + fill + + + + + + + True + _Proportional: + True + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + proportional_optionmenu + + + 0 + 1 + 1 + 2 + fill + + + + + + + True + _Serif: + True + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + combo-entry1 + + + 0 + 1 + 2 + 3 + fill + + + + + + + True + S_ans serif: + True + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + combo-entry2 + + + 0 + 1 + 3 + 4 + fill + + + + + + + True + _Monospace: + True + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + combo-entry5 + + + 0 + 1 + 4 + 5 + fill + + + + + + + True + _Language encoding: + True + False + GTK_JUSTIFY_CENTER + False + False + 0 + 0.5 + 0 + 0 + optionmenu2 + + + 0 + 1 + 0 + 1 + fill + + + + + + + True + True + 0 + + + + + True + + + + True + Western + True + + + + + + True + Central European + True + + + + + + True + Japanese + True + + + + + + True + Traditional Chinese + True + + + + + + True + Simplified Chinese + True + + + + + + True + Korean + True + + + + + + True + Cyrillic + True + + + + + + True + Baltic + True + + + + + + True + Greek + True + + + + + + True + Turkish + True + + + + + + True + Unicode + True + + + + + + True + Thai + True + + + + + + True + Hebrew + True + + + + + + True + Arabic + True + + + + + + + 1 + 2 + 0 + 1 + fill + + + + + + + True + True + 0 + + + + + + + True + Serif + True + + + + + + True + Sans Serif + True + + + + + + + 1 + 2 + 1 + 2 + + + + + + + True + False + 5 + + + + True + True + Always us_e these fonts + True + GTK_RELIEF_NORMAL + False + False + True + + + 0 + True + True + + + + + + True + Min_imum font size: + True + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + min_size_spinbutton + + + 0 + False + False + + + + + + True + True + 1 + 0 + False + GTK_UPDATE_ALWAYS + False + False + 0 0 100 1 10 10 + + + 0 + False + True + + + + + 0 + 4 + 6 + 7 + fill + + + + + + True + False + True + False + True + False + + + + True + True + False + True + 0 + + True + * + False + + + + + + True + GTK_SELECTION_BROWSE + + + + + 1 + 2 + 2 + 3 + + + + + + + True + False + True + False + True + False + + + + True + True + False + True + 0 + + True + * + False + + + + + + True + GTK_SELECTION_BROWSE + + + + + 1 + 2 + 3 + 4 + + + + + + + True + False + True + False + True + False + + + + True + True + False + True + 0 + + True + * + False + + + + + + True + GTK_SELECTION_BROWSE + + + + + 1 + 2 + 4 + 5 + + + + + + + True + + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + + + 0 + 1 + 5 + 6 + fill + + + + + + 0 + True + True + + + + + 0 + True + True + + + + + 0 + False + False + + + + + + True + False + 0 + + + + True + False + 6 + + + + True + <b>Colors</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + False + 0 + + + + True + + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + False + 6 + + + + True + False + 6 + + + + True + True + True + False + Pick the background color + + + 0 + False + False + + + + + + True + _Background + True + False + GTK_JUSTIFY_CENTER + False + False + 1 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + 0 + True + True + + + + + + True + False + 6 + + + + True + True + True + False + Pick the text color + + + 0 + False + False + + + + + + True + _Text + True + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + 0 + True + True + + + + + + True + True + Use s_ystem colors + True + GTK_RELIEF_NORMAL + False + False + True + + + 0 + False + False + + + + + + True + True + Al_ways use these colors + True + GTK_RELIEF_NORMAL + False + False + True + + + 0 + False + False + + + + + 0 + True + True + + + + + 0 + True + True + + + + + 0 + True + True + + + + + + True + False + 6 + + + + True + <b>Links</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + False + 0 + + + + True + + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + False + 6 + + + + True + False + 6 + + + + True + True + True + False + Pick the unvisited link color + + + 0 + False + False + + + + + + True + _Unvisited link + True + False + GTK_JUSTIFY_CENTER + False + False + 1 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + 0 + False + True + + + + + + True + False + 6 + + + + True + True + True + False + Pick the visited link color + + + 0 + False + False + + + + + + True + _Visited link + True + False + GTK_JUSTIFY_CENTER + False + False + 0 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + 0 + False + True + + + + + 0 + True + True + + + + + 0 + True + True + + + + + 0 + True + True + + + + + 0 + False + False + + + + + + + + True + window1 + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + + + + 12 + True + False + 18 + + + + True + False + 6 + + + + True + <b>Tabs</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + False + 0 + + + + True + + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + False + 6 + + + + True + True + _Open in tabs by default + True + GTK_RELIEF_NORMAL + False + False + True + + + 0 + False + False + + + + + + True + True + _Jump to new tabs automatically + True + GTK_RELIEF_NORMAL + False + False + True + + + 0 + False + False + + + + + + True + True + Open _popups in tabs + True + GTK_RELIEF_NORMAL + False + False + True + + + 0 + False + False + + + + + 0 + True + True + + + + + 0 + True + True + + + + + 0 + False + False + + + + + + True + False + 6 + + + + True + <b>Spinner</b> + True + True + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + False + 0 + + + + True + + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + 160 + True + True + GTK_SELECTION_SINGLE + 78 + 4 + 2 + 2 + False + False + + + + + + 0 + True + True + + + + + 0 + True + True + + + + + 0 + False + True + + + + + + + + True + window1 + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + + + + 12 + True + False + 18 + + + + True + False + 6 + + + + True + <b>Caches</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + False + 0 + + + + True + + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + 0 + False + True + + + + + + True + False + 12 + + + + True + False + 6 + + + + True + _Compare page: + True + False + GTK_JUSTIFY_CENTER + False + False + 0 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + True + Once per _session + True + GTK_RELIEF_NORMAL + False + False + True + + + 0 + False + False + + + + + + True + True + E_very time + True + GTK_RELIEF_NORMAL + False + False + True + cache_compare_radiobutton + + + 0 + False + False + + + + + + True + True + _Never + True + GTK_RELIEF_NORMAL + False + False + True + cache_compare_radiobutton + + + 0 + False + False + + + + + + True + True + _Automatically + True + GTK_RELIEF_NORMAL + False + False + True + cache_compare_radiobutton + + + 0 + False + False + + + + + 0 + True + True + + + + + + True + 2 + 4 + False + 6 + 12 + + + + True + kB + False + False + GTK_JUSTIFY_CENTER + False + False + 0 + 0.5 + 0 + 0 + + + 2 + 3 + 0 + 1 + + + + + + + + True + kB + False + False + GTK_JUSTIFY_CENTER + False + False + 0.5 + 0.5 + 0 + 0 + + + 2 + 3 + 1 + 2 + + + + + + + + True + Dis_k cache: + True + False + GTK_JUSTIFY_CENTER + False + False + 0 + 0.5 + 0 + 0 + disk_cache_spin + + + 0 + 1 + 0 + 1 + fill + + + + + + + True + Memor_y cache: + True + False + GTK_JUSTIFY_CENTER + False + False + 0 + 0.5 + 0 + 0 + memory_cache_spin + + + 0 + 1 + 1 + 2 + fill + + + + + + + True + True + 1 + 0 + False + GTK_UPDATE_ALWAYS + False + False + 1 0 1e+06 1000 10 10 + + + 1 + 2 + 1 + 2 + + + + + + + True + True + 1 + 0 + False + GTK_UPDATE_ALWAYS + False + False + 1 0 1e+06 1000 10 10 + + + 1 + 2 + 0 + 1 + + + + + + + True + True + Clear _Memory Cache + True + GTK_RELIEF_NORMAL + + + + 3 + 4 + 1 + 2 + + + + + + + + True + True + Clear _Disk Cache + True + GTK_RELIEF_NORMAL + + + + 3 + 4 + 0 + 1 + fill + + + + + + 0 + False + False + + + + + 0 + False + False + + + + + 0 + False + False + + + + + 0 + False + False + + + + + + + + True + window2 + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + + + + 12 + True + False + 18 + + + + True + False + 6 + + + + True + <b>Cookies</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + False + 0 + + + + True + + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + False + 6 + + + + True + True + _Always accept + True + GTK_RELIEF_NORMAL + False + False + True + + + 0 + False + False + + + + + + True + True + Accept _from current server only + True + GTK_RELIEF_NORMAL + False + False + True + cookies_radiobutton + + + 0 + False + False + + + + + + True + True + _Never accept + True + GTK_RELIEF_NORMAL + False + False + True + cookies_radiobutton + + + 0 + False + False + + + + + + True + True + _Warn before accepting a cookie + True + GTK_RELIEF_NORMAL + False + False + True + + + 0 + False + False + + + + + + True + True + Coo_kies expire at the end of the session + True + GTK_RELIEF_NORMAL + False + False + True + + + 0 + False + False + + + + + 0 + True + True + + + + + 0 + True + True + + + + + 0 + False + True + + + + + + True + False + 6 + + + + True + <b>Images</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + False + 0 + + + + True + + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + False + 6 + + + + True + True + _Always load + True + GTK_RELIEF_NORMAL + False + False + True + + + 0 + False + False + + + + + + True + True + _Load from current server only + True + GTK_RELIEF_NORMAL + False + False + True + images_radiobutton + + + 0 + False + False + + + + + + True + True + _Never load + True + GTK_RELIEF_NORMAL + False + False + True + images_radiobutton + + + 0 + False + False + + + + + 0 + False + False + + + + + 0 + True + True + + + + + 0 + False + False + + + + + + True + False + 6 + + + + True + <b>Others</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + False + 0 + + + + True + + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + 3 + 2 + False + 6 + 6 + + + + True + True + Allow _Java (requires plugin) + True + GTK_RELIEF_NORMAL + False + False + True + + + 0 + 1 + 1 + 2 + fill + + + + + + + True + True + Allow Java_Script + True + GTK_RELIEF_NORMAL + False + False + True + + + 0 + 1 + 2 + 3 + fill + + + + + + + True + True + Allow _popups + True + GTK_RELIEF_NORMAL + False + False + True + + + 0 + 1 + 0 + 1 + fill + + + + + + + True + True + Allow statusbar _messages + True + GTK_RELIEF_NORMAL + False + False + True + + + 1 + 2 + 0 + 1 + fill + + + + + + + True + True + _Remember passwords + True + GTK_RELIEF_NORMAL + False + False + True + + + 1 + 2 + 1 + 2 + fill + + + + + + 0 + False + False + + + + + 0 + True + True + + + + + 0 + False + False + + + + + + + + 6 + 300 + Languages editor + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + False + + + + True + False + 0 + + + + True + GTK_BUTTONBOX_END + + + + True + True + True + gtk-add + True + GTK_RELIEF_NORMAL + 0 + + + + + + True + True + True + gtk-remove + True + GTK_RELIEF_NORMAL + 0 + + + + + + True + True + True + gtk-close + True + GTK_RELIEF_NORMAL + -7 + + + + + + 0 + False + True + GTK_PACK_END + + + + + + 6 + True + False + 6 + + + + True + False + 6 + + + + True + Language + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + True + -1 + + + 0 + True + True + + + + + 0 + False + True + + + + + + True + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + True + True + False + False + True + + + + + 0 + True + True + + + + + 0 + True + True + + + + + + + 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 @@ + + + + + + + + 7 + True + Print + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + False + + + + True + False + 6 + + + + True + GTK_BUTTONBOX_END + + + + True + True + True + gtk-print-preview + True + GTK_RELIEF_NORMAL + 50 + + + + + + + True + True + True + gtk-cancel + True + GTK_RELIEF_NORMAL + -6 + + + + + + + True + True + True + True + gtk-print + True + GTK_RELIEF_NORMAL + -5 + + + + + + 0 + False + True + GTK_PACK_END + + + + + + 5 + True + True + True + True + GTK_POS_TOP + False + 2 + 2 + False + + + + 12 + True + False + 18 + + + + True + False + 6 + + + + True + <b>Printer</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + False + 0 + + + + True + + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + 2 + 2 + False + 6 + 12 + + + + True + True + _Printer + True + GTK_RELIEF_NORMAL + False + False + True + + + 0 + 1 + 0 + 1 + fill + + + + + + + True + True + _File + True + GTK_RELIEF_NORMAL + False + False + True + printer_radiobutton + + + 0 + 1 + 1 + 2 + fill + + + + + + + True + True + True + True + 0 + lpr + True + * + False + + + 1 + 2 + 0 + 1 + + + + + + + True + 10 + Choose a file to print to + False + False + + + + True + True + True + True + 0 + + True + * + False + + + + + 1 + 2 + 1 + 2 + + + + + + 0 + False + False + + + + + 0 + True + True + + + + + 0 + False + False + + + + + + True + False + 6 + + + + True + <b>Pages range</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + False + 0 + + + + True + + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + 3 + 2 + False + 6 + 6 + + + + True + True + _All pages + True + GTK_RELIEF_NORMAL + False + False + True + + + 0 + 1 + 0 + 1 + fill + + + + + + + True + True + Pa_ges + True + GTK_RELIEF_NORMAL + False + False + True + all_pages_radiobutton + + + 0 + 1 + 2 + 3 + fill + + + + + + + True + False + 5 + + + + True + from: + False + False + GTK_JUSTIFY_CENTER + False + False + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + True + 1 + 0 + False + GTK_UPDATE_ALWAYS + False + False + 1 0 100 1 10 10 + + + 0 + False + True + + + + + + True + to: + False + False + GTK_JUSTIFY_CENTER + False + False + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + True + 1 + 0 + False + GTK_UPDATE_ALWAYS + False + False + 1 0 100 1 10 10 + + + 0 + False + True + + + + + 1 + 2 + 2 + 3 + fill + + + + + + True + True + _Selection + True + GTK_RELIEF_NORMAL + False + False + True + all_pages_radiobutton + + + 0 + 1 + 1 + 2 + fill + + + + + + 0 + True + True + + + + + 0 + True + True + + + + + 0 + False + True + + + + + False + True + + + + + + True + General + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + tab + + + + + + 12 + True + False + 18 + + + + True + False + 6 + + + + True + <b>Size</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + False + 0 + + + + True + + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + True + 6 + + + + True + True + _Letter (8.5" x 11") + True + GTK_RELIEF_NORMAL + False + False + True + + + 0 + False + False + + + + + + True + True + L_egal (8.5" x 14") + True + GTK_RELIEF_NORMAL + False + False + True + letter_radiobutton + + + 0 + False + False + + + + + + True + True + E_xecutive (7.25" x 10.5") + True + GTK_RELIEF_NORMAL + False + False + True + letter_radiobutton + + + 0 + False + False + + + + + + True + True + A_4 (8.27" x 11.69") + True + GTK_RELIEF_NORMAL + True + False + True + letter_radiobutton + + + 0 + False + False + + + + + 0 + True + True + + + + + + True + gtk-dnd + 6 + 0.5 + 0.5 + 0 + 0 + + + 0 + True + True + + + + + 0 + True + True + + + + + 0 + False + False + + + + + + True + False + 6 + + + + True + <b>Orientation</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + False + 0 + + + + True + + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + False + 0 + + + + True + True + P_ortrait + True + GTK_RELIEF_NORMAL + False + False + True + + + 0 + False + False + + + + + + True + True + Lan_dscape + True + GTK_RELIEF_NORMAL + False + False + True + orient_p_radiobutton + + + 0 + False + False + + + + + 0 + True + True + + + + + 0 + True + True + + + + + 0 + False + False + + + + + False + True + + + + + + True + Paper Details + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + tab + + + + + + 12 + True + False + 18 + + + + True + False + 18 + + + + True + False + 6 + + + + True + <b>Margins (inches)</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + False + 0 + + + + True + + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + 4 + 2 + False + 6 + 6 + + + + True + _Bottom + True + False + GTK_JUSTIFY_CENTER + False + False + 0 + 0.5 + 0 + 0 + bottom_spinbutton + + + 0 + 1 + 1 + 2 + fill + + + + + + + True + Le_ft + True + False + GTK_JUSTIFY_CENTER + False + False + 0 + 0.5 + 0 + 0 + left_spinbutton + + + 0 + 1 + 2 + 3 + fill + + + + + + + True + _Right + True + False + GTK_JUSTIFY_CENTER + False + False + 0 + 0.5 + 0 + 0 + right_spinbutton + + + 0 + 1 + 3 + 4 + fill + + + + + + + True + _Top + True + False + GTK_JUSTIFY_CENTER + False + False + 0 + 0.5 + 0 + 0 + top_spinbutton + + + 0 + 1 + 0 + 1 + fill + + + + + + + True + True + 0.1 + 1 + True + GTK_UPDATE_ALWAYS + False + False + 0.6 0 100 0.1 10 10 + + + 1 + 2 + 1 + 2 + + + + + + + True + True + 0.1 + 1 + True + GTK_UPDATE_ALWAYS + False + False + 0.5 0 100 0.1 10 10 + + + 1 + 2 + 2 + 3 + + + + + + + True + True + 0.1 + 1 + True + GTK_UPDATE_ALWAYS + False + False + 0.3 0 100 0.1 10 10 + + + 1 + 2 + 0 + 1 + + + + + + + True + True + 0.1 + 1 + True + GTK_UPDATE_ALWAYS + False + False + 0.5 0 100 0.1 10 10 + + + 1 + 2 + 3 + 4 + + + + + + 0 + False + False + + + + + 0 + True + True + + + + + 0 + False + False + + + + + + True + False + 6 + + + + True + <b>Colors</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + False + 0 + + + + True + + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + False + 6 + + + + True + True + _Color + True + GTK_RELIEF_NORMAL + False + False + True + + + 0 + False + False + + + + + + True + True + G_rayscale + True + GTK_RELIEF_NORMAL + False + False + True + print_color_radiobutton + + + 0 + False + False + + + + + + True + gtk-select-color + 6 + 0.5 + 0.5 + 0 + 0 + + + 0 + True + True + + + + + 0 + False + False + + + + + 0 + True + True + + + + + 0 + True + False + + + + + 0 + False + True + + + + + + True + False + 0 + + + + True + False + 6 + + + + True + <b>Footers</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + False + 0 + + + + True + + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + False + 6 + + + + True + True + Page nu_mbers + True + GTK_RELIEF_NORMAL + False + False + True + + + 0 + False + False + + + + + + True + True + _Date + True + GTK_RELIEF_NORMAL + False + False + True + + + 0 + False + False + + + + + 0 + True + True + + + + + 0 + False + False + + + + + 0 + True + True + + + + + + True + False + 6 + + + + True + <b>Headers</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + False + 0 + + + + True + + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + False + 6 + + + + True + True + P_age Title + True + GTK_RELIEF_NORMAL + False + False + True + + + 0 + False + False + + + + + + True + True + Page _URL + True + GTK_RELIEF_NORMAL + False + False + True + + + 0 + False + False + + + + + 0 + False + False + + + + + 0 + True + True + + + + + 0 + True + True + + + + + 0 + True + True + + + + + False + True + + + + + + True + Appearance + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + tab + + + + + 0 + True + True + + + + + + + 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 @@ + + + + + + + 6 + + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + 350 + True + False + False + + + + True + False + 8 + + + + True + GTK_BUTTONBOX_END + + + + True + True + True + gtk-cancel + True + GTK_RELIEF_NORMAL + -6 + + + + + + True + True + True + True + gtk-ok + True + GTK_RELIEF_NORMAL + -5 + + + + + 0 + False + True + GTK_PACK_END + + + + + + 6 + True + 4 + 3 + False + 6 + 12 + + + + True + True + DYNAMIC + True + GTK_RELIEF_NORMAL + False + False + True + + + 2 + 3 + 3 + 4 + fill + + + + + + + True + True + True + False + 0 + + True + * + True + + + 2 + 3 + 2 + 3 + + + + + + + True + True + True + True + True + 0 + + True + * + True + + + 2 + 3 + 1 + 2 + + + + + + + True + Password + False + False + GTK_JUSTIFY_CENTER + False + False + 1 + 0.5 + 0 + 0 + + + 1 + 2 + 2 + 3 + fill + + + + + + + True + Username + False + False + GTK_JUSTIFY_CENTER + False + False + 1 + 0.5 + 0 + 0 + + + 1 + 2 + 1 + 2 + fill + + + + + + + True + DYNAMIC + False + False + GTK_JUSTIFY_FILL + False + False + 0 + 0.5 + 0 + 0 + + + 1 + 3 + 0 + 1 + + + + + + True + gtk-dialog-question + 6 + 0.5 + 0.5 + 0 + 0 + + + 0 + 1 + 0 + 3 + fill + fill + + + + + 0 + True + True + + + + + + + + 6 + + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + 350 + True + False + False + + + + True + False + 8 + + + + True + GTK_BUTTONBOX_END + + + + True + True + True + gtk-cancel + True + GTK_RELIEF_NORMAL + -6 + + + + + + True + True + True + True + gtk-ok + True + GTK_RELIEF_NORMAL + -5 + + + + + 0 + False + True + GTK_PACK_END + + + + + + 6 + True + 2 + 3 + False + 6 + 12 + + + + True + True + True + True + True + True + 0 + + True + * + True + + + 2 + 3 + 0 + 1 + fill + + + + + + True + DYNAMIC + False + False + GTK_JUSTIFY_CENTER + False + False + 1 + 0.5 + 0 + 0 + + + 1 + 2 + 0 + 1 + fill + + + + + + True + True + DYNAMIC + True + GTK_RELIEF_NORMAL + False + False + True + + + 2 + 3 + 1 + 2 + expand + + + + + + True + gtk-dialog-question + 6 + 0.5 + 0.5 + 0 + 0 + + + 0 + 1 + 0 + 1 + fill + fill + + + + + 0 + True + True + + + + + + + + 6 + + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + 350 + True + False + False + + + + True + False + 8 + + + + True + GTK_BUTTONBOX_END + + + + True + True + True + gtk-cancel + True + GTK_RELIEF_NORMAL + -6 + + + + + + True + True + True + True + gtk-ok + True + GTK_RELIEF_NORMAL + -5 + + + + + 0 + False + True + GTK_PACK_END + + + + + + True + DYNAMIC + False + False + GTK_JUSTIFY_FILL + False + False + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + 6 + True + 2 + 3 + False + 6 + 12 + + + + True + Password + False + False + GTK_JUSTIFY_CENTER + False + False + 1 + 0.5 + 0 + 0 + + + 1 + 2 + 0 + 1 + fill + + + + + + True + True + DYNAMIC + True + GTK_RELIEF_NORMAL + False + False + True + + + 2 + 3 + 1 + 2 + expand + + + + + + True + gtk-dialog-question + 6 + 0.5 + 0.5 + 0 + 0 + + + 0 + 1 + 0 + 1 + fill + fill + + + + + + True + True + True + True + False + 0 + + True + * + True + + + 2 + 3 + 0 + 1 + fill + + + + + 0 + True + True + + + + + + + + 6 + + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + False + + + + True + False + 8 + + + + True + GTK_BUTTONBOX_END + + + + True + True + True + gtk-cancel + True + GTK_RELIEF_NORMAL + -6 + + + + + + True + True + True + True + gtk-ok + True + GTK_RELIEF_NORMAL + -5 + + + + + 0 + False + True + GTK_PACK_END + + + + + + 6 + True + 2 + 2 + False + 6 + 12 + + + + True + DYNAMIC + False + False + GTK_JUSTIFY_FILL + True + False + 7.45058e-09 + 0.5 + 0 + 0 + + + 1 + 2 + 0 + 1 + fill + + + + + + True + gtk-dialog-question + 6 + 0.5 + 0.5 + 0 + 0 + + + 0 + 1 + 0 + 2 + fill + shrink|fill + + + + + + True + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_NONE + GTK_CORNER_TOP_LEFT + + + + True + True + True + False + False + True + + + + + 1 + 2 + 1 + 2 + + + + + 0 + True + True + + + + + + + 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 @@ + + + + + + + 6 + True + Toolbar Editor + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + False + + + + 450 + 350 + True + False + 0 + + + + True + GTK_BUTTONBOX_END + + + + True + True + GTK_RELIEF_NORMAL + 0 + + + + True + 0.5 + 0.5 + 0 + 0 + + + + True + False + 2 + + + + True + gtk-revert-to-saved + 4 + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + _Reset to defaults + True + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + + + + + + + True + True + gtk-undo + True + GTK_RELIEF_NORMAL + 0 + + + + + + True + True + True + gtk-close + True + GTK_RELIEF_NORMAL + 0 + + + + + 0 + False + True + GTK_PACK_END + + + + + + 6 + True + False + 6 + + + + True + False + 6 + + + + True + <b>_Available Controls</b> + True + True + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + True + False + False + False + True + + + + + 0 + True + True + + + + + 0 + True + True + + + + + + True + False + 0 + + + + + + + + True + 3 + 3 + False + 0 + 0 + + + + True + False + True + GTK_RELIEF_NONE + + + + True + GTK_ARROW_UP + GTK_SHADOW_OUT + 0.5 + 0.5 + 0 + 0 + + + + + 1 + 2 + 0 + 1 + + + + + + + + True + False + True + GTK_RELIEF_NONE + + + + True + GTK_ARROW_RIGHT + GTK_SHADOW_OUT + 0.5 + 0.5 + 0 + 0 + + + + + 2 + 3 + 1 + 2 + + + + + + + + True + False + True + GTK_RELIEF_NONE + + + + True + GTK_ARROW_DOWN + GTK_SHADOW_OUT + 0.5 + 0.5 + 0 + 0 + + + + + 1 + 2 + 2 + 3 + + + + + + + + True + False + True + GTK_RELIEF_NONE + + + + True + GTK_ARROW_LEFT + GTK_SHADOW_OUT + 0.5 + 0.5 + 0 + 0 + + + + + 0 + 1 + 1 + 2 + + + + + + + 0 + True + False + + + + + + + + + 4 + False + False + + + + + + True + False + 6 + + + + True + <b>Cu_rrent Controls</b> + True + True + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + True + False + False + False + True + + + + + 0 + True + True + + + + + 0 + True + True + + + + + 0 + True + True + + + + + + + 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 @@ + + + + +

Welcome ...

+

Smart Bookmarks

+

+Right click the icon and choose "Add Bookmark" from the menu list. +

+
+
  • + +Search the web - Google + +
  • +
  • + +Search images - Google + +
  • + + + 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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 +#include +#include +#include +#include +#include +#include +#include + +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 +#include + +#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 +#include +#include + +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 +#include +#include + +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 +#include + +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 + * + * 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 + +#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 +#include +#include + +#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 + +#include "ephy-embed-persist.h" + +#include "mozilla-embed.h" +#include "mozilla-embed-persist.h" + +#include + +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 +#include + +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 + +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 + +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 + +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 + +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 +#include +#include +#include + +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 +#include + +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 + +#include "ephy-embed-shell.h" +#include "ephy-marshal.h" +#include "ephy-favicon-cache.h" + +#include "mozilla-embed-shell.h" + +#include + +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 +#include + +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 +#include +#include +#include +#include +#include + +/** + * 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 ("\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 ("\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 + * @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, ""); + + 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, ""); + group_index++; + } + + g_string_append (xml_string, ""); + + 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 +#include + +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 +#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 +#include +#include + +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 + * + * 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 +#include +#include +#include +#include +#include + +#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 +#include + +#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 + * + * 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 +#include + +#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 +#include +#include + +#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 +#include +#include +#include + +//#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 + +#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 +#include + +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 sStream; + nsresult rv = NS_NewStorageStream(1, 16, getter_AddRefs(sStream)); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr oStream; + rv = sStream->GetOutputStream(0, getter_AddRefs(oStream)); + + PRUint32 bytes; + oStream->Write("Dummy stream\0", 13, &bytes); + + nsCOMPtr iStream; + rv = sStream->NewInputStream(0, getter_AddRefs(iStream)); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr 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 channel = do_QueryInterface(aRequest); + if(!channel) return NS_ERROR_FAILURE; + + nsCOMPtr uri; + rv = channel->GetURI(getter_AddRefs(uri)); + if (NS_FAILED(rv)) return rv; + + aRequest->Cancel(NS_BINDING_ABORTED); + if (uri) + { + nsCOMPtr 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 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 +#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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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 windowInternal = + do_QueryInterface (aWindowContext); + + nsCOMPtr 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 saveFile (do_CreateInstance(NS_LOCAL_FILE_CONTRACTID)); + + PRInt16 okToSave = nsIFilePicker::returnCancel; + + if (okToSave == nsIFilePicker::returnCancel) + { + nsCOMPtr 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 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 helperService = + do_GetService (NS_EXTERNALHELPERAPPSERVICE_CONTRACTID); + + nsCOMPtr 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 mimeInfo; + rv = mLauncher->GetMIMEInfo(getter_AddRefs(mimeInfo)); + if(NS_FAILED(rv)) return NS_ERROR_FAILURE; + + nsCOMPtr 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 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 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 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 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, "%s", 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 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 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 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 +#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 mLauncher; + nsCOMPtr mContext; + + nsCOMPtr mUri; + PRInt64 mTimeDownloadStarted; + nsCOMPtr mTempFile; + + char *mMimeType; + PRBool mUrlHelper; + GnomeVFSMimeApplication *mHelperApp; + + nsCString mUrl; + nsCString mScheme; + + PRBool mDownloadCanceled; + PRBool mHelperProgress; + + nsCOMPtr 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 + +#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 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 domDoc; + result = node->GetOwnerDocument(getter_AddRefs(domDoc)); + if (NS_FAILED(result) || !domDoc) return NS_ERROR_FAILURE; + + nsCOMPtr doc = do_QueryInterface (domDoc); + if(!doc) return NS_ERROR_FAILURE; + + nsCOMPtr 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 eventTarget; + + aDOMEvent->GetTarget(getter_AddRefs(eventTarget)); + + nsresult result; + nsCOMPtr 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 + +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 +#include + +#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 DocShell; + result = GetDocShell (getter_AddRefs(DocShell)); + if (NS_FAILED(result) || !DocShell) return NS_ERROR_FAILURE; + + nsCOMPtr dsHistory = do_QueryInterface (DocShell); + if (!dsHistory) return NS_ERROR_FAILURE; + + static NS_DEFINE_CID(kGlobalHistoryCID, GALEON_GLOBALHISTORY_CID); + + nsCOMPtr 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 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 domWindowExternal; + mWebBrowser->GetContentDOMWindow(getter_AddRefs(domWindowExternal)); + + nsCOMPtr domWindow; + domWindow = do_QueryInterface(domWindowExternal); + + nsCOMPtr piWin(do_QueryInterface(domWindow)); + if (!piWin) return; + + nsCOMPtr chromeHandler; + piWin->GetChromeEventHandler(getter_AddRefs(chromeHandler)); + + mEventReceiver = do_QueryInterface(chromeHandler); +} + +void +EphyWrapper::AttachListeners(void) +{ + if (!mEventReceiver || mListenersAttached) + return; + + nsCOMPtr 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 target; + target = do_QueryInterface (mEventReceiver); + + target->RemoveEventListener(NS_LITERAL_STRING("DOMLinkAdded"), mEventListener, PR_FALSE); +} + +nsresult EphyWrapper::GetDocShell (nsIDocShell **aDocShell) +{ + nsCOMPtr browserAsItem; + browserAsItem = do_QueryInterface(mWebBrowser); + if (!browserAsItem) return NS_ERROR_FAILURE; + + // get the owner for that item + nsCOMPtr treeOwner; + browserAsItem->GetTreeOwner(getter_AddRefs(treeOwner)); + if (!treeOwner) return NS_ERROR_FAILURE; + + // get the primary content shell as an item + nsCOMPtr contentItem; + treeOwner->GetPrimaryContentShell(getter_AddRefs(contentItem)); + if (!contentItem) return NS_ERROR_FAILURE; + + // QI that back to a docshell + nsCOMPtr 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 print(do_GetInterface(mWebBrowser, &result)); + if (NS_FAILED(result) || !print) return NS_ERROR_FAILURE; + + nsCOMPtr 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 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 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 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 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 DocShell; + result = GetDocShell (getter_AddRefs(DocShell)); + if (NS_FAILED(result) || !DocShell) return NS_ERROR_FAILURE; + + nsCOMPtr ContentNav = do_QueryInterface (DocShell, + &result); + if (!ContentNav) return NS_ERROR_FAILURE; + + nsCOMPtr 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 DocShell; + result = GetDocShell (getter_AddRefs(DocShell)); + if (NS_FAILED(result) || !DocShell) return NS_ERROR_FAILURE; + + nsCOMPtr 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 DocShell; + result = GetDocShell (getter_AddRefs(DocShell)); + if (NS_FAILED(result) || !DocShell) return NS_ERROR_FAILURE; + + if (reflow) + { + nsCOMPtr contentViewer; + result = DocShell->GetContentViewer (getter_AddRefs(contentViewer)); + if (!NS_SUCCEEDED (result) || !contentViewer) return NS_ERROR_FAILURE; + + nsCOMPtr mdv = do_QueryInterface(contentViewer, + &result); + if (NS_FAILED(result) || !mdv) return NS_ERROR_FAILURE; + + return mdv->SetTextZoom (aZoom); + } + else + { + SetZoomOnDocshell (aZoom, DocShell); + + nsCOMPtr docShellNode(do_QueryInterface(DocShell)); + if (docShellNode) + { + PRInt32 i; + PRInt32 n; + docShellNode->GetChildCount(&n); + for (i=0; i < n; i++) + { + nsCOMPtr child; + docShellNode->GetChildAt(i, getter_AddRefs(child)); + nsCOMPtr childAsShell(do_QueryInterface(child)); + if (childAsShell) + { + return SetZoomOnDocshell (aZoom, childAsShell); + } + } + } + } + + return NS_OK; +} + +nsresult EphyWrapper::SetZoomOnDocshell (float aZoom, nsIDocShell *DocShell) +{ + nsresult result; + + nsCOMPtr PresContext; + result = DocShell->GetPresContext (getter_AddRefs(PresContext)); + if (NS_FAILED(result)) return NS_ERROR_FAILURE; + + nsCOMPtr DeviceContext; + result = PresContext->GetDeviceContext (getter_AddRefs(DeviceContext)); + + return DeviceContext->SetTextZoom (aZoom); +} + +nsresult EphyWrapper::GetZoom (float *aZoom) +{ + nsresult result; + + nsCOMPtr DocShell; + result = GetDocShell (getter_AddRefs(DocShell)); + if (NS_FAILED(result) || !DocShell) return NS_ERROR_FAILURE; + + nsCOMPtr contentViewer; + result = DocShell->GetContentViewer (getter_AddRefs(contentViewer)); + if (!NS_SUCCEEDED (result) || !contentViewer) return NS_ERROR_FAILURE; + + nsCOMPtr 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 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 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 DocShell; + result = GetDocShell (getter_AddRefs(DocShell)); + if (NS_FAILED(result) || !DocShell) return NS_ERROR_FAILURE; + + nsCOMPtr 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 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 SessionHistory; + result = GetSHistory (getter_AddRefs(SessionHistory)); + if (NS_FAILED(result) || ! SessionHistory) return NS_ERROR_FAILURE; + + nsCOMPtr 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 SessionHistory; + result = GetSHistory (getter_AddRefs(SessionHistory)); + if (NS_FAILED(result) || ! SessionHistory) return NS_ERROR_FAILURE; + + nsCOMPtr he; + result = SessionHistory->GetEntryAtIndex (index, PR_FALSE, + getter_AddRefs (he)); + if (NS_FAILED(result) || (!he)) return NS_ERROR_FAILURE; + + nsCOMPtr 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 tAFinder + (do_GetService(NS_TYPEAHEADFIND_CONTRACTID, &rv)); + if (NS_SUCCEEDED(rv)) + { + nsCOMPtr aFocusedWindow; + rv = GetFocusedDOMWindow(getter_AddRefs(aFocusedWindow)); + if (NS_SUCCEEDED(rv)) + { + nsSupportsInterfacePointerImpl windowPtr; + windowPtr.SetData(aFocusedWindow); + + tAFinder->FindNext(search_backwards, &windowPtr); + + nsCOMPtr retValue; + rv = windowPtr.GetData(getter_AddRefs(retValue)); + if (NS_SUCCEEDED(rv) && !retValue) + { + *didFind = PR_TRUE; + return NS_OK; + } + } + } + + } + + nsCOMPtr 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 DOMWindow; + result = GetFocusedDOMWindow (getter_AddRefs(DOMWindow)); + if (NS_FAILED(result) || !DOMWindow) return NS_ERROR_FAILURE; + + nsCOMPtr scriptGlobal = do_QueryInterface(DOMWindow); + if (!scriptGlobal) return NS_ERROR_FAILURE; + + nsCOMPtr docshell; + if (NS_FAILED(scriptGlobal->GetDocShell(getter_AddRefs(docshell)))) + return NS_ERROR_FAILURE; + + nsCOMPtr 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 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 wn; + rv = GetWebNavigation(getter_AddRefs(wn)); + if (!wn || !NS_SUCCEEDED(rv)) return NS_ERROR_FAILURE; + + nsCOMPtr 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 wn; + rv = GetWebNavigation(getter_AddRefs(wn)); + if (!wn || !NS_SUCCEEDED(rv)) return NS_ERROR_FAILURE; + + nsCOMPtr 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 DOMDocument; + + result = GetMainDOMDocument (getter_AddRefs(DOMDocument)); + if (NS_FAILED(result) || !DOMDocument) return NS_ERROR_FAILURE; + + nsCOMPtr doc = do_QueryInterface(DOMDocument); + if(!doc) return NS_ERROR_FAILURE; + + nsCOMPtr uri; + doc->GetDocumentURL(getter_AddRefs(uri)); + + return uri->GetSpec (url); +} + +nsresult EphyWrapper::GetDocumentUrl (nsCString &url) +{ + nsresult result; + + nsCOMPtr DOMDocument; + + result = GetDOMDocument (getter_AddRefs(DOMDocument)); + if (NS_FAILED(result) || !DOMDocument) return NS_ERROR_FAILURE; + + nsCOMPtr doc = do_QueryInterface(DOMDocument); + if(!doc) return NS_ERROR_FAILURE; + + nsCOMPtr uri; + doc->GetDocumentURL(getter_AddRefs(uri)); + + uri->GetSpec (url); + + return NS_OK; +} + +nsresult EphyWrapper::GetDocumentTitle (char **title) +{ + nsresult result; + + nsCOMPtr DOMDocument; + + result = GetDOMDocument (getter_AddRefs(DOMDocument)); + if (NS_FAILED(result) || !DOMDocument) return NS_ERROR_FAILURE; + + nsCOMPtr 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 DocShell; + result = GetDocShell (getter_AddRefs(DocShell)); + if (NS_FAILED(result) || !DocShell) return NS_ERROR_FAILURE; + + nsCOMPtr wn_src = do_QueryInterface (DocShell, + &result); + if (!wn_src) return NS_ERROR_FAILURE; + + nsCOMPtr h_src; + result = wn_src->GetSessionHistory (getter_AddRefs (h_src)); + if (!NS_SUCCEEDED(result) || (!h_src)) return NS_ERROR_FAILURE; + + nsCOMPtr destDocShell; + result = dest->GetDocShell (getter_AddRefs(destDocShell)); + if (NS_FAILED(result) || !DocShell) return NS_ERROR_FAILURE; + + nsCOMPtr wn_dest = do_QueryInterface (destDocShell, + &result); + if (!wn_dest) return NS_ERROR_FAILURE; + + nsCOMPtr h_dest; + result = wn_dest->GetSessionHistory (getter_AddRefs (h_dest)); + if (!NS_SUCCEEDED (result) || (!h_dest)) return NS_ERROR_FAILURE; + + nsCOMPtr hi_dest = do_QueryInterface (h_dest); + if (!hi_dest) return NS_ERROR_FAILURE; + + h_src->GetCount (&count); + h_src->GetIndex (&index); + + if (count) { + nsCOMPtr he; + nsCOMPtr 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 DocShell; + result = GetDocShell (getter_AddRefs(DocShell)); + if (NS_FAILED(result) || !DocShell) return NS_ERROR_FAILURE; + + nsCOMPtr contentViewer; + result = DocShell->GetContentViewer (getter_AddRefs(contentViewer)); + if (!NS_SUCCEEDED (result) || !contentViewer) return NS_ERROR_FAILURE; + + nsCOMPtr 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 clipboard (do_GetInterface(mWebBrowser)); + return clipboard->CanCutSelection (result); +} + +nsresult EphyWrapper::CanCopySelection(PRBool *result) +{ + nsCOMPtr clipboard (do_GetInterface(mWebBrowser)); + return clipboard->CanCopySelection (result); +} + +nsresult EphyWrapper::CanPaste(PRBool *result) +{ + nsCOMPtr clipboard (do_GetInterface(mWebBrowser)); + return clipboard->CanPaste (result); +} + +nsresult EphyWrapper::CutSelection(void) +{ + nsCOMPtr clipboard (do_GetInterface(mWebBrowser)); + return clipboard->CutSelection (); +} + +nsresult EphyWrapper::CopySelection(void) +{ + nsCOMPtr clipboard (do_GetInterface(mWebBrowser)); + return clipboard->CopySelection (); +} + +nsresult EphyWrapper::Paste(void) +{ + nsCOMPtr 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 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 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 link; + result = links->Item (i, getter_AddRefs (link)); + if (NS_FAILED (result)) return NS_ERROR_FAILURE; + + nsCOMPtr 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 doc = + do_QueryInterface (aDOMDocument); + if(!doc) return NS_ERROR_FAILURE; + + nsCOMPtr 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 DocShell; + result = GetDocShell (getter_AddRefs(DocShell)); + if (NS_FAILED(result) || !DocShell) return NS_ERROR_FAILURE; + + nsCOMPtr ContentNav = do_QueryInterface (DocShell, + &result); + if (!ContentNav) return NS_ERROR_FAILURE; + + nsCOMPtr 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 clipboard (do_GetInterface(mWebBrowser)); + return clipboard->SelectAll (); +} + +nsresult EphyWrapper::ScrollUp (void) +{ + nsresult result; + + nsCOMPtr 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 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 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 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 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 DOMDocument; + + result = GetDOMDocument (getter_AddRefs(DOMDocument)); + if (NS_FAILED(result) || !DOMDocument) return NS_ERROR_FAILURE; + + nsCOMPtr 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 DOMDocument; + + result = GetDOMDocument (getter_AddRefs(DOMDocument)); + if (NS_FAILED(result) || !DOMDocument) return NS_ERROR_FAILURE; + + nsCOMPtr doc = do_QueryInterface(DOMDocument); + if(!doc) return NS_ERROR_FAILURE; + + nsCOMPtr col; + doc->GetImages(getter_AddRefs(col)); + + PRUint32 count, i; + col->GetLength(&count); + for (i = 0; i < count; i++) + { + nsCOMPtr node; + col->Item(i, getter_AddRefs(node)); + if (!node) continue; + + nsCOMPtr element; + element = do_QueryInterface(node); + if (!element) continue; + + nsCOMPtr 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 DOMDocument; + + result = GetDOMDocument (getter_AddRefs(DOMDocument)); + if (NS_FAILED(result) || !DOMDocument) return NS_ERROR_FAILURE; + + nsCOMPtr doc = do_QueryInterface(DOMDocument); + if(!doc) return NS_ERROR_FAILURE; + + nsCOMPtr col; + doc->GetForms(getter_AddRefs(col)); + + PRUint32 count, i; + col->GetLength(&count); + for (i = 0; i < count; i++) + { + nsCOMPtr node; + col->Item(i, getter_AddRefs(node)); + if (!node) continue; + + nsCOMPtr element; + element = do_QueryInterface(node); + if (!element) continue; + + nsCOMPtr 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 doc = + do_QueryInterface (aDOMDocument); + if(!doc) return NS_ERROR_FAILURE; + + nsCOMPtr 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 DOMDocument; + result = GetMainDOMDocument (getter_AddRefs(DOMDocument)); + if (NS_FAILED(result) || !DOMDocument) return NS_ERROR_FAILURE; + + /* first, get a list of elements */ + PRUint32 links_count; + + NS_NAMED_LITERAL_STRING(strname, "LINK"); + + nsCOMPtr 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 link; + result = links->Item (i, getter_AddRefs (link)); + if (NS_FAILED (result)) continue; + + nsCOMPtr 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 doc = + do_QueryInterface (aDOMDocument); + if(!doc) continue; + + nsCOMPtr 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 doc = do_QueryInterface(aDOMDocument); + if(!doc) return NS_ERROR_FAILURE; + + nsCOMPtr col; + doc->GetLinks(getter_AddRefs(col)); + + PRUint32 count, i; + col->GetLength(&count); + for (i = 0; i < count; i++) + { + nsCOMPtr node; + col->Item(i, getter_AddRefs(node)); + if (!node) continue; + + nsCOMPtr element; + element = do_QueryInterface(node); + if (!element) continue; + + nsCOMPtr 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 DOMWindow; + rv = mWebBrowser->GetContentDOMWindow(getter_AddRefs(DOMWindow)); + + nsCOMPtr globalObject; + globalObject = do_QueryInterface (DOMWindow); + if (!globalObject) return NS_ERROR_FAILURE; + + nsCOMPtr 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 + +#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 mWebBrowser; + + nsCOMPtr mChromeNav; + + GtkMozEmbed *mGtkMozEmbed; +private: + nsCOMPtr mTargetDocument; + nsCOMPtr mProgress; + nsCOMPtr 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 +#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 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 domDoc; + rv = node->GetOwnerDocument(getter_AddRefs(domDoc)); + if (NS_FAILED(rv) || !domDoc) return NS_ERROR_FAILURE; + + mDOMDocument = domDoc; + + nsCOMPtr doc = do_QueryInterface(domDoc, &rv); + if (NS_FAILED(rv) || !doc) return NS_ERROR_FAILURE; + + nsCOMPtr 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 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 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 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 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 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 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 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 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 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 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 childNode; + node->GetFirstChild (getter_AddRefs(childNode)); + if (childNode) + { + nsCOMPtr 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 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 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 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 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 parentNode; + node->GetParentNode (getter_AddRefs(parentNode)); + node = parentNode; + } + + return NS_OK; +} + +nsresult EventContext::GetCSSBackground (nsIDOMNode *node, nsAutoString& url) +{ + nsresult result; + + nsCOMPtr style; + style = do_QueryInterface (node); + if (!style) return NS_ERROR_FAILURE; + + nsCOMPtr 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 nsEvent = do_QueryInterface(aMouseEvent, &result); + if (NS_FAILED(result) || !nsEvent) return NS_ERROR_FAILURE; + + nsCOMPtr OriginalTarget; + result = nsEvent->GetOriginalTarget(getter_AddRefs(OriginalTarget)); + if (NS_FAILED(result) || !OriginalTarget) return NS_ERROR_FAILURE; + + nsCOMPtr 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 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 mainDocument; + result = mWrapper->GetMainDOMDocument (getter_AddRefs(mainDocument)); + if (NS_FAILED(result) || !mainDocument) return NS_ERROR_FAILURE; + + nsCOMPtr 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 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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#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 ww; + ww = do_GetService(WINDOWWATCHER_CONTRACTID, &rv); + if (NS_SUCCEEDED(rv)) + { + nsCOMPtr 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 + +#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 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 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 +#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 mParent; + + nsCString mTitle; + nsCString mFilter; + nsCString mDefaultString; + + nsCOMPtr mFile; + nsCOMPtr 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=\ + +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 +#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 +#include +#include +#include + +#include + +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 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 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 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 + +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 +#include +#include +#include +#include + +GtkWidget *MozillaFindGtkParent (nsIDOMWindow *aDOMWindow) +{ + nsresult result; + + nsCOMPtr wwatch + (do_GetService("@mozilla.org/embedcomp/window-watcher;1")); + if (!wwatch) return nsnull; + + nsCOMPtr domWindow(aDOMWindow); + if (!domWindow) + { + result = wwatch->GetActiveWindow(getter_AddRefs(domWindow)); + if (NS_FAILED(result) || !domWindow) return nsnull; + } + + nsCOMPtr windowChrome; + result = wwatch->GetChromeForWindow (domWindow, + getter_AddRefs(windowChrome)); + if (NS_FAILED(result)) return nsnull; + + nsCOMPtr 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 +#include + +#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 + +#include + +#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 +#endif + +#include + +#include "print-dialog.h" +#include "ephy-embed.h" +#include "MozillaPrivate.h" + +#include +#include +#include +#include +#include +#include + +#include + +/* 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 +#endif + +#include "ProgressListener.h" + +#include "eel-gconf-extensions.h" +#include "ephy-file-helpers.h" + +#include +#include +#include + +#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 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 helperService = + do_GetService (NS_EXTERNALHELPERAPPSERVICE_CONTRACTID); + + nsCOMPtr 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 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 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 helperService = + do_GetService (NS_EXTERNALHELPERAPPSERVICE_CONTRACTID, &rv); + if (NS_SUCCEEDED(rv)) + { + nsCOMPtr 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 +#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 mLauncher; + nsCOMPtr mPersist; + nsCOMPtr mHandler; + nsCOMPtr mParent; + nsCOMPtr mRequest; + + EphyEmbedPersist *mEphyPersist; + + nsCOMPtr mUri; + PRInt64 mTimeDownloadStarted; + nsCOMPtr 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 mObserver; + + nsCOMPtr 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 +#include +#include +#include +#include +#include + +/* 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 mChannel; + nsCOMPtr 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 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 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 +#include +#include +#include +#include + +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 linkURI; + linkURI = nsnull; + if (uri) + { + s.AssignWithConversion(uri); + rv = NS_NewURI(getter_AddRefs(linkURI), s); + if (NS_FAILED(rv) || !linkURI) return G_FAILED; + } + + nsCOMPtr bpersist = + do_CreateInstance(NS_WEBBROWSERPERSIST_CONTRACTID, &rv); + if (NS_FAILED(rv) || !persist) return G_FAILED; + + nsCOMPtr file; + NS_NewLocalFile(NS_ConvertUTF8toUCS2(filename), PR_TRUE, getter_AddRefs(file)); + if (NS_FAILED(rv) || !file) return G_FAILED; + + nsCOMPtr 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 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 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 document = + do_QueryInterface (DOMDocument, &rv); + if (NS_FAILED(rv) || !document) return G_FAILED; + + nsCOMPtr 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 +#include + +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 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 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 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 docCharsetAtom; + nsCOMPtr ccm2 = + do_GetService (NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv); + if (!NS_SUCCEEDED(rv)) return G_FAILED; + + nsCOMPtr 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 cssupports = + (dont_AddRef)(cs_list->ElementAt(i)); + nsCOMPtr 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 mozFontList; + mozFontList = do_CreateInstance("@mozilla.org/gfx/fontlist;1", &rv); + if(NS_FAILED(rv)) return G_FAILED; + + nsCOMPtr 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 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 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 permissionManager = + do_CreateInstance (NS_PERMISSIONMANAGER_CONTRACTID); + nsCOMPtr 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 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 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 cookieManager = + do_CreateInstance (NS_COOKIEMANAGER_CONTRACTID); + nsCOMPtr 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 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 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 passwordManager = + do_CreateInstance (NS_PASSWORDMANAGER_CONTRACTID); + nsCOMPtr 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 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 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 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 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 + +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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +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 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 uri; + rv = NS_NewURI (getter_AddRefs(uri), aUri); + if (NS_FAILED(rv) || !uri) return NULL; + + nsCOMPtr 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 pageDescriptor; + rv = sWrapper->GetPageDescriptor(getter_AddRefs(pageDescriptor)); + if (!pageDescriptor || NS_FAILED(rv)) return G_FAILED; + + rv = dWrapper->LoadDocument(pageDescriptor, static_cast(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 channel; + channel = do_QueryInterface (MOZILLA_EMBED(embed)->priv->request, + &result); + if (NS_FAILED (result)) return G_FAILED; + + nsCOMPtr info; + result = channel->GetSecurityInfo(getter_AddRefs(info)); + if (NS_FAILED (result)) return G_FAILED; + + *description = NULL; + if (info) + { + nsCOMPtr 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 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 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 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 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 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 + +#include +#include + +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 + +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 + +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 +#include +#include +#include +#include +#include +#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 +#include +#include +#include +#include +#include + +gboolean +mozilla_prefs_save (void) +{ + nsCOMPtr 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 prefService = + do_GetService (NS_PREFSERVICE_CONTRACTID); + nsCOMPtr 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 prefService = + do_GetService (NS_PREFSERVICE_CONTRACTID); + nsCOMPtr 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 prefService = + do_GetService (NS_PREFSERVICE_CONTRACTID); + nsCOMPtr 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 prefService = + do_GetService (NS_PREFSERVICE_CONTRACTID); + nsCOMPtr 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 prefService = + do_GetService (NS_PREFSERVICE_CONTRACTID); + nsCOMPtr 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 prefService = + do_GetService (NS_PREFSERVICE_CONTRACTID); + nsCOMPtr 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 prefService = + do_GetService (NS_PREFSERVICE_CONTRACTID); + nsCOMPtr 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 + * + * 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 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 + * + * 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 + +#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 +#include + +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 + +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 +*/ + +#include +#include +#include "eel-gconf-extensions.h" + +#include +#include +#include +#include +#include + +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 +*/ + +#ifndef EEL_GCONF_EXTENSIONS_H +#define EEL_GCONF_EXTENSIONS_H + +#include +#include +#include + +#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 + * + * 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 + * + * 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 + +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 +#include + +#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 +#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 +#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 + Darin Adler +*/ + +#include + +#include "ephy-bonobo-extensions.h" +#include "ephy-string.h" +#include + +#include +#include +#include +#include + +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 ("\n", + item_name, command_name); + break; + case NUMBERED_MENU_ITEM_RADIO: + xml_item = g_strdup_printf ("\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 ("\n", + item_name, command_name, pixbuf_data); + g_free (pixbuf_data); + } else { + xml_item = g_strdup_printf ("\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 ("\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 ("\n", + item_name, pixbuf_data, command_name); + g_free (pixbuf_data); + } else { + xml_string = g_strdup_printf ("\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 ("\n", + item_name, pixbuf_data); + g_free (pixbuf_data); + } else { + xml_string = g_strdup_printf ("\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 ("\n", + name, pixbuf_data); + g_free (pixbuf_data); + } else { + xml_string = g_strdup_printf ("\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 ("", ++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 ("", + 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 ("", 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 +*/ + +#ifndef EPHY_BONOBO_EXTENSIONS_H +#define EPHY_BONOBO_EXTENSIONS_H + +#include +#include +#include +#include + +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 +#include + +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 +#include +#include + +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 +#include + +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 +#include +#include + +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 +#endif + +#include +#include +#include +#include +#include +#include +#include + +#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 + +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 + +#include + +#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 + +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 +#include +#include + +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 +#include +#include + +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 +#include +#include +#include + +/* 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 +#include +#include +#include + +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 + * (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 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 +#include +#include + +#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 + * (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 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 + +#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 + * + * 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 +#include +#include +#include +#include +#include +#include + +#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 + * + * 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 + +#include + +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 + +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 + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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 + * + * 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 +#include +#include +#include + +#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 +#include +#include +#include +#include +#include + +/** + * 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 + +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 + +#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 + +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 +#include + +#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 +#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 (""); + + 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 +#include +#include +#include +#include +#include + +#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 +#include + +#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 ("", ++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 +#include + +#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 +#include +#include +#include +#include + +#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 + ("", _("Back"));; + break; + case EPHY_TBI_STD_TOOLITEM_FORWARD: + xml_item = g_strdup_printf + ("", _("Forward")); + break; + case EPHY_TBI_STD_TOOLITEM_UP: + xml_item = g_strdup_printf + ("", _("Up"));; + break; + case EPHY_TBI_STD_TOOLITEM_STOP: + xml_item = g_strdup_printf + ("", _("Stop")); + break; + case EPHY_TBI_STD_TOOLITEM_RELOAD: + xml_item = g_strdup_printf + ("", _("Reload")); + break; + case EPHY_TBI_STD_TOOLITEM_HOME: + xml_item = g_strdup_printf + ("", _("Home"));; + break; + case EPHY_TBI_STD_TOOLITEM_GO: + xml_item = g_strdup_printf + ("", _("Go"));; + break; + case EPHY_TBI_STD_TOOLITEM_NEW: + xml_item = g_strdup_printf + ("", _("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 +#include +#include +#include +#include +#include +#include + +#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 + +#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 + +#include + +#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 + +#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 +#include + +#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 + +#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 + +#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 + +#include +#include + +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 + * + * 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 +#include +#include + +#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 + * + * 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 +#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 +#include +#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 + +#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 + * Copyright (C) 2001,2002 Kristian Rietveld + * + * 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 +#include + +/****** 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 + * Copyright (C) 2001,2002 Kristian Rietveld + * + * 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 + +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 +#include +#include +#include +#include +#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 +#include +#include + +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +#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 +#include + +#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 , + Marco Pesenti Gritti Markup support + */ + +#include "ephy-ellipsizing-label.h" + +#include + +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, "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 , + */ + +#ifndef EPHY_ELLIPSIZING_LABEL_H +#define EPHY_ELLIPSIZING_LABEL_H + +#include + +#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 +#include +#include +#include +#include +#include + +//#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 +#include + +#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 +#include +#include + +#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 +#include + +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 + * + * Ephy port by Marco Pesenti Gritti + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#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 + * + * This is the header file for the throbber on the location bar + * + */ + +#ifndef EPHY_SPINNER_H +#define EPHY_SPINNER_H + +#include +#include + +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 + * + * 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 +#include + +#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 + * + * 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 + +#include + +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 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 +#include +#include +#include +#include + +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 +#include + +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 + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#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), _("Title:")); + 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), _("Keywords:")); + 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), _("Search:")); + 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 + * + * 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 + +#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 +#include + +//#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 + +#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 + +//#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 +#include + +/* 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 + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#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), _("Title:")); + 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), _("Keywords:")); + 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 + * + * 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 + +#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 + * + * 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 +#include +#include +#include +#include + +#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 + * + * 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 +#include + +#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 + * + * 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 +#include +#include +#include +#include +#include + +#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 + * + * 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 + +#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 +#include +#include +#include + +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 +#include + +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 +#include +#include + +#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, "\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, "\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, "\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 + +/* 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 + * + * 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 +#include +#include +#include +#include +#include + +#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 + * + * 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 + +#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 +#endif + +#include "ephy-shell.h" +#include "ephy-automation.h" +#include "ephy-window.h" +#include "EphyAutomation.h" + +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#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 +#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 +#include +#include +#include +#include +#include + +#ifdef ENABLE_NAUTILUS_VIEW + +#include +#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 +#include + +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 + +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 +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#include + +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 +#include +#include +#include +#include +#include + +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 +#include + +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 +#include +#include +#include + +#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 (¤t_date, 1); + g_date_set_time (¤t_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 (¤t_date, 1); + break; + /* Last three days */ + case 3: + g_date_subtract_days (¤t_date, 2); + break; + /* Week */ + case 4: + g_date_subtract_days (¤t_date, 7); + break; + /* Month */ + case 5: + g_date_subtract_months (¤t_date, 1); + break; + default: + break; + } + + g_date_to_struct_tm (¤t_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 +#include + +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 +#include +#include +#include +#include +#include +#include +#include +#include + +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 +#include +#include + +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 +#include +#include +#include + +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 (_("Value")); + 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 (_("Path")); + 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 (_("Secure")); + 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 (_("Expire")); + 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 + +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 + +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 +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#include + +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 +#include +#include +#include +#include +#include +#include +#include +#include + +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 +#include +#include + +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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), + _("Epiphany appears to have crashed or been killed the last time it was run.")); + 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 +#include + +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 +#include +#include +#include +#include +#include +#include +#include +#include + +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 +#include + +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 +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#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 +#include +#include + +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 +#include + +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 + +#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 +#include +#include +#include +#include +#include +#include +#include + +#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 ", + 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 + +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); + -- cgit v1.2.3