diff options
author | Christian Persch <chpe@src.gnome.org> | 2007-08-26 04:59:04 +0800 |
---|---|---|
committer | Christian Persch <chpe@src.gnome.org> | 2007-08-26 04:59:04 +0800 |
commit | 6deabce61b1758b0c395678bf5c2769ee4ca17c6 (patch) | |
tree | 27866c89b34cb0fe866753fbef2894e6dfd01785 /embed | |
parent | d2bc7076ca31996d4a5b80b74e4380e6f2f56321 (diff) | |
download | gsoc2013-epiphany-6deabce61b1758b0c395678bf5c2769ee4ca17c6.tar gsoc2013-epiphany-6deabce61b1758b0c395678bf5c2769ee4ca17c6.tar.gz gsoc2013-epiphany-6deabce61b1758b0c395678bf5c2769ee4ca17c6.tar.bz2 gsoc2013-epiphany-6deabce61b1758b0c395678bf5c2769ee4ca17c6.tar.lz gsoc2013-epiphany-6deabce61b1758b0c395678bf5c2769ee4ca17c6.tar.xz gsoc2013-epiphany-6deabce61b1758b0c395678bf5c2769ee4ca17c6.tar.zst gsoc2013-epiphany-6deabce61b1758b0c395678bf5c2769ee4ca17c6.zip |
Initial checkin: merged embed/gecko from xulrunner branch to embed/xulrunner, and svn copied embed/mozilla to embed/xulrunner/embed. Not integreated with the build yet.
svn path=/trunk/; revision=7297
Diffstat (limited to 'embed')
141 files changed, 30405 insertions, 0 deletions
diff --git a/embed/xulrunner/AUTHORS b/embed/xulrunner/AUTHORS new file mode 100644 index 000000000..7b35d3e1d --- /dev/null +++ b/embed/xulrunner/AUTHORS @@ -0,0 +1,2 @@ +The code was originally taken from mozilla's gtkmozembed +code.
\ No newline at end of file diff --git a/embed/xulrunner/COPYRIGHT b/embed/xulrunner/COPYRIGHT new file mode 100644 index 000000000..a4516955f --- /dev/null +++ b/embed/xulrunner/COPYRIGHT @@ -0,0 +1,3 @@ +This library is available under the terms of the +GNU Lesser General Public Licence, either version 2.1, or +(at your option) any later version. diff --git a/embed/xulrunner/ChangeLog b/embed/xulrunner/ChangeLog new file mode 100644 index 000000000..234c62134 --- /dev/null +++ b/embed/xulrunner/ChangeLog @@ -0,0 +1,545 @@ +2006-10-13 Jean-François Rameau <jframeau@cvs.gnome.org> + + * src/Makefile.am: + * tests/testgeckoembed.cpp: + + Fix type-builtin part. Fix missing include in testgeckoembed.cpp. + +2006-10-08 Christian Persch <chpe@cvs.gnome.org> + + * src/Makefile.am: + + Fix a bug in the last commit. + +2006-10-08 Christian Persch <chpe@cvs.gnome.org> + + * src/Makefile.am: + + Make the type builtins value types not global. + +2006-09-17 Christian Persch <chpe@cvs.gnome.org> + + * Makefile.am: + * configure.ac: + * data/Makefile.am: + * data/gnome-gecko-embed.pc.in: + * m4/gecko.m4: + + Add pkg-config file. + +2006-09-06 Christian Persch <chpe@cvs.gnome.org> + + * *.c *.cpp: + + Remove some unnecessary static data. + +2006-08-22 Christian Persch <chpe@cvs.gnome.org> + + * configure.ac: + * src/EmbedProgress.cpp: + * src/Makefile.am: + * src/gecko-embed-single.h: + R src/gecko-embed-types.c: + * src/gecko-embed-types.h: + * src/gecko-embed.cpp: + * src/gecko-embed.h: + + Autogenerate the type builtins. + +2006-08-22 Christian Persch <chpe@cvs.gnome.org> + + A src/AutoWindowModalState.cpp: + A src/AutoWindowModalState.h: + * src/GeckoPromptService.cpp: + * src/Makefile.am: + + Sync with Epiphany. + +2006-08-22 Christian Persch <chpe@cvs.gnome.org> + + * src/AutoJSContextStack.cpp: + * src/EmbedContentListener.cpp: + * src/EmbedEventListener.cpp: + * src/EmbedProgress.cpp: + * src/EmbedWindowCreator.cpp: + * src/GeckoBrowser.cpp: + * src/GeckoPromptService.cpp: + * src/GeckoSingle.cpp: + * src/GeckoUtils.cpp: + * src/gecko-dom-event.cpp: + * src/gecko-embed-single.cpp: + * src/gecko-embed-types.c: + * src/gecko-embed.cpp: + * src/gecko-init.cpp: + * src/nsEmbedAPI.cpp: + + Include config.h unconditionally. + +2006-08-22 Christian Persch <chpe@cvs.gnome.org> + + R COPYING: + A COPYING.LESSER: + R COPYING.MPL: + * COPYRIGHT: + * Makefile.am: + * configure.ac: + R src/EmbedComponents.cpp.in: + * src/EmbedContentListener.cpp: + * src/EmbedContentListener.h: + * src/EmbedEventListener.cpp: + * src/EmbedEventListener.h: + * src/EmbedProgress.cpp: + * src/EmbedProgress.h: + * src/EmbedStream.cpp: + * src/EmbedStream.h: + * src/EmbedWindow.cpp: + * src/EmbedWindow.h: + * src/EmbedWindowCreator.cpp: + * src/EmbedWindowCreator.h: + * src/GeckoBrowser.cpp: + * src/GeckoBrowser.h: + * src/GeckoSingle.cpp: + * src/GeckoSingle.h: + * src/gecko-embed-private.h: + * src/gecko-embed-signals.h: + * src/gecko-embed-single-private.h: + * src/gecko-embed-single.cpp: + * src/gecko-embed-single.h: + * src/gecko-embed-types.c: + * src/gecko-embed-types.h: + * src/gecko-embed.cpp: + * src/gecko-embed.h: + * src/gecko-init.cpp: + * src/nsEmbedAPI.cpp: + * src/nsProfileDirServiceProvider.cpp: + * src/nsProfileDirServiceProvider2.cpp: + * tests/testgeckoembed.cpp: + + Cleanup and exercise relicence clause to make this LGPL 2.1+ only. + +2006-07-18 Christian Persch <chpe@cvs.gnome.org> + + * src/GeckoPromptService.cpp: + + Force label wrapping. + +2006-04-01 Christian Persch <chpe@cvs.gnome.org> + + * src/GeckoPromptService.cpp: + + Fix crash when cancelling the prompt before the timeout has run. + +2006-03-21 Christian Persch <chpe@cvs.gnome.org> + + * tests/testgeckoembed.cpp: + + Add handler for context menu signal. + +2006-03-21 Christian Persch <chpe@cvs.gnome.org> + + * src/gecko-embed.cpp: + + Fix focus signal connection. + +2006-03-21 Christian Persch <chpe@cvs.gnome.org> + + * src/gecko-embed.cpp: + + Fix typo. + +2006-03-21 Christian Persch <chpe@cvs.gnome.org> + + * src/Makefile.am: + A src/gecko-dom-event.h: + A src/gecko-dom-event-internal.h: + A src/gecko-dom-event-private.h: + A src/gecko-dom-event.cpp: + * src/EmbedEventListener.cpp: + * src/EmbedEventListener.h: + * src/GeckoBrowser.cpp: + * src/gecko-embed-marshal.list: + * src/gecko-embed-signals.h: + * src/gecko-embed.cpp: + * src/gecko-embed.h: + * tests/testgeckoembed.cpp: + + Rework the DOM signals. + Add context menu signal. + +2006-03-21 Christian Persch <chpe@cvs.gnome.org> + + R src/gecko-embed-marshal.c: + R src/gecko-embed-marshal.h: + + Remove autogenerated files from cvs. + +2006-03-17 Xan Lopez <xan@gnome.org> + + * src/GeckoSingle.cpp: + * src/Makefile.am: + * src/gecko-init-private.h: + * src/gecko-init.cpp: + * src/gecko-init.h: + * tests/testgeckoembed.cpp: + + Rework headers. + +2006-03-17 Xan Lopez <xan@gnome.org> + + * src/GeckoSingle.cpp: + * src/GeckoSingle.h: + * src/Makefile.am: + * src/gecko-embed-single.cpp: + * src/gecko-embed-single.h: + * src/gecko-init-private.h: + * src/gecko-init.cpp: + * src/gecko-init.h: + + Moved init/shutdown logic to gecko-init + + * tests/testgeckoembed.cpp: + + Change test to use new functions + +2006-03-15 Xan Lopez <xan@gnome.org> + + * bindings/python/test.py: + + Update. + +2006-03-15 Xan Lopez <xan@gnome.org> + + * bindings/python/gnomegeckoembed.defs: + * src/gecko-embed-types.h: + + Fix the flags/enum thing properly. + +2006-03-15 Xan Lopez <xan@gnome.org> + + * m4/python.m4: + + Forgot. + +2006-03-15 Xan Lopez <xan@gnome.org> + + * Makefile.am: + * bindings/Makefile.am: + * bindings/python/Makefile.am: + * bindings/python/gnomegeckoembed.defs: + * bindings/python/gnomegeckoembed.override: + * bindings/python/gnomegeckoembedmodule.c: (initgnomegeckoembed): + * bindings/python/test.py: + * configure.ac: + + Python bindings. + + * src/GeckoBrowser.cpp: + + Fix typo. + + * src/gecko-embed-types.h: + + s/GECKO_TYPE_EMBED_STATUS_ENUM/GECKO_TYPE_EMBED_STATUS_FLAGS/ + +2006-03-14 Jean-François Rameau <jframeau@cvs.gnome.org> + + * autogen.sh: + * src/GeckoSingle.cpp: + + Fix some typos. + +2006-03-13 Christian Persch <chpe@cvs.gnome.org> + + R src/EmbedPrompter.cpp: + R src/EmbedPrompter.h: + R src/GtkPromptService.cpp: + R src/GtkPromptService.h: + A src/AutoJSContextStack.cpp: + A src/AutoJSContextStack.h: + A src/GeckoPromptService.cpp: + A src/GeckoPromptService.h: + * src/EmbedWindow.cpp: + * src/GeckoBrowser.cpp: + * src/GeckoSingle.cpp: + * src/GeckoUtils.cpp: + * src/GeckoUtils.h: + * src/Makefile.am: + + Import prompt service implementation from Epiphany. + +2004-03-13 Christian Persch <chpe@cvs.gnome.org> + + * src/gecko-embed.cpp: + + Fix signal declarations to include RUN_LAST. + +2006-03-13 Xan Lopez <xan@gnome.org> + + * src/EmbedEventListener.cpp: + + Merge https://bugzilla.mozilla.org/show_bug.cgi?id=306839 + +2004-03-13 Christian Persch <chpe@cvs.gnome.org> + + * Makefile.am: + + Add ACLOCAL_AMFLAGS. + +2004-03-13 Christian Persch <chpe@cvs.gnome.org> + + * configure.ac: + + We don't want to support gecko 1.7 or non-toolkit geckos. + +2006-03-13 Xan Lopez <xan@gnome.org> + + * src/gecko-embed-types.c: (gecko_embed_progress_flags_get_type): + * src/gecko-embed-types.h: + + Merge https://bugzilla.mozilla.org/show_bug.cgi?id=306550 + +2006-03-13 Xan Lopez <xan@gnome.org> + + * src/GeckoBrowser.cpp: + * src/GeckoSingle.h: + * src/gecko-embed.cpp: + + Merge https://bugzilla.mozilla.org/show_bug.cgi?id=210373 + +2006-03-13 Xan Lopez <xan@gnome.org> + + * src/GeckoBrowser.h: + * src/GeckoSingle.cpp: + * src/GeckoSingle.h: + * src/Makefile.am: + + Merge https://bugzilla.mozilla.org/show_bug.cgi?id=275463 + +2006-03-13 Xan Lopez <xan@gnome.org> + + * src/GeckoBrowser.cpp: + * src/GeckoBrowser.h: + * src/gecko-embed.cpp: + + Ahem, back off #97580. + +2006-03-13 Xan Lopez <xan@gnome.org> + + * src/gecko-embed.cpp: + + Merge http://bonsai.mozilla.org/cvsview2.cgi?diff_mode=context&whitespace_mode=show&subdir=mozilla/embedding/browser/gtk/src&command=DIFF_FRAMESET&file=gtkmozembed2.cpp&rev1=1.42&rev2=1.43&root=/cvsroot + +2006-03-13 Xan Lopez <xan@gnome.org> + + * src/EmbedContentListener.cpp: + + Merge http://bonsai.mozilla.org/cvsview2.cgi?diff_mode=context&whitespace_mode=show&subdir=mozilla/embedding/browser/gtk/src&command=DIFF_FRAMESET&file=EmbedContentListener.cpp&rev1=1.17&rev2=1.18&root=/cvsroot + +2006-03-13 Xan Lopez <xan@gnome.org> + + * src/GeckoBrowser.cpp: + * src/GeckoBrowser.h: + * src/gecko-embed.cpp: + + Merge https://bugzilla.mozilla.org/show_bug.cgi?id=97580 + +2006-03-13 Xan Lopez <xan@gnome.org> + + * src/GeckoSingle.cpp: + + Merge https://bugzilla.mozilla.org/show_bug.cgi?id=242024 + +2006-03-13 Xan Lopez <xan@gnome.org> + + * src/EmbedWindow.cpp: + + Merge https://bugzilla.mozilla.org/show_bug.cgi?id=238052 + +2006-03-13 Xan Lopez <xan@gnome.org> + + * configure.ac: + + Fix typo. + + * src/GeckoBrowser.cpp: + + Merge https://bugzilla.mozilla.org/show_bug.cgi?id=276482 + +2004-09-25 Christian Persch <chpe@cvs.gnome.org> + + * src/GeckoBrowser.cpp: + * src/GeckoSingle.cpp: + * src/gecko-embed-single.cpp: + * tests/testgeckoembed.cpp: + + Make testgeckoembed link. + +2004-09-24 Christian Persch <chpe@cvs.gnome.org> + + * src/EmbedProgress.cpp: + * src/GeckoBrowser.cpp: + * src/GeckoSingle.cpp: + * src/GeckoSingle.h: + * src/gecko-embed-single.cpp: + * src/gecko-embed.cpp: + + Fix startup. + +2004-09-24 Christian Persch <chpe@cvs.gnome.org> + + * src/gecko-embed.cpp: + + Last GtkSignal bits ported to gobject. + +2004-09-24 Christian Persch <chpe@cvs.gnome.org> + + * src/EmbedEventListener.cpp: + * src/EmbedProgress.cpp: + * src/EmbedWindow.cpp: + * src/EmbedWindowCreator.cpp: + * src/GeckoBrowser.h: + * src/GeckoSingle.cpp: + * src/gecko-embed-signals.h: + * src/gecko-embed.cpp: + * src/gecko-embed.h: + + More gobject porting. + +2004-09-24 Christian Persch <chpe@cvs.gnome.org> + + * tests/Makefile.am: + * tests/TestGtkEmbed.cpp: + * tests/testgeckoembed.cpp: + + Started to port testgeckoembed to GeckoEmbed. + +2004-09-24 Christian Persch <chpe@cvs.gnome.org> + + * src/EmbedWindowCreator.cpp: + + Ported to gobject. + +2004-09-24 Christian Persch <chpe@cvs.gnome.org> + + * src/EmbedPrompter.cpp: + * src/EmbedWindow.cpp: + + Ported to gobject. + +2004-09-24 Christian Persch <chpe@cvs.gnome.org> + + * src/EmbedProgress.cpp: + + Ported to gobject. + + * src/gecko-embed-marshal.list: + * src/gecko-embed.cpp: + + Fix a signal. + +2004-09-24 Christian Persch <chpe@cvs.gnome.org> + + * src/EmbedContentListener.cpp: + * src/EmbedEventListener.cpp: + + Ported to gobject. + +2004-09-24 Christian Persch <chpe@cvs.gnome.org> + + * src/EmbedContentListener.cpp: + * src/EmbedContentListener.h: + * src/EmbedEventListener.cpp: + * src/EmbedEventListener.h: + * src/EmbedPrivate.cpp: + * src/EmbedPrivate.h: + * src/EmbedProgress.cpp: + * src/EmbedProgress.h: + * src/EmbedWindow.cpp: + * src/EmbedWindow.h: + * src/EmbedWindowCreator.cpp: + * src/GeckoBrowser.cpp: + * src/GeckoBrowser.h: + * src/GeckoSingle.cpp: + * src/GeckoSingle.h: + * src/Makefile.am: + * src/gecko-embed-marshal.list: + * src/gecko-embed-marshalers.list: + * src/gecko-embed-private.h: + * src/gecko-embed-signals.h: + * src/gecko-embed-single-private.h: + * src/gecko-embed-single.cpp: + * src/gecko-embed-types.c: (gecko_embed_progress_flags_get_type), + (gecko_embed_status_enums_get_type), + (gecko_embed_reload_flags_get_type), + (gecko_embed_chrome_flags_get_type): + * src/gecko-embed-types.h: + * src/gecko-embed.cpp: + * src/gecko-embed.h: + * src/gtkmozembed.h: + * src/gtkmozembed2.cpp: + * src/gtkmozembed_internal.h: + * src/gtkmozembedmarshal.list: + * src/gtkmozembedprivate.h: + + Renamed GtkMozEmbed to GeckoEmbed, EmbedPrivate to GeckoBrowser and split + GeckoBrowser into per-embed and global things (-> GeckoSingle). + First round of making things use gobject instead of gtkobject. + +2004-09-23 Christian Persch <chpe@cvs.gnome.org> + + * src/Makefile.am: + * src/gtkmozembedmarshal.c: + * src/gtkmozembedmarshal.h: + + Make marshalers autogenerate from list. + +2004-09-23 Christian Persch <chpe@cvs.gnome.org> + + * src/EmbedPrivate.cpp: + * src/EmbedWindow.cpp: + * src/gtkmozembed2.cpp: + * tests/TestGtkEmbed.cpp: + * tests/TestGtkEmbedChild.cpp: + * tests/TestGtkEmbedMDI.cpp: + * tests/TestGtkEmbedSocket.cpp: + + Remove all #ifdef MOZ_WIDGET_GTK code, and remove the + checks for MOZ_WIDGET_GTK2. + +2004-09-23 Christian Persch <chpe@cvs.gnome.org> + + * src/EmbedPrivate.cpp: + * src/Makefile.am: + * tests/Makefile.am: + * tests/TestGtkEmbed.cpp: + + Make it link and run. + +2004-09-21 Christian Persch <chpe@cvs.gnome.org> + + * data/gnome-gecko-embed-0.0.pc.in: + * src/EmbedContentListener.cpp: + * src/EmbedPrivate.cpp: + * src/EmbedPrivate.h: + * src/EmbedProgress.cpp: + * src/EmbedProgress.h: + * src/EmbedPrompter.cpp: + * src/EmbedPrompter.h: + * src/EmbedWindow.cpp: + * src/EmbedWindow.h: + * src/GtkPromptService.cpp: + * src/GtkPromptService.h: + * src/Makefile.am: + * src/gtkmozembed2.cpp: + + Incorporate latest patch [http://bugzilla.mozilla.org/attachment.cgi?id=148650&action=view] + from bug [http://bugzilla.mozilla.org/show_bug.cgi?id=205425]. + +2004-09-21 Christian Persch <chpe@cvs.gnome.org> + + * TODO: + * autogen.sh: + * configure.ac: + * src/Makefile.am: + + Make it pass autogen. diff --git a/embed/xulrunner/HACKING b/embed/xulrunner/HACKING new file mode 100644 index 000000000..b93d7ae64 --- /dev/null +++ b/embed/xulrunner/HACKING @@ -0,0 +1,10 @@ +Do NOT commit to this module without permission from +chpe@gnome.org . + +Please send patches either to chpe@gnome.org or for discussion to +epiphany-list@gnome.org. + +Code style is mozilla code style, that is 2-spaces for indentation, and +curly brackets are on a the same line. + +All files have to be encoded in UTF-8. diff --git a/embed/xulrunner/MAINTAINERS b/embed/xulrunner/MAINTAINERS new file mode 100644 index 000000000..7e15500c2 --- /dev/null +++ b/embed/xulrunner/MAINTAINERS @@ -0,0 +1,2 @@ +Email: chpe@gnome.org +Email: xan@gnome.org diff --git a/embed/xulrunner/Makefile.am b/embed/xulrunner/Makefile.am new file mode 100644 index 000000000..1a6185567 --- /dev/null +++ b/embed/xulrunner/Makefile.am @@ -0,0 +1,9 @@ +SUBDIRS = src data bindings tests + +NULL = + +EXTRA_DIST = \ + README \ + TODO \ + COPYRIGHT \ + $(NULL) diff --git a/embed/xulrunner/NEWS b/embed/xulrunner/NEWS new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/embed/xulrunner/NEWS diff --git a/embed/xulrunner/PLAN b/embed/xulrunner/PLAN new file mode 100644 index 000000000..50d0e9427 --- /dev/null +++ b/embed/xulrunner/PLAN @@ -0,0 +1,26 @@ +The plan is to fix the things which suck in gtkmozembed and some of +which require direct access to the embedding layer to be fixed. + +Note that the following plans are not set in stone. + +- lifecycle: + Move from the push_startup/pop_startup lifecycle management to explicit + init/shutdown. +- dom events: + Make the DOM events signals actually useful by implementing a DOM context + class accessible from C, where the context is only calculated on demand + (since DOM signals can be emitted frequently and getting context is slow) +- gtk-like tooltips: + Make tooltips follow mouse (like in evince), not time out, and and make sure + they don't fall off the side of the screen +- printing: + Integrate with gtk+ 2.10 printing out-of-the-box; atm every application + codes its own libgnomeprint ps-to-printer support. +- more gobject-like: + Make use of gobject properties instead of signals (à la EphyTab) +- find: + Copy EphyEmbedFind. +- prefs: + Provide access to mozilla prefs from C (like mozilla-notifiers.h in epiphany/embed/mozilla/) + and map common gconf prefs to moz prefs automatically (like mozilla-notifiers.cpp). + That way we can also share the font prefs between epiphany, yelp and devhelp. diff --git a/embed/xulrunner/README b/embed/xulrunner/README new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/embed/xulrunner/README diff --git a/embed/xulrunner/STATUS b/embed/xulrunner/STATUS new file mode 100644 index 000000000..7732c1479 --- /dev/null +++ b/embed/xulrunner/STATUS @@ -0,0 +1,2 @@ +Taken from gtkmozembed trunk on 2004-09-21 + diff --git a/embed/xulrunner/TODO b/embed/xulrunner/TODO new file mode 100644 index 000000000..e8bb8e81b --- /dev/null +++ b/embed/xulrunner/TODO @@ -0,0 +1 @@ +- Fix tooltip direction: on RTL the tooltip should be RTL too! (see https://bugzilla.mozilla.org/show_bug.cgi?id=91312) diff --git a/embed/xulrunner/bindings/Makefile.am b/embed/xulrunner/bindings/Makefile.am new file mode 100644 index 000000000..0f4745056 --- /dev/null +++ b/embed/xulrunner/bindings/Makefile.am @@ -0,0 +1,5 @@ +SUBDIRS = + +if ENABLE_PYTHON +SUBDIRS += python +endif diff --git a/embed/xulrunner/bindings/python/Makefile.am b/embed/xulrunner/bindings/python/Makefile.am new file mode 100644 index 000000000..68ed1efe9 --- /dev/null +++ b/embed/xulrunner/bindings/python/Makefile.am @@ -0,0 +1,63 @@ +defsdir = $(datadir)/pygtk/2.0/defs +defs_DATA = gnomegeckoembed.defs + +pkgpythondir = $(pyexecdir)/gtk-2.0 +pkgpyexecdir = $(pyexecdir)/gtk-2.0 + +# gnomegeckoembed module +pkgpyexec_LTLIBRARIES = gnomegeckoembed.la + +gnomegeckoembed_la_CPPFLAGS = \ + -I$(top_srcdir) \ + -I$(top_srcdir)/embed/gecko/src \ + -I$(top_builddir)/embed/gecko/src \ + $(AM_CPPFLAGS) + +gnomegeckoembed_la_CFLAGS = \ + $(GGE_DEPENDENCY_CFLAGS) \ + $(GECKO_CFLAGS) \ + $(NO_STRICT_ALIASING_CFLAGS) \ + $(PYGTK_CFLAGS) \ + $(PYTHON_CFLAGS) \ + $(AM_CFLAGS) + +gnomegeckoembed_la_LIBADD = \ + $(top_builddir)/embed/gecko/src/libgnomegeckoembed-0.0.la \ + $(GECKO_LIBS) \ + $(PYTHON_LIBS) \ + $(PYTHON_EXTRA_LIBS) \ + $(PYGTK_LIBS) + +gnomegeckoembed_la_LDFLAGS = \ + -module -avoid-version \ + -export-symbols-regex initgnomegeckoembed \ + -R$(GECKO_HOME) \ + $(AM_LDFLAGS) + +gnomegeckoembed_la_SOURCES = gnomegeckoembedmodule.c +nodist_gnomegeckoembed_la_SOURCES = gnomegeckoembed.c + +gnomegeckoembed.c: gnomegeckoembed.defs gnomegeckoembed.override +CLEANFILES = gnomegeckoembed.c +EXTRA_DIST = gnomegeckoembed.override gnomegeckoembed.defs + +.defs.c: + (cd $(srcdir)\ + && $(PYGTK_CODEGEN) \ + --override $*.override \ + --prefix py$* $*.defs) > gen-$*.c \ + && cp gen-$*.c $*.c \ + && rm -f gen-$*.c + +BINDING_HEADERS_SRCDIR_IN = \ + src/gecko-embed.h \ + src/gecko-embed-single.h \ + src/gecko-embed-types.h + +BINDING_HEADERS_BUILDDIR_IN = + +BINDING_HEADERS_SRCDIR := $(addprefix $(top_srcdir)/,$(BINDING_HEADERS_SRCDIR_IN)) +BINDING_HEADERS_BUILDDIR := $(addprefix $(top_builddir)/,$(BINDING_HEADERS_BUILDDIR_IN)) + +regenerate-python-binding: + $(PYGTK_H2DEF) $(sort $(BINDING_HEADERS_SRCDIR) $(BINDING_HEADERS_BUILDDIR)) > gnomegeckoembed.defs.new diff --git a/embed/xulrunner/bindings/python/gnomegeckoembed.defs b/embed/xulrunner/bindings/python/gnomegeckoembed.defs new file mode 100644 index 000000000..e3c0f10b5 --- /dev/null +++ b/embed/xulrunner/bindings/python/gnomegeckoembed.defs @@ -0,0 +1,294 @@ +;; -*- scheme -*- +; object definitions ... +(define-object Embed + (in-module "Gecko") + (parent "GtkBin") + (c-name "GeckoEmbed") + (gtype-id "GECKO_TYPE_EMBED") +) + +(define-object EmbedSingle + (in-module "Gecko") + (parent "GObject") + (c-name "GeckoEmbedSingle") + (gtype-id "GECKO_TYPE_EMBED_SINGLE") +) + +;; Enumerations and flags ... + +(define-enum EmbedProgressFlags + (in-module "Gecko") + (c-name "GeckoEmbedProgressFlags") + (gtype-id "GECKO_TYPE_EMBED_PROGRESS_FLAGS") + (values + '("start" "GECKO_EMBED_FLAG_START") + '("redirecting" "GECKO_EMBED_FLAG_REDIRECTING") + '("transferring" "GECKO_EMBED_FLAG_TRANSFERRING") + '("negotiating" "GECKO_EMBED_FLAG_NEGOTIATING") + '("stop" "GECKO_EMBED_FLAG_STOP") + '("is-request" "GECKO_EMBED_FLAG_IS_REQUEST") + '("is-document" "GECKO_EMBED_FLAG_IS_DOCUMENT") + '("is-network" "GECKO_EMBED_FLAG_IS_NETWORK") + '("is-window" "GECKO_EMBED_FLAG_IS_WINDOW") + '("restoring" "GECKO_EMBED_FLAG_RESTORING") + ) +) + +(define-enum EmbedStatusEnum + (in-module "Gecko") + (c-name "GeckoEmbedStatusEnum") + (gtype-id "GECKO_TYPE_EMBED_STATUS_ENUM") + (values + '("dns" "GECKO_EMBED_STATUS_FAILED_DNS") + '("connect" "GECKO_EMBED_STATUS_FAILED_CONNECT") + '("timeout" "GECKO_EMBED_STATUS_FAILED_TIMEOUT") + '("usercanceled" "GECKO_EMBED_STATUS_FAILED_USERCANCELED") + ) +) + +(define-enum EmbedReloadFlags + (in-module "Gecko") + (c-name "GeckoEmbedReloadFlags") + (gtype-id "GECKO_TYPE_EMBED_RELOAD_FLAGS") + (values + '("normal" "GECKO_EMBED_FLAG_RELOADNORMAL") + '("bypasscache" "GECKO_EMBED_FLAG_RELOADBYPASSCACHE") + '("bypassproxy" "GECKO_EMBED_FLAG_RELOADBYPASSPROXY") + '("bypassproxyandcache" "GECKO_EMBED_FLAG_RELOADBYPASSPROXYANDCACHE") + '("charsetchange" "GECKO_EMBED_FLAG_RELOADCHARSETCHANGE") + ) +) + +(define-enum EmbedChromeFlags + (in-module "Gecko") + (c-name "GeckoEmbedChromeFlags") + (gtype-id "GECKO_TYPE_EMBED_CHROME_FLAGS") + (values + '("defaultchrome" "GECKO_EMBED_FLAG_DEFAULTCHROME") + '("windowborderson" "GECKO_EMBED_FLAG_WINDOWBORDERSON") + '("windowcloseon" "GECKO_EMBED_FLAG_WINDOWCLOSEON") + '("windowresizeon" "GECKO_EMBED_FLAG_WINDOWRESIZEON") + '("menubaron" "GECKO_EMBED_FLAG_MENUBARON") + '("toolbaron" "GECKO_EMBED_FLAG_TOOLBARON") + '("locationbaron" "GECKO_EMBED_FLAG_LOCATIONBARON") + '("statusbaron" "GECKO_EMBED_FLAG_STATUSBARON") + '("personaltoolbaron" "GECKO_EMBED_FLAG_PERSONALTOOLBARON") + '("scrollbarson" "GECKO_EMBED_FLAG_SCROLLBARSON") + '("titlebaron" "GECKO_EMBED_FLAG_TITLEBARON") + '("extrachromeon" "GECKO_EMBED_FLAG_EXTRACHROMEON") + '("allchrome" "GECKO_EMBED_FLAG_ALLCHROME") + '("windowraised" "GECKO_EMBED_FLAG_WINDOWRAISED") + '("windowlowered" "GECKO_EMBED_FLAG_WINDOWLOWERED") + '("centerscreen" "GECKO_EMBED_FLAG_CENTERSCREEN") + '("dependent" "GECKO_EMBED_FLAG_DEPENDENT") + '("modal" "GECKO_EMBED_FLAG_MODAL") + '("openasdialog" "GECKO_EMBED_FLAG_OPENASDIALOG") + '("openaschrome" "GECKO_EMBED_FLAG_OPENASCHROME") + ) +) + + +;; From ../../src/gecko-embed-single.h + +(define-function gecko_embed_single_get_type + (c-name "gecko_embed_single_get_type") + (return-type "GType") +) + +(define-function gecko_embed_single_get + (c-name "gecko_embed_single_get") + (return-type "GeckoEmbedSingle*") +) + +(define-function gecko_embed_single_push_startup + (c-name "gecko_embed_single_push_startup") + (return-type "none") +) + +(define-function gecko_embed_single_pop_startup + (c-name "gecko_embed_single_pop_startup") + (return-type "none") +) + +(define-function gecko_embed_single_set_comp_path + (c-name "gecko_embed_single_set_comp_path") + (return-type "none") + (parameters + '("const-char*" "aPath") + ) +) + +(define-function gecko_embed_single_set_profile_path + (c-name "gecko_embed_single_set_profile_path") + (return-type "none") + (parameters + '("const-char*" "aDir") + '("const-char*" "aName") + ) +) + + + +;; From ../../src/gecko-embed-types.h + +(define-function gecko_embed_progress_flags_get_type + (c-name "gecko_embed_progress_flags_get_type") + (return-type "GType") +) + +(define-function gecko_embed_status_enum_get_type + (c-name "gecko_embed_status_enum_get_type") + (return-type "GType") +) + +(define-function gecko_embed_reload_flags_get_type + (c-name "gecko_embed_reload_flags_get_type") + (return-type "GType") +) + +(define-function gecko_embed_chrome_flags_get_type + (c-name "gecko_embed_chrome_flags_get_type") + (return-type "GType") +) + + + +;; From ../../src/gecko-embed.h + +(define-function gecko_embed_get_type + (c-name "gecko_embed_get_type") + (return-type "GType") +) + +(define-function gecko_embed_new + (c-name "gecko_embed_new") + (is-constructor-of "GeckoEmbed") + (return-type "GtkWidget*") +) + +(define-method load_url + (of-object "GeckoEmbed") + (c-name "gecko_embed_load_url") + (return-type "none") + (parameters + '("const-char*" "url") + ) +) + +(define-method stop_load + (of-object "GeckoEmbed") + (c-name "gecko_embed_stop_load") + (return-type "none") +) + +(define-method can_go_back + (of-object "GeckoEmbed") + (c-name "gecko_embed_can_go_back") + (return-type "gboolean") +) + +(define-method can_go_forward + (of-object "GeckoEmbed") + (c-name "gecko_embed_can_go_forward") + (return-type "gboolean") +) + +(define-method go_back + (of-object "GeckoEmbed") + (c-name "gecko_embed_go_back") + (return-type "none") +) + +(define-method go_forward + (of-object "GeckoEmbed") + (c-name "gecko_embed_go_forward") + (return-type "none") +) + +(define-method render_data + (of-object "GeckoEmbed") + (c-name "gecko_embed_render_data") + (return-type "none") + (parameters + '("const-char*" "data") + '("guint32" "len") + '("const-char*" "base_uri") + '("const-char*" "mime_type") + ) +) + +(define-method open_stream + (of-object "GeckoEmbed") + (c-name "gecko_embed_open_stream") + (return-type "none") + (parameters + '("const-char*" "base_uri") + '("const-char*" "mime_type") + ) +) + +(define-method append_data + (of-object "GeckoEmbed") + (c-name "gecko_embed_append_data") + (return-type "none") + (parameters + '("const-char*" "data") + '("guint32" "len") + ) +) + +(define-method close_stream + (of-object "GeckoEmbed") + (c-name "gecko_embed_close_stream") + (return-type "none") +) + +(define-method get_link_message + (of-object "GeckoEmbed") + (c-name "gecko_embed_get_link_message") + (return-type "char*") +) + +(define-method get_js_status + (of-object "GeckoEmbed") + (c-name "gecko_embed_get_js_status") + (return-type "char*") +) + +(define-method get_title + (of-object "GeckoEmbed") + (c-name "gecko_embed_get_title") + (return-type "char*") +) + +(define-method get_location + (of-object "GeckoEmbed") + (c-name "gecko_embed_get_location") + (return-type "char*") +) + +(define-method reload + (of-object "GeckoEmbed") + (c-name "gecko_embed_reload") + (return-type "none") + (parameters + '("gint32" "flags") + ) +) + +(define-method set_chrome_mask + (of-object "GeckoEmbed") + (c-name "gecko_embed_set_chrome_mask") + (return-type "none") + (parameters + '("guint32" "flags") + ) +) + +(define-method get_chrome_mask + (of-object "GeckoEmbed") + (c-name "gecko_embed_get_chrome_mask") + (return-type "guint32") +) + + diff --git a/embed/xulrunner/bindings/python/gnomegeckoembed.override b/embed/xulrunner/bindings/python/gnomegeckoembed.override new file mode 100644 index 000000000..e40fb9afe --- /dev/null +++ b/embed/xulrunner/bindings/python/gnomegeckoembed.override @@ -0,0 +1,19 @@ +%% +headers +#include <Python.h> + +#include "pygobject.h" +#include "gecko-embed.h" +#include "gecko-embed-single.h" + +%% +modulename gnomegeckoembed +%% +import gobject.GObject as PyGObject_Type +import gtk.Object as PyGtkObject_Type +import gtk.Bin as PyGtkBin_Type +%% +ignore-glob + *_get_type + _* +%% diff --git a/embed/xulrunner/bindings/python/gnomegeckoembedmodule.c b/embed/xulrunner/bindings/python/gnomegeckoembedmodule.c new file mode 100644 index 000000000..f7786fa17 --- /dev/null +++ b/embed/xulrunner/bindings/python/gnomegeckoembedmodule.c @@ -0,0 +1,29 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* include this first, before NO_IMPORT_PYGOBJECT is defined */ +#include <pygobject.h> + +void pygtkmozembed_register_classes (PyObject *d); +void pygtkmozembed_add_constants(PyObject *module, const gchar *strip_prefix); + +extern PyMethodDef pygnomegeckoembed_functions[]; + +DL_EXPORT(void) +initgnomegeckoembed(void) +{ + PyObject *m, *d; + + init_pygobject (); + + m = Py_InitModule ("gnomegeckoembed", pygnomegeckoembed_functions); + d = PyModule_GetDict (m); + + pygnomegeckoembed_register_classes (d); + /*pygnomegeckoembed_add_constants(m, "GNOME_GECKO_EMBED_");*/ + + if (PyErr_Occurred ()) { + Py_FatalError ("can't initialise module gnomegeckoembed"); + } +} diff --git a/embed/xulrunner/bindings/python/test.py b/embed/xulrunner/bindings/python/test.py new file mode 100644 index 000000000..d06278e5f --- /dev/null +++ b/embed/xulrunner/bindings/python/test.py @@ -0,0 +1,32 @@ +#! /usr/bin/python +import pygtk +pygtk.require("2.0") +import gtk +import gnomegeckoembed +import os + +class Base: + def destroy(self, widget, data=None): + gtk.main_quit() + + def __init__(self): + gnomegeckoembed.gecko_embed_single_set_comp_path("/usr/lib/firefox") + gnomegeckoembed.gecko_embed_single_push_startup() + self.browser = gnomegeckoembed.Embed() + self.browser.load_url("www.gnome.org") + + self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) + self.window.connect("destroy", self.destroy) + self.window.set_default_size(800, 600) + self.window.add(self.browser) + self.browser.show() + self.window.show() + + def main(self): + gtk.main() + +print __name__ +if __name__ == "__main__": + base = Base() + base.main() + diff --git a/embed/xulrunner/data/Makefile.am b/embed/xulrunner/data/Makefile.am new file mode 100644 index 000000000..3363f76b4 --- /dev/null +++ b/embed/xulrunner/data/Makefile.am @@ -0,0 +1,3 @@ +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = gnome-gecko-embed-$(GGE_API_VERSION).pc + diff --git a/embed/xulrunner/data/gnome-gecko-embed.pc.in b/embed/xulrunner/data/gnome-gecko-embed.pc.in new file mode 100644 index 000000000..c9887651b --- /dev/null +++ b/embed/xulrunner/data/gnome-gecko-embed.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: GNOME Gecko Embed Library +Description: GNOME Gecko Embed Library +Version: @GGE_VERSION@ +Requires: gtk+-2.0, @GECKO@-xpcom +Libs: -L${libdir} +Cflags: -I${includedir} diff --git a/embed/xulrunner/embed/AutoJSContextStack.cpp b/embed/xulrunner/embed/AutoJSContextStack.cpp new file mode 100644 index 000000000..97fa84f33 --- /dev/null +++ b/embed/xulrunner/embed/AutoJSContextStack.cpp @@ -0,0 +1,47 @@ +/* + * Copyright © 2006 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#include "mozilla-config.h" +#include "config.h" + +#include <nsServiceManagerUtils.h> + +#include "AutoJSContextStack.h" + +AutoJSContextStack::~AutoJSContextStack() +{ + if (mStack) + { + JSContext* cx; + mStack->Pop (&cx); + + NS_ASSERTION(cx == nsnull, "We pushed a null context but popped a non-null context!?"); + } +} + +nsresult +AutoJSContextStack::Init() +{ + nsresult rv; + mStack = do_GetService ("@mozilla.org/js/xpc/ContextStack;1", &rv); + if (NS_FAILED (rv)) return rv; + + return mStack->Push (nsnull); +} diff --git a/embed/xulrunner/embed/AutoJSContextStack.h b/embed/xulrunner/embed/AutoJSContextStack.h new file mode 100644 index 000000000..0db423a64 --- /dev/null +++ b/embed/xulrunner/embed/AutoJSContextStack.h @@ -0,0 +1,41 @@ +/* + * Copyright © 2006 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#ifndef AUTO_JSCONTEXTSTACK_H +#define AUTO_JSCONTEXTSTACK_H + +struct JSContext; + +#include <nsCOMPtr.h> +#include <nsIJSContextStack.h> + +class AutoJSContextStack +{ + public: + AutoJSContextStack () { } + ~AutoJSContextStack (); + + nsresult Init (); + + private: + nsCOMPtr<nsIJSContextStack> mStack; +}; + +#endif diff --git a/embed/xulrunner/embed/AutoWindowModalState.cpp b/embed/xulrunner/embed/AutoWindowModalState.cpp new file mode 100644 index 000000000..0ff11e4ab --- /dev/null +++ b/embed/xulrunner/embed/AutoWindowModalState.cpp @@ -0,0 +1,61 @@ +/* + * Copyright © 2006 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#include <mozilla-config.h> +#include "config.h" + +#include "AutoWindowModalState.h" + +AutoWindowModalState::AutoWindowModalState (nsIDOMWindow *aWindow) +{ +#ifdef HAVE_GECKO_1_8_1 + if (aWindow) { + mWindow = do_QueryInterface (aWindow); + NS_ASSERTION (mWindow, "Should have a window here!"); + } + + if (mWindow) { +#ifdef HAVE_GECKO_1_9 + mWindow->EnterModalState (); +#else + nsCOMPtr<nsPIDOMWindow_MOZILLA_1_8_BRANCH> window (do_QueryInterface (mWindow)); + NS_ENSURE_TRUE (window, ); + + window->EnterModalState (); +#endif /* HAVE_GECKO_1_9 */ + } +#endif /* HAVE_GECKO_1_8_1 */ +} + +AutoWindowModalState::~AutoWindowModalState() +{ +#ifdef HAVE_GECKO_1_8_1 + if (mWindow) { +#ifdef HAVE_GECKO_1_9 + mWindow->LeaveModalState (); +#else + nsCOMPtr<nsPIDOMWindow_MOZILLA_1_8_BRANCH> window (do_QueryInterface (mWindow)); + NS_ENSURE_TRUE (window, ); + + window->LeaveModalState (); +#endif /* HAVE_GECKO_1_9 */ + } +#endif /* HAVE_GECKO_1_8_1 */ +} diff --git a/embed/xulrunner/embed/AutoWindowModalState.h b/embed/xulrunner/embed/AutoWindowModalState.h new file mode 100644 index 000000000..557865799 --- /dev/null +++ b/embed/xulrunner/embed/AutoWindowModalState.h @@ -0,0 +1,38 @@ +/* + * Copyright © 2006 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#ifndef AUTO_WINDOWMODALSTATE_H +#define AUTO_WINDOWMODALSTATE_H + +#include <nsCOMPtr.h> +#include <nsPIDOMWindow.h> + +class AutoWindowModalState +{ + public: + AutoWindowModalState (nsIDOMWindow *); + ~AutoWindowModalState (); + + private: + + nsCOMPtr<nsPIDOMWindow> mWindow; +}; + +#endif diff --git a/embed/xulrunner/embed/ContentHandler.cpp b/embed/xulrunner/embed/ContentHandler.cpp new file mode 100644 index 000000000..0510aa3f1 --- /dev/null +++ b/embed/xulrunner/embed/ContentHandler.cpp @@ -0,0 +1,479 @@ +/* + * Copyright © 2001 Philip Langdale + * Copyright © 2003 Marco Pesenti Gritti + * Copyright © 2003 Xan Lopez + * Copyright © 2004 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#include "mozilla-config.h" +#include "config.h" + +#include <glib/gi18n.h> +#include <gtk/gtkbutton.h> +#include <gtk/gtkdialog.h> +#include <gtk/gtkimage.h> +#include <gtk/gtkmain.h> +#include <gtk/gtkmessagedialog.h> +#include <gtk/gtkstock.h> +#include <libgnomevfs/gnome-vfs-mime.h> +#include <libgnomevfs/gnome-vfs-utils.h> + +#include <nsStringAPI.h> + +#include <nsCExternalHandlerService.h> +#include <nsComponentManagerUtils.h> +#include <nsIDOMWindow.h> +#include <nsIInterfaceRequestorUtils.h> +#include <nsILocalFile.h> +#include <nsIMIMEInfo.h> +#include <nsIURL.h> +#include <nsMemory.h> +#include <nsNetError.h> +#include <nsServiceManagerUtils.h> + +#include "eel-gconf-extensions.h" +#include "ephy-debug.h" +#include "ephy-embed-shell.h" +#include "ephy-embed-single.h" +#include "ephy-file-chooser.h" +#include "ephy-file-helpers.h" +#include "ephy-gui.h" +#include "ephy-prefs.h" +#include "ephy-stock-icons.h" + +#include "AutoJSContextStack.h" +#include "AutoWindowModalState.h" +#include "EphyUtils.h" +#include "MozDownload.h" + +#include "ContentHandler.h" + +/* FIXME: we don't generally have a timestamp for the user action which initiated this + * content handler. + */ +GContentHandler::GContentHandler() +: mUserTime(0) +{ + LOG ("GContentHandler ctor (%p)", this); +} + +GContentHandler::~GContentHandler() +{ + LOG ("GContentHandler dtor (%p)", this); +} + +NS_IMPL_ISUPPORTS1(GContentHandler, nsIHelperAppLauncherDialog) + +/* void show (in nsIHelperAppLauncher aLauncher, in nsISupports aContext, in unsigned long aReason); */ +NS_IMETHODIMP +GContentHandler::Show (nsIHelperAppLauncher *aLauncher, + nsISupports *aContext, + PRUint32 aReason) +{ + nsresult rv; + EphyEmbedSingle *single; + gboolean handled = FALSE; + + /* FIXME: handle aForced / aReason argument in some way? */ + + mContext = aContext; + + /* Check for a potential veto */ + nsCOMPtr<nsIDOMWindow> window (do_GetInterface (aContext)); + GtkWidget *embed = EphyUtils::FindEmbed (window); + if (EPHY_IS_EMBED (embed)) + { + if (g_object_get_data (G_OBJECT (embed), "content-handler-deny")) + { + return NS_OK; + } + } + + mLauncher = aLauncher; + rv = Init (); + NS_ENSURE_SUCCESS (rv, rv); + + single = EPHY_EMBED_SINGLE (ephy_embed_shell_get_embed_single (embed_shell)); + g_signal_emit_by_name (single, "handle_content", mMimeType.get(), + mUrl.get(), &handled); + + if (!handled) + { + MIMEInitiateAction (); + } + else + { + mLauncher->Cancel (NS_BINDING_ABORTED); + } + + return NS_OK; +} + +/* nsILocalFile promptForSaveToFile (in nsISupports aWindowContext, in wstring aDefaultFile, in wstring aSuggestedFileExtension); */ +NS_IMETHODIMP GContentHandler::PromptForSaveToFile( + nsIHelperAppLauncher *aLauncher, + nsISupports *aWindowContext, + const PRUnichar *aDefaultFile, + const PRUnichar *aSuggestedFileExtension, + nsILocalFile **_retval) +{ + EphyFileChooser *dialog; + int response; + char *filename = NULL; + nsCString defaultFile; + + NS_UTF16ToCString (nsString (aDefaultFile), + NS_CSTRING_ENCODING_UTF8, defaultFile); + + if (mAction != CONTENT_ACTION_SAVEAS) + { + return BuildDownloadPath (defaultFile.get(), _retval); + } + + nsresult rv; + AutoJSContextStack stack; + rv = stack.Init (); + if (NS_FAILED (rv)) return rv; + + nsCOMPtr<nsIDOMWindow> parentDOMWindow (do_GetInterface (aWindowContext)); + GtkWidget *parentWindow = GTK_WIDGET (EphyUtils::FindGtkParent (parentDOMWindow)); + + AutoWindowModalState modalState (parentDOMWindow); + + dialog = ephy_file_chooser_new (_("Save"), parentWindow, + GTK_FILE_CHOOSER_ACTION_SAVE, + CONF_STATE_SAVE_DIR, + EPHY_FILE_FILTER_ALL); + gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), TRUE); + gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), defaultFile.get()); + + if (parentWindow) + { + gtk_window_group_add_window (ephy_gui_ensure_window_group (GTK_WINDOW (parentWindow)), + GTK_WINDOW (dialog)); + } + + /* FIXME: this will only be the real user time if we came from ::Show */ + ephy_gui_window_update_user_time (GTK_WIDGET (dialog), (guint32) mUserTime); + + /* FIXME: modal -- mozilla sucks! */ + do + { + g_free (filename); + response = gtk_dialog_run (GTK_DIALOG (dialog)); + filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog)); + } while (response == GTK_RESPONSE_ACCEPT + && !ephy_gui_check_location_writable (GTK_WIDGET (dialog), filename)); + + if (response == GTK_RESPONSE_ACCEPT) + { + nsCOMPtr <nsILocalFile> destFile (do_CreateInstance(NS_LOCAL_FILE_CONTRACTID)); + NS_ENSURE_TRUE (destFile, NS_ERROR_FAILURE); + + destFile->InitWithNativePath (nsCString (filename)); + g_free (filename); + + NS_IF_ADDREF (*_retval = destFile); + + gtk_widget_destroy (GTK_WIDGET (dialog)); + + return NS_OK; + } + else + { + gtk_widget_destroy (GTK_WIDGET (dialog)); + g_free (filename); + + return NS_ERROR_FAILURE; + } +} + +NS_METHOD GContentHandler::Init () +{ + nsresult rv; + + NS_ENSURE_TRUE (mLauncher, NS_ERROR_FAILURE); + + nsCOMPtr<nsIMIMEInfo> MIMEInfo; + mLauncher->GetMIMEInfo (getter_AddRefs(MIMEInfo)); + NS_ENSURE_TRUE (MIMEInfo, NS_ERROR_FAILURE); + + rv = MIMEInfo->GetMIMEType (mMimeType); + + nsCOMPtr<nsIURI> uri; + mLauncher->GetSource (getter_AddRefs(uri)); + NS_ENSURE_TRUE (uri, NS_ERROR_FAILURE); + + uri->GetSpec (mUrl); + + return NS_OK; +} + +static void +response_cb (GtkWidget *dialog, + int response, + GContentHandler *self) +{ + gtk_widget_destroy (dialog); + + if (response > 0) + { + self->mAction = (ContentAction) response; + } + else + { + self->mAction = CONTENT_ACTION_NONE; + } + + self->MIMEDoAction (); +} + +static void +release_cb (GContentHandler *data) +{ + NS_RELEASE (data); +} + +NS_METHOD GContentHandler::MIMEConfirmAction () +{ + GtkWidget *dialog, *button, *image; + const char *action_label; + const char *mime_description; + nsCString file_name; + + nsCOMPtr<nsIDOMWindow> parentDOMWindow = do_GetInterface (mContext); + GtkWindow *parentWindow = GTK_WINDOW (EphyUtils::FindGtkParent(parentDOMWindow)); + + action_label = (mAction == CONTENT_ACTION_OPEN) || + (mAction == CONTENT_ACTION_OPEN_TMP) ? + GTK_STOCK_OPEN : STOCK_DOWNLOAD; + + mime_description = gnome_vfs_mime_get_description (mMimeType.get()); + if (mime_description == NULL) + { + /* Translators: The text before the "|" is context to help you decide on + * the correct translation. You MUST OMIT it in the translated string. */ + mime_description = Q_("File Type:|Unknown"); + } + + /* We have one tiny, minor issue, the filename can be empty (""), + is that severe enough to be completely fixed ? */ + nsString suggested; + + mLauncher->GetSuggestedFileName (suggested); + NS_UTF16ToCString (suggested, + NS_CSTRING_ENCODING_UTF8, file_name); + + if (mPermission != EPHY_MIME_PERMISSION_SAFE && mHelperApp) + { + dialog = gtk_message_dialog_new + (parentWindow, GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_WARNING, GTK_BUTTONS_NONE, + _("Download this potentially unsafe file?")); + + gtk_message_dialog_format_secondary_text + (GTK_MESSAGE_DIALOG (dialog), + /* translators: First %s is the file type description, + Second %s is the file name */ + _("File Type: “%s”.\n\nIt is unsafe to open “%s” as " + "it could potentially damage your documents or " + "invade your privacy. You can download it instead."), + mime_description, file_name.get()); + } + else if (mAction == CONTENT_ACTION_OPEN_TMP && mHelperApp) + { + dialog = gtk_message_dialog_new + (parentWindow, GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, + _("Open this file?")); + + gtk_message_dialog_format_secondary_text + (GTK_MESSAGE_DIALOG (dialog), + /* translators: First %s is the file type description, + Second %s is the file name, + Third %s is the application used to open the file */ + _("File Type: “%s”.\n\nYou can open “%s” using “%s” or save it."), + mime_description, file_name.get(), mHelperApp->name); + } + else + { + dialog = gtk_message_dialog_new + (parentWindow, GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, + _("Download this file?")); + + gtk_message_dialog_format_secondary_text + (GTK_MESSAGE_DIALOG (dialog), + /* translators: First %s is the file type description, + Second %s is the file name */ + _("File Type: “%s”.\n\nYou have no application able to open “%s”. " + "You can download it instead."), + mime_description, file_name.get()); + } + + button = gtk_button_new_with_label (_("_Save As...")); + image = gtk_image_new_from_stock (GTK_STOCK_SAVE_AS, GTK_ICON_SIZE_BUTTON); + gtk_button_set_image (GTK_BUTTON (button), image); + /* don't show the image! see bug #307818 */ + gtk_widget_show (button); + gtk_dialog_add_action_widget (GTK_DIALOG (dialog), button, CONTENT_ACTION_SAVEAS); + + gtk_dialog_add_button (GTK_DIALOG (dialog), + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); + gtk_dialog_add_button (GTK_DIALOG (dialog), + action_label, mAction); + + gtk_window_set_icon_name (GTK_WINDOW (dialog), EPHY_STOCK_EPHY); + + int defaultResponse = mAction == CONTENT_ACTION_NONE + ? (int) GTK_RESPONSE_CANCEL + : (int) mAction; + gtk_dialog_set_default_response (GTK_DIALOG (dialog), defaultResponse); + + NS_ADDREF_THIS(); + g_signal_connect_data (dialog, "response", + G_CALLBACK (response_cb), this, + (GClosureNotify) release_cb, (GConnectFlags) 0); + + /* FIXME: should find a way to get the user time of the user action which + * initiated this content handler + */ + gtk_window_present (GTK_WINDOW (dialog)); + + return NS_OK; +} + +NS_METHOD GContentHandler::MIMEInitiateAction (void) +{ + gboolean auto_downloads; + + if (eel_gconf_get_boolean (CONF_LOCKDOWN_DISABLE_SAVE_TO_DISK)) return NS_OK; + + auto_downloads = eel_gconf_get_boolean (CONF_AUTO_DOWNLOADS); + + mHelperApp = gnome_vfs_mime_get_default_application (mMimeType.get()); + mPermission = ephy_file_check_mime (mMimeType.get()); + + /* HACK! Check that this 'helper application' isn't Epiphany itself, + * see bug #310023. + */ + if (mHelperApp) + { + const char *id = gnome_vfs_mime_application_get_desktop_id (mHelperApp); + + /* FIXME! menu editing can make this check fail!!!! */ + if (id && strcmp (id, "epiphany.desktop") == 0) + { + mHelperApp = nsnull; + } + } + + if (auto_downloads) + { + mAction = CONTENT_ACTION_OPEN; + } + else + { + mAction = CONTENT_ACTION_OPEN_TMP; + } + + if (!mHelperApp || mPermission != EPHY_MIME_PERMISSION_SAFE) + { + mAction = CONTENT_ACTION_DOWNLOAD; + } + + if (!auto_downloads || mAction == CONTENT_ACTION_DOWNLOAD) + { + MIMEConfirmAction (); + } + else + { + MIMEDoAction (); + } + + return NS_OK; +} + +NS_METHOD GContentHandler::MIMEDoAction (void) +{ + /* This is okay, since we either clicked on a button, or we get 0 */ + mUserTime = gtk_get_current_event_time (); + + nsCOMPtr<nsIMIMEInfo> mimeInfo; + mLauncher->GetMIMEInfo(getter_AddRefs(mimeInfo)); + NS_ENSURE_TRUE (mimeInfo, NS_ERROR_FAILURE); + + char *info = NULL; + + if (mAction == CONTENT_ACTION_OPEN) + { + g_return_val_if_fail (mHelperApp, NS_ERROR_FAILURE); + + const char *id; + id = gnome_vfs_mime_application_get_desktop_id (mHelperApp); + + /* The current time is fine here as the user has just clicked + * a button (it is used as the time for the application opening) + */ + info = g_strdup_printf ("gnome-default:%d:%s", gtk_get_current_event_time(), id); + } + else if (mAction == CONTENT_ACTION_DOWNLOAD) + { + info = g_strdup_printf ("gnome-browse-to-file:%d", gtk_get_current_event_time()); + } + + /* See http://bugzilla.gnome.org/show_bug.cgi?id=456945 */ +#ifndef HAVE_GECKO_1_9 + if (info != NULL) + { + nsString desc; + NS_CStringToUTF16 (nsCString (info), + NS_CSTRING_ENCODING_UTF8, desc); + g_free (info); + + /* HACK we use the application description to ask + MozDownload to open the file when download + is finished */ + mimeInfo->SetApplicationDescription (desc); + } + else + { + mimeInfo->SetApplicationDescription (nsString ()); + } +#endif /* HAVE_GECKO_1_9 */ + + if (mAction == CONTENT_ACTION_OPEN) + { + mLauncher->SaveToDisk (nsnull, PR_FALSE); + } + else if (mAction == CONTENT_ACTION_OPEN_TMP) + { + mLauncher->LaunchWithApplication (nsnull, PR_FALSE); + } + else if (mAction == CONTENT_ACTION_NONE) + { + mLauncher->Cancel (NS_BINDING_ABORTED); + } + else + { + mLauncher->SaveToDisk (nsnull, PR_FALSE); + } + + return NS_OK; +} diff --git a/embed/xulrunner/embed/ContentHandler.h b/embed/xulrunner/embed/ContentHandler.h new file mode 100644 index 000000000..113e29070 --- /dev/null +++ b/embed/xulrunner/embed/ContentHandler.h @@ -0,0 +1,81 @@ +/* + * Copyright © 2000-2003 Marco Pesenti Gritti, + * Copyright © 2003 Xan Lopez + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#ifndef CONTENT_HANDLER_H +#define CONTENT_HANDLER_H + +#include <libgnomevfs/gnome-vfs-mime-handlers.h> + +#include <nsCOMPtr.h> +#include <nsIFile.h> +#include <nsIHelperAppLauncherDialog.h> +#include <nsIURI.h> + +#include "ephy-file-helpers.h" + + +typedef enum +{ + CONTENT_ACTION_OPEN = 1, + CONTENT_ACTION_OPEN_TMP, + CONTENT_ACTION_DOWNLOAD, + CONTENT_ACTION_SAVEAS, + CONTENT_ACTION_NONE +} ContentAction; + +#define G_CONTENTHANDLER_CID \ +{ /* 16072c4a-23a6-4996-9beb-9335c06bbeae */ \ + 0x16072c4a, \ + 0x23a6, \ + 0x4996, \ + {0x9b, 0xeb, 0x93, 0x35, 0xc0, 0x6b, 0xbe, 0xae} \ +} + +class GContentHandler : public nsIHelperAppLauncherDialog +{ + public: + NS_DECL_ISUPPORTS + NS_DECL_NSIHELPERAPPLAUNCHERDIALOG + + GContentHandler(); + virtual ~GContentHandler(); + + NS_METHOD MIMEDoAction (); + ContentAction mAction; + private: + + NS_METHOD Init (); + + NS_METHOD MIMEInitiateAction (); + NS_METHOD MIMEConfirmAction (); + + nsCOMPtr<nsIHelperAppLauncher> mLauncher; + nsCOMPtr<nsISupports> mContext; + + GnomeVFSMimeApplication *mHelperApp; + EphyMimePermission mPermission; + + nsCString mUrl; + nsCString mMimeType; + PRUint32 mUserTime; +}; + +#endif /* CONTENT_HANDLER_H */ diff --git a/embed/xulrunner/embed/EphyAboutModule.cpp b/embed/xulrunner/embed/EphyAboutModule.cpp new file mode 100644 index 000000000..6fb6a5849 --- /dev/null +++ b/embed/xulrunner/embed/EphyAboutModule.cpp @@ -0,0 +1,725 @@ +/* + * Copyright © 2001 Matt Aubury, Philip Langdale + * Copyright © 2004 Crispin Flowerday + * Copyright © 2005 Christian Persch + * Copyright © 2005 Adam Hooper + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#include "mozilla-config.h" +#include "config.h" + +#include <string.h> + +#include <glib/gi18n.h> +#include <gtk/gtk.h> + +// we need nsEscape which depends on internal strings :((( +#define MOZILLA_INTERNAL_API 1 +#include <nsString.h> + +#include <nsAutoPtr.h> +#include <nsCOMPtr.h> +#include <nsEscape.h> +#include <nsIChannel.h> +#include <nsIInputStreamChannel.h> +#include <nsIInputStream.h> +#include <nsIIOService.h> +#include <nsIOutputStream.h> +#include <nsIScriptSecurityManager.h> +#include <nsIStorageStream.h> +#include <nsIURI.h> +#include <nsNetCID.h> +#include <nsNetUtil.h> +#include <nsServiceManagerUtils.h> + +#include "ephy-debug.h" + +#include "EphyRedirectChannel.h" + +#include "EphyAboutModule.h" + +EphyAboutModule::EphyAboutModule() +{ + LOG ("EphyAboutModule ctor [%p]\n", this); +} + +EphyAboutModule::~EphyAboutModule() +{ + LOG ("EphyAboutModule dtor [%p]\n", this); +} + +NS_IMPL_ISUPPORTS1 (EphyAboutModule, nsIAboutModule) + +/* nsIChannel newChannel (in nsIURI aURI); */ +NS_IMETHODIMP +EphyAboutModule::NewChannel(nsIURI *aURI, + nsIChannel **_retval) +{ + NS_ENSURE_ARG(aURI); + + nsCAutoString path; + aURI->GetPath (path); + + if (strncmp (path.get(), "neterror?", strlen ("neterror?")) == 0) + { + return CreateErrorPage (aURI, _retval); + } + + if (strncmp (path.get (), "recover?", strlen ("recover?")) == 0) + { + return CreateRecoverPage (aURI, _retval); + } + + if (strcmp (path.get (), "epiphany") == 0) + { + return Redirect (nsDependentCString ("file://" SHARE_DIR "/epiphany.xhtml"), _retval); + } + + return NS_ERROR_ILLEGAL_VALUE; +} + +#ifdef HAVE_GECKO_1_9 +/* unsigned long getURIFlags(in nsIURI aURI); */ +NS_IMETHODIMP +EphyAboutModule::GetURIFlags (nsIURI *aURI, + PRUint32 *_result) +{ + *_result = 0; + return NS_OK; +} +#endif + +/* private functions */ + +nsresult +EphyAboutModule::Redirect(const nsACString &aURL, + nsIChannel **_retval) +{ + *_retval = nsnull; + + nsresult rv; + nsCOMPtr<nsIURI> uri; + rv = NS_NewURI (getter_AddRefs (uri), aURL); + NS_ENSURE_SUCCESS (rv, rv); + + nsCOMPtr<nsIChannel> tempChannel; + rv = NS_NewChannel (getter_AddRefs (tempChannel), uri); + NS_ENSURE_SUCCESS (rv, rv); + + tempChannel->SetOriginalURI (uri); + + nsCOMPtr<nsIScriptSecurityManager> securityManager = + do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); + NS_ENSURE_SUCCESS (rv, rv); + + nsCOMPtr<nsIPrincipal> principal; + rv = securityManager->GetCodebasePrincipal(uri, getter_AddRefs(principal)); + NS_ENSURE_SUCCESS (rv, rv); + + rv = tempChannel->SetOwner(principal); + NS_ENSURE_SUCCESS (rv, rv); + + tempChannel.swap (*_retval); + + return NS_OK; +} + +nsresult +EphyAboutModule::ParseURL(const char *aURL, + nsACString &aCode, + nsACString &aRawOriginURL, + nsACString &aOriginURL, + nsACString &aOriginCharset, + nsACString &aTitle) +{ + /* The page URL is of the form "about:neterror?e=<errorcode>&u=<URL>&c=<charset>&d=<description>" */ + const char *query = strstr (aURL, "?"); + if (!query) return NS_ERROR_FAILURE; + + /* skip the '?' */ + ++query; + + char **params = g_strsplit (query, "&", -1); + if (!params) return NS_ERROR_FAILURE; + + for (PRUint32 i = 0; params[i] != NULL; ++i) + { + char *param = params[i]; + + if (strlen (param) <= 2) continue; + + switch (param[0]) + { + case 'e': + aCode.Assign (nsUnescape (param + 2)); + break; + case 'u': + aRawOriginURL.Assign (param + 2); + aOriginURL.Assign (nsUnescape (param + 2)); + break; + case 'c': + aOriginCharset.Assign (nsUnescape (param + 2)); + break; + /* The next one is not used in neterror but recover: */ + case 't': + aTitle.Assign (nsUnescape (param + 2)); + break; + case 'd': + /* we don't need mozilla's description parameter */ + default: + break; + } + } + + g_strfreev (params); + + return NS_OK; +} + +nsresult +EphyAboutModule::GetErrorMessage(nsIURI *aURI, + const char *aError, + char **aStockIcon, + char **aTitle, + char **aPrimary, + char **aSecondary, + char **aTertiary, + char **aLinkIntro) +{ + *aStockIcon = GTK_STOCK_DIALOG_ERROR; + + if (strcmp (aError, "protocolNotFound") == 0) + { + nsCAutoString scheme; + aURI->GetScheme (scheme); + + /* Translators: %s is the name of a protocol, like "http" etc. */ + *aTitle = g_strdup_printf (_("“%s” Protocol is not Supported"), scheme.get()); + /* Translators: %s is the name of a protocol, like "http" etc. */ + *aPrimary = g_strdup_printf (_("“%s” protocol is not supported."), scheme.get()); + /* FIXME: get the list of supported protocols from necko */ + *aSecondary = g_strdup (_("Supported protocols are “http”, “https”, “ftp”, “file”, “smb” " + "and “sftp”.")); + } + else if (strcmp (aError, "fileNotFound") == 0) + { + nsCAutoString path; + aURI->GetPath (path); + + /* Translators: %s is the path and filename, for example "/home/user/test.html" */ + *aTitle = g_markup_printf_escaped (_("File “%s” not Found"), path.get()); + /* Translators: %s is the path and filename, for example "/home/user/test.html" */ + *aPrimary = g_markup_printf_escaped (_("File “%s” not found."), path.get()); + *aSecondary = g_strdup (_("Check the location of the file and try again.")); + } + else if (strcmp (aError, "dnsNotFound") == 0) + { + nsCAutoString host; + aURI->GetHost (host); + + /* Translators: %s is the hostname, like "www.example.com" */ + *aTitle = g_markup_printf_escaped (_("“%s” Could not be Found"), + host.get()); + /* Translators: %s is the hostname, like "www.example.com" */ + *aPrimary = g_markup_printf_escaped (_("“%s” could not be found."), + host.get()); + *aSecondary = g_strdup (_("Check that you are connected to the internet, and " + "that the address is correct.")); + *aLinkIntro = _("If this page used to exist, you may find an archived version:"); + } + else if (strcmp (aError, "connectionFailure") == 0) + { + nsCAutoString host; + aURI->GetHost (host); + + /* Translators: %s is the hostname, like "www.example.com" */ + *aTitle = g_markup_printf_escaped + (_("“%s” Refused the Connection"), + host.get()); + /* Translators: %s is the hostname, like "www.example.com" */ + *aPrimary = g_markup_printf_escaped + (_("“%s” refused the connection."), + host.get()); + + /* FIXME what about 127.0.0.* ? */ + if (strcmp (host.get(), "localhost") == 0) + { + PRInt32 port; + aURI->GetPort (&port); + + *aSecondary = g_strdup (_("Likely causes of the problem are")); + + /* Try to get the service name attached to that port */ + if (port != -1) + { + struct servent *serv; + + if ((serv = getservbyport (htons (port), NULL)) != NULL) + { + *aTertiary = g_markup_printf_escaped ( + _("<ul>" + "<li>the service ""%s"" isn't started.</li>" + "Try to start it using the Services Configuration Tool in " + "System > Control Center, or</ul>" + "<ul><li>the port number %d is wrong.</li>" + "</ul>"), + serv->s_name, port); + } + else + { + *aTertiary = g_markup_printf_escaped ( + _("<ul>" + "<li>some service isn't started, or</li>" + "<li>the port number %d is wrong.</li>" + "</ul>"), + port); + } + } + else + { + *aTertiary = _("<ul>" + "<li>some service isn't started, or</li>" + "<li>you got the port number wrong.</li>" + "</ul>"); + } + } + else + { + *aSecondary = g_strdup (_("The server may be busy or you may have a " + "network connection problem. Try again later.")); + *aLinkIntro = _("There may be an old version of the page you wanted:"); + } + } + else if (strcmp (aError, "netInterrupt") == 0) + { + nsCAutoString host; + aURI->GetHost (host); + + /* Translators: %s is the hostname, like "www.example.com" */ + *aTitle = g_markup_printf_escaped + (_("“%s” Interrupted the Connection"), + host.get()); + /* Translators: %s is the hostname, like "www.example.com" */ + *aPrimary = g_markup_printf_escaped + (_("“%s” interrupted the connection."), + host.get()); + *aSecondary = g_strdup (_("The server may be busy or you may have a " + "network connection problem. Try again later.")); + *aLinkIntro = _("There may be an old version of the page you wanted:"); + } + else if (strcmp (aError, "netTimeout") == 0) + { + nsCAutoString host; + aURI->GetHost (host); + + /* Translators: %s is the hostname, like "www.example.com" */ + *aTitle = g_markup_printf_escaped + (_("“%s” is not Responding"), + host.get()); + /* Translators: %s is the hostname, like "www.example.com" */ + *aPrimary = g_markup_printf_escaped + (_("“%s” is not responding."), + host.get()); + *aSecondary = g_strdup (_("The connection was lost because the " + "server took too long to respond.")); + *aTertiary = _("The server may be busy or you may have a network " + "connection problem. Try again later."); + *aLinkIntro = _("There may be an old version of the page you wanted:"); + } + else if (strcmp (aError, "malformedURI") == 0) + { + *aTitle = g_strdup (_("Invalid Address")); + *aPrimary = g_strdup (_("Invalid address.")); + *aSecondary = g_strdup (_("The address you entered is not valid.")); + } + else if (strcmp (aError, "redirectLoop") == 0) + { + nsCAutoString host; + aURI->GetHost (host); + + /* Translators: %s is the hostname, like "www.example.com" */ + *aTitle = g_markup_printf_escaped + (_("“%s” Redirected Too Many Times"), + host.get()); + /* Translators: %s is the hostname, like "www.example.com" */ + *aPrimary = g_strdup (_("This page cannot load because of a problem with the Web site.")); + + *aSecondary = g_markup_printf_escaped + (_("The server “%s” is redirecting in a way that will never complete."), + host.get()); + *aLinkIntro = _("There may be an old version of the page you wanted:"); + } + else if (strcmp (aError, "unknownSocketType") == 0) + { + nsCAutoString host; + aURI->GetHost (host); + + /* Translators: %s is the hostname, like "www.example.com" */ + *aTitle = g_markup_printf_escaped + (_("“%s” Requires an Encrypted Connection"), + host.get()); + /* Translators: %s is the hostname, like "www.example.com" */ + *aPrimary = g_markup_printf_escaped + (_("“%s” requires an encrypted connection."), + host.get()); + *aSecondary = g_strdup (_("The document could not be loaded because " + "encryption support is not installed.")); + } + else if (strcmp (aError, "netReset") == 0) + { + nsCAutoString host; + aURI->GetHost (host); + + /* Translators: %s is the hostname, like "www.example.com" */ + *aTitle = g_markup_printf_escaped + (_("“%s” Dropped the Connection"), + host.get()); + /* Translators: %s is the hostname, like "www.example.com" */ + *aPrimary = g_markup_printf_escaped + (_("“%s” dropped the connection."), + host.get()); + *aSecondary = g_strdup (_("The server dropped the connection " + "before any data could be read.")); + *aTertiary = _("The server may be busy or you may have a " + "network connection problem. Try again later."); + *aLinkIntro = _("There may be an old version of the page you wanted:"); + } + else if (strcmp (aError, "netOffline") == 0) + { + /* Error is a bit too strong here */ + *aStockIcon = GTK_STOCK_DIALOG_INFO; + + *aTitle = g_strdup (_("Cannot Load Document Whilst Working Offline")); + *aPrimary = g_strdup (_("Cannot load document whilst working offline.")); + *aSecondary = g_strdup (_("To view this document, disable “Work Offline” and try again.")); + } + else if (strcmp (aError, "deniedPortAccess") == 0) + { + nsCAutoString host; + aURI->GetHost (host); + + PRInt32 port = -1; + aURI->GetPort (&port); + + /* Translators: %s is the hostname, like "www.example.com" */ + *aTitle = g_markup_printf_escaped + (_("“%s” Denied Access to Port “%d”"), + host.get(), port > 0 ? port : 80); + /* Translators: %s is the hostname, like "www.example.com" */ + *aPrimary = g_markup_printf_escaped + (_("“%s” denied access to port “%d”."), + host.get(), port > 0 ? port : 80); + *aSecondary = g_strdup (_("The server dropped the connection " + "before any data could be read.")); + *aTertiary = _("The server may be busy or you may have a " + "network connection problem. Try again later."); + *aLinkIntro = _("There may be an old version of the page you wanted:"); + } + else if (strcmp (aError, "proxyResolveFailure") == 0 || + strcmp (aError, "proxyConnectFailure") == 0) + { + *aTitle = g_strdup (_("Could not Connect to Proxy Server")); + *aPrimary = g_strdup (_("Could not connect to proxy server.")); + *aSecondary = g_strdup (_("Check your proxy server settings. " + "If the connection still fails, there may be " + "a problem with your proxy server or your " + "network connection.")); + } + /* This was introduced in gecko 1.9 */ + else if (strcmp (aError, "contentEncodingError") == 0) + { + *aTitle = g_strdup (_("Could not Display Content")); + *aPrimary = g_strdup (_("Could not display content.")); + *aSecondary = g_strdup (_("The page uses an unsupported or invalid form of compression.")); + } + else + { + return NS_ERROR_ILLEGAL_VALUE; + } + + return NS_OK; +} + +nsresult +EphyAboutModule::CreateErrorPage(nsIURI *aErrorURI, + nsIChannel **_retval) +{ + *_retval = nsnull; + + /* First parse the arguments */ + nsresult rv; + nsCAutoString spec; + rv = aErrorURI->GetSpec (spec); + NS_ENSURE_TRUE (NS_SUCCEEDED (rv), rv); + + nsCAutoString error, rawurl, url, charset, dummy; + rv = ParseURL (spec.get (), error, rawurl, url, charset, dummy); + if (NS_FAILED (rv)) return rv; + if (error.IsEmpty () || rawurl.IsEmpty () || url.IsEmpty()) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIURI> uri; + rv = NS_NewURI (getter_AddRefs (uri), url, charset.get()); + /* FIXME can uri be NULL if the original url was invalid? */ + NS_ENSURE_SUCCESS (rv, rv); + + char *stock_id = nsnull, *title = nsnull, *primary = nsnull, + *secondary = nsnull, *tertiary = nsnull, *linkintro = nsnull; + rv = GetErrorMessage (uri, error.get(), &stock_id, &title, &primary, + &secondary, &tertiary, &linkintro); + + /* we don't know about this error code. + * FIXME: We'd like to forward to mozilla's about:neterror handler, + * but I don't know how to. So just redirect to the same page that + * mozilla's handler redirects to. + */ + if (rv == NS_ERROR_ILLEGAL_VALUE) + { + nsCAutoString newurl(spec); + + /* remove "about:neterror" part and insert mozilla's error page url */ + newurl.Cut(0, strlen ("about:neterror")); + newurl.Insert("chrome://global/content/netError.xhtml", 0); + + return Redirect (newurl, _retval); + } + NS_ENSURE_SUCCESS (rv, rv); + NS_ENSURE_TRUE (primary && secondary, NS_ERROR_FAILURE); + + nsCOMPtr<nsIChannel> channel; + rv = WritePage (aErrorURI, uri, aErrorURI, rawurl, title, stock_id, primary, secondary, tertiary, linkintro, getter_AddRefs (channel)); + NS_ENSURE_SUCCESS (rv, rv); + + g_free (title); + g_free (primary); + g_free (secondary); + + channel.swap (*_retval); + + return NS_OK; +} + +nsresult +EphyAboutModule::CreateRecoverPage(nsIURI *aRecoverURI, + nsIChannel **_retval) +{ + *_retval = nsnull; + + /* First parse the arguments */ + nsresult rv; + nsCAutoString spec; + rv = aRecoverURI->GetSpec (spec); + NS_ENSURE_TRUE (NS_SUCCEEDED (rv), rv); + + nsCAutoString error, rawurl, url, charset, title; + rv = ParseURL (spec.get (), error, rawurl, url, charset, title); + if (NS_FAILED (rv)) return rv; + if (rawurl.IsEmpty () || url.IsEmpty()) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIURI> uri; + rv = NS_NewURI(getter_AddRefs (uri), url, charset.get()); + NS_ENSURE_SUCCESS (rv, rv); + + char *secondary = g_markup_printf_escaped + (_("The page “%s” in this tab was not fully loaded yet when " + "the web browser crashed; it could have caused the crash."), + url.get()); + + nsCOMPtr<nsIChannel> channel; + rv = WritePage (aRecoverURI, uri, uri, rawurl, title.get(), + GTK_STOCK_DIALOG_INFO, title.get() /* as primary */, + secondary, nsnull, nsnull, getter_AddRefs (channel)); + NS_ENSURE_SUCCESS (rv, rv); + + nsRefPtr<EphyRedirectChannel> redirectChannel (new EphyRedirectChannel (channel)); + if (!redirectChannel) return NS_ERROR_OUT_OF_MEMORY; + + g_free (secondary); + + NS_ADDREF(*_retval = redirectChannel); + + return NS_OK; +} + +nsresult +EphyAboutModule::WritePage(nsIURI *aOriginalURI, + nsIURI *aURI, + nsIURI *aChannelURI, + const nsACString &aRawURL, + const char *aTitle, + const char *aStockIcon, + const char *aPrimary, + const char *aSecondary, + const char *aTertiary, + const char *aLinkIntro, + nsIChannel **_retval) +{ + *_retval = nsnull; + + nsresult rv; + nsCOMPtr<nsIStorageStream> storageStream; + rv = NS_NewStorageStream (16384, (PRUint32) -1, getter_AddRefs (storageStream)); + NS_ENSURE_SUCCESS (rv, rv); + + nsCOMPtr<nsIOutputStream> stream; + rv = storageStream->GetOutputStream (0, getter_AddRefs (stream)); + NS_ENSURE_SUCCESS (rv, rv); + + char *language = g_strdup (pango_language_to_string (gtk_get_default_language ())); + g_strdelimit (language, "_-@", '\0'); + + Write (stream, + "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" + "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" " + "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n" + "<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\""); + Write (stream, language); + Write (stream, + "\" xml:lang=\""); + Write (stream, language); + Write (stream, + "\">\n" + "<head>\n" + "<title>"); + Write (stream, aTitle); + /* no favicon for now, it would pollute the favicon cache */ + /* "<link rel=\"icon\" type=\"image/png\" href=\"moz-icon://stock/gtk-dialog-error?size=16\" />\n" */ + Write (stream, + "</title>\n" + "<style type=\"text/css\">\n" + "div#body {\n" + "top: 12px;\n" + "right: 12px;\n" + "bottom: 12px;\n" + "left: 12px;\n" + "overflow: auto;\n" + + "background: -moz-dialog url('moz-icon://stock/"); + Write (stream, aStockIcon); + Write (stream, + "?size=dialog') no-repeat 12px 12px;\n" + "color: -moz-dialogtext;\n" + "font: message-box;\n" + "border: 1px solid -moz-dialogtext;\n" + + "padding: 12px 12px 12px 72px;\n" + "}\n" + + "h1 {\n" + "margin: 0;\n" + "font-size: 1.2em;\n" + "}\n" + "</style>\n" + "</head>\n" + "<body dir=\""); + Write (stream, + gtk_widget_get_default_direction () == GTK_TEXT_DIR_RTL ? "rtl" : "ltr"); + Write (stream, + "\">\n" + "<div id=\"body\">" + "<h1>"); + Write (stream, aPrimary); + Write (stream, + "</h1>\n"); + if (aSecondary) + { + Write (stream, "<p>"); + Write (stream, aSecondary); + if (aTertiary) + { + Write (stream, " "); + Write (stream, aTertiary); + } + Write (stream, "</p>\n"); + } + + PRBool isHttp = PR_FALSE, isHttps = PR_FALSE; + aURI->SchemeIs ("http", &isHttp); + aURI->SchemeIs ("https", &isHttps); + if (aLinkIntro && (isHttp || isHttps)) + { + nsCString raw(aRawURL); + + Write (stream, "<p>"); + Write (stream, aLinkIntro); + Write (stream, "<ul>\n"); + Write (stream, "<li><a href=\"http://www.google.com/search?q=cache:"); + Write (stream, raw.get()); + Write (stream, "\">"); + /* Translators: The text before the "|" is context to help you decide on + * the correct translation. You MUST OMIT it in the translated string. */ + Write (stream, Q_("You may find an old version:|in the Google Cache")); + Write (stream, "</a></li>\n"); + + Write (stream, "<li><a href=\"http://web.archive.org/web/*/"); + Write (stream, raw.get()); + Write (stream, "\">"); + /* Translators: The text before the "|" is context to help you decide on + * the correct translation. You MUST OMIT it in the translated string. */ + Write (stream, Q_("You may find an old version:|in the Internet Archive")); + Write (stream, "</a></li>\n" + "</ul>\n" + "</p>"); + } + + Write (stream, + "</div>\n" + "</body>\n" + "</html>\n"); + + g_free (language); + + /* finish the rendering */ + nsCOMPtr<nsIInputStream> inputStream; + rv = storageStream->NewInputStream (0, getter_AddRefs (inputStream)); + NS_ENSURE_SUCCESS (rv, rv); + + nsCOMPtr<nsIChannel> channel; + rv = NS_NewInputStreamChannel (getter_AddRefs (channel), + aChannelURI, + inputStream, + NS_LITERAL_CSTRING ("application/xhtml+xml"), + NS_LITERAL_CSTRING ("utf-8")); + NS_ENSURE_SUCCESS (rv, rv); + + rv = channel->SetOriginalURI (aOriginalURI); + NS_ENSURE_SUCCESS (rv, rv); + + nsCOMPtr<nsIScriptSecurityManager> securityManager + (do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv)); + NS_ENSURE_SUCCESS (rv, rv); + + nsCOMPtr<nsIPrincipal> principal; + rv = securityManager->GetCodebasePrincipal (aOriginalURI, getter_AddRefs (principal)); + NS_ENSURE_SUCCESS (rv, rv); + + rv = channel->SetOwner(principal); + NS_ENSURE_SUCCESS (rv, rv); + + channel.swap (*_retval); + + return NS_OK; +} + +nsresult +EphyAboutModule::Write(nsIOutputStream *aStream, + const char *aText) +{ + PRUint32 bytesWritten; + return aStream->Write (aText, strlen (aText), &bytesWritten); +} diff --git a/embed/xulrunner/embed/EphyAboutModule.h b/embed/xulrunner/embed/EphyAboutModule.h new file mode 100644 index 000000000..21a269c49 --- /dev/null +++ b/embed/xulrunner/embed/EphyAboutModule.h @@ -0,0 +1,65 @@ +/* + * Copyright © 2001 Matt Aubury, Philip Langdale + * Copyright © 2004 Crispin Flowerday + * Copyright © 2005 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#ifndef EPHY_ABOUT_MODULE_H +#define EPHY_ABOUT_MODULE_H + +#include <nsIAboutModule.h> + +/* a9aea13e-21de-4be8-a07e-a05f11658c55 */ +#define EPHY_ABOUT_MODULE_CID \ +{ 0xa9aea13e, 0x21de, 0x4be8, \ + { 0xa0, 0x7e, 0xa0, 0x5f, 0x11, 0x65, 0x8c, 0x55 } } + +#define EPHY_ABOUT_NETERROR_CONTRACTID NS_ABOUT_MODULE_CONTRACTID_PREFIX "neterror" +#define EPHY_ABOUT_NETERROR_CLASSNAME "Epiphany about:neterror module" + +#define EPHY_ABOUT_EPIPHANY_CONTRACTID NS_ABOUT_MODULE_CONTRACTID_PREFIX "epiphany" +#define EPHY_ABOUT_EPIPHANY_CLASSNAME "Epiphany about:epiphany module" +#define EPHY_ABOUT_RECOVER_CONTRACTID NS_ABOUT_MODULE_CONTRACTID_PREFIX "recover" +#define EPHY_ABOUT_RECOVER_CLASSNAME "Epiphany about:recover module" + +class nsIChannel; +class nsIOutputStream; +class nsIInputStreamChannel; +class nsIURI; + +class EphyAboutModule : public nsIAboutModule +{ + public: + NS_DECL_ISUPPORTS + NS_DECL_NSIABOUTMODULE + + EphyAboutModule(); + virtual ~EphyAboutModule(); + + private: + nsresult Redirect(const nsACString&, nsIChannel**); + nsresult ParseURL(const char*, nsACString&, nsACString&, nsACString&, nsACString&, nsACString&); + nsresult GetErrorMessage(nsIURI*, const char*, char**, char**, char**, char**, char**, char**); + nsresult CreateErrorPage(nsIURI*, nsIChannel**); + nsresult CreateRecoverPage(nsIURI*, nsIChannel**); + nsresult WritePage(nsIURI*, nsIURI*, nsIURI*, const nsACString&, const char*, const char*, const char*, const char*, const char*, const char*, nsIChannel**); + nsresult Write(nsIOutputStream*, const char*); +}; + +#endif /* EPHY_ABOUT_MODULE_H */ diff --git a/embed/xulrunner/embed/EphyBadCertRejector.cpp b/embed/xulrunner/embed/EphyBadCertRejector.cpp new file mode 100644 index 000000000..99ffe4393 --- /dev/null +++ b/embed/xulrunner/embed/EphyBadCertRejector.cpp @@ -0,0 +1,68 @@ +/* + * Copyright © 2005 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#include "mozilla-config.h" +#include "config.h" + +#include "EphyBadCertRejector.h" + +NS_IMPL_THREADSAFE_ISUPPORTS1 (EphyBadCertRejector, nsIBadCertListener) + +/* boolean confirmUnknownIssuer (in nsIInterfaceRequestor socketInfo, in nsIX509Cert cert, out short certAddType); */ +NS_IMETHODIMP +EphyBadCertRejector::ConfirmUnknownIssuer(nsIInterfaceRequestor *socketInfo, + nsIX509Cert *cert, + PRInt16 *certAddType, + PRBool *_retval) +{ + *certAddType = nsIBadCertListener::UNINIT_ADD_FLAG; + *_retval = PR_FALSE; + return NS_OK; +} + +/* boolean confirmMismatchDomain (in nsIInterfaceRequestor socketInfo, in AUTF8String targetURL, in nsIX509Cert cert); */ +NS_IMETHODIMP +EphyBadCertRejector::ConfirmMismatchDomain(nsIInterfaceRequestor *socketInfo, + const nsACString & targetURL, + nsIX509Cert *cert, + PRBool *_retval) +{ + *_retval = PR_FALSE; + return NS_OK; +} + +/* boolean confirmCertExpired (in nsIInterfaceRequestor socketInfo, in nsIX509Cert cert); */ +NS_IMETHODIMP +EphyBadCertRejector::ConfirmCertExpired(nsIInterfaceRequestor *socketInfo, + nsIX509Cert *cert, + PRBool *_retval) +{ + *_retval = PR_FALSE; + return NS_OK; +} + +/* void notifyCrlNextupdate (in nsIInterfaceRequestor socketInfo, in AUTF8String targetURL, in nsIX509Cert cert); */ +NS_IMETHODIMP +EphyBadCertRejector::NotifyCrlNextupdate(nsIInterfaceRequestor *socketInfo, + const nsACString & targetURL, + nsIX509Cert *cert) +{ + return NS_OK; +} diff --git a/embed/xulrunner/embed/EphyBadCertRejector.h b/embed/xulrunner/embed/EphyBadCertRejector.h new file mode 100644 index 000000000..dcab75c6c --- /dev/null +++ b/embed/xulrunner/embed/EphyBadCertRejector.h @@ -0,0 +1,36 @@ +/* + * Copyright © 2005 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#ifndef EPHY_BAD_CERT_REJECTOR_H +#define EPHY_BAD_CERT_REJECTOR_H + +#include <nsIBadCertListener.h> + +class EphyBadCertRejector : public nsIBadCertListener +{ + public: + NS_DECL_ISUPPORTS + NS_DECL_NSIBADCERTLISTENER + + EphyBadCertRejector () { } + ~EphyBadCertRejector () { } +}; + +#endif diff --git a/embed/xulrunner/embed/EphyBrowser.cpp b/embed/xulrunner/embed/EphyBrowser.cpp new file mode 100644 index 000000000..f80aeb59a --- /dev/null +++ b/embed/xulrunner/embed/EphyBrowser.cpp @@ -0,0 +1,1614 @@ +/* + * Copyright © 2000-2004 Marco Pesenti Gritti + * Copyright © 2003, 2004, 2005 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#include "mozilla-config.h" +#include "config.h" + +#include <unistd.h> + +#include <nsStringAPI.h> + +#include <nsIChannel.h> +#include <nsICommandManager.h> +#include <nsIContentViewer.h> +#include <nsIDocCharset.h> +#include <nsIDocShellTreeItem.h> +#include <nsIDocShellTreeNode.h> +#include <nsIDocShellTreeOwner.h> +#include <nsIDOM3Document.h> +#include <nsIDOMAbstractView.h> +#include <nsIDOMAbstractView.h> +#include <nsIDOMCSSPrimitiveValue.h> +#include <nsIDOMCSSStyleDeclaration.h> +#include <nsIDOMCSSStyleDeclaration.h> +#include <nsIDOMCSSValue.h> +#include <nsIDOMDocument.h> +#include <nsIDOMDocumentView.h> +#include <nsIDOMDocumentView.h> +#include <nsIDOMElement.h> +#include <nsIDOMEvent.h> +#include <nsIDOMEventTarget.h> +#include <nsIDOMHTMLCollection.h> +#include <nsIDOMHTMLDocument.h> +#include <nsIDOMHTMLDocument.h> +#include <nsIDOMHTMLElement.h> +#include <nsIDOMHTMLFormElement.h> +#include <nsIDOMHTMLInputElement.h> +#include <nsIDOMHTMLTextAreaElement.h> +#include <nsIDOMKeyEvent.h> +#include <nsIDOMMouseEvent.h> +#include <nsIDOMNode.h> +#include <nsIDOMNSEvent.h> +#include <nsIDOMNSEventTarget.h> +#include <nsIDOMPopupBlockedEvent.h> +#include <nsIDOMViewCSS.h> +#include <nsIDOMWindow2.h> +#include <nsIDOMXMLDocument.h> +#include <nsIHistoryEntry.h> +#include <nsIInterfaceRequestor.h> +#include <nsIInterfaceRequestorUtils.h> +#include <nsIPrintSettings.h> +#include <nsIPrintSettingsService.h> +#include <nsIScriptSecurityManager.h> +#include <nsIServiceManager.h> +#include <nsISHEntry.h> +#include <nsISHistory.h> +#include <nsISHistoryInternal.h> +#include <nsISimpleEnumerator.h> +#include <nsIURI.h> +#include <nsIWebBrowserFocus.h> +#include <nsIWebBrowserPrint.h> +#include <nsIWebPageDescriptor.h> +#include <nsMemory.h> +#include <nsServiceManagerUtils.h> + +#ifdef HAVE_MOZILLA_PSM +#include <nsICertificateDialogs.h> +#include <nsISSLStatus.h> +#include <nsISSLStatusProvider.h> +#include <nsITransportSecurityInfo.h> +#include <nsIX509Cert.h> +#endif + +#ifdef ALLOW_PRIVATE_API +#include <nsIContentPolicy.h> +#include <nsIDocShell.h> +#include <nsIDOMWindowInternal.h> +#include <nsIImageDocument.h> +#include <nsIMarkupDocumentViewer.h> +#endif + +#include "gecko-embed.h" +#include "gecko-embed-private.h" + +#include "ephy-debug.h" +#include "ephy-embed.h" +#include "ephy-embed-shell.h" +#include "ephy-string.h" +#include "ephy-zoom.h" +#include "mozilla-embed-event.h" +#include "mozilla-embed.h" + +#include "AutoJSContextStack.h" +#include "EphyUtils.h" +#include "EventContext.h" +#include "GeckoPrintService.h" + +#include "EphyBrowser.h" + +NS_IMPL_ISUPPORTS1(EphyEventListener, nsIDOMEventListener) + +NS_IMETHODIMP +EphyDOMLinkEventListener::HandleEvent (nsIDOMEvent* aDOMEvent) +{ + nsCOMPtr<nsIDOMEventTarget> eventTarget; + aDOMEvent->GetTarget(getter_AddRefs(eventTarget)); + + nsCOMPtr<nsIDOMElement> linkElement (do_QueryInterface (eventTarget)); + if (!linkElement) return NS_ERROR_FAILURE; + + nsresult rv; + nsString value; + rv = linkElement->GetAttribute (NS_LITERAL_STRING ("rel"), value); + if (NS_FAILED (rv)) return NS_ERROR_FAILURE; + + nsCString rel; + NS_UTF16ToCString (value, NS_CSTRING_ENCODING_UTF8, rel); + + if (g_ascii_strcasecmp (rel.get(), "SHORTCUT ICON") == 0 || + g_ascii_strcasecmp (rel.get(), "ICON") == 0) + { + nsCOMPtr<nsIDOMDocument> domDoc; + linkElement->GetOwnerDocument(getter_AddRefs(domDoc)); + NS_ENSURE_TRUE (domDoc, NS_ERROR_FAILURE); + + nsCOMPtr<nsIDOMDocumentView> docView (do_QueryInterface (domDoc)); + NS_ENSURE_TRUE (docView, NS_ERROR_FAILURE); + + nsCOMPtr<nsIDOMAbstractView> abstractView; + docView->GetDefaultView (getter_AddRefs (abstractView)); + + nsCOMPtr<nsIDOMWindow> domWin (do_QueryInterface (abstractView)); + NS_ENSURE_TRUE (domWin, NS_ERROR_FAILURE); + + nsCOMPtr<nsIDOMWindow> topDomWin; + domWin->GetTop (getter_AddRefs (topDomWin)); + + nsCOMPtr<nsISupports> domWinAsISupports (do_QueryInterface (domWin)); + nsCOMPtr<nsISupports> topDomWinAsISupports (do_QueryInterface (topDomWin)); + /* disallow subframes to set favicon */ + if (domWinAsISupports != topDomWinAsISupports) return NS_OK; + + nsCOMPtr<nsIURI> docUri; + rv = GetDocURI (linkElement, getter_AddRefs (docUri)); + NS_ENSURE_TRUE (NS_SUCCEEDED (rv) && docUri, NS_ERROR_FAILURE); + + rv = linkElement->GetAttribute (NS_LITERAL_STRING ("href"), value); + if (NS_FAILED (rv) || !value.Length()) return NS_ERROR_FAILURE; + + nsCString cLink; + NS_UTF16ToCString (value, NS_CSTRING_ENCODING_UTF8, cLink); + + nsCString faviconUrl; + rv = docUri->Resolve (cLink, faviconUrl); + NS_ENSURE_SUCCESS (rv, NS_ERROR_FAILURE); + + nsCOMPtr<nsIURI> favUri; + EphyUtils::NewURI (getter_AddRefs (favUri), faviconUrl); + NS_ENSURE_TRUE (favUri, NS_ERROR_FAILURE); + + /* Only proceed for http favicons. Bug #312291 */ + PRBool isHttp = PR_FALSE, isHttps = PR_FALSE; + favUri->SchemeIs ("http", &isHttp); + favUri->SchemeIs ("https", &isHttps); + if (!isHttp && !isHttps) return NS_OK; + + /* check if load is allowed */ + nsCOMPtr<nsIScriptSecurityManager> secMan + (do_GetService("@mozilla.org/scriptsecuritymanager;1")); + /* refuse if we can't check */ + NS_ENSURE_TRUE (secMan, NS_OK); + + rv = secMan->CheckLoadURI(docUri, favUri, + nsIScriptSecurityManager::STANDARD); + /* failure means it didn't pass the security check */ + if (NS_FAILED (rv)) return NS_OK; + + /* security check passed, now check with content policy */ + nsCOMPtr<nsIContentPolicy> policy = + do_GetService("@mozilla.org/layout/content-policy;1"); + /* refuse if we can't check */ + NS_ENSURE_TRUE (policy, NS_OK); + + linkElement->GetAttribute (NS_LITERAL_STRING ("type"), value); + + nsCString cTypeVal; + NS_UTF16ToCString (value, NS_CSTRING_ENCODING_UTF8, cTypeVal); + + PRInt16 decision = 0; + rv = policy->ShouldLoad (nsIContentPolicy::TYPE_IMAGE, + favUri, docUri, eventTarget, + cTypeVal, nsnull, + &decision); + NS_ENSURE_SUCCESS (rv, NS_ERROR_FAILURE); + if (decision != nsIContentPolicy::ACCEPT) return NS_OK; + + /* Hide password part */ + nsCString user; + favUri->GetUsername (user); + favUri->SetUserPass (user); + + nsCString spec; + favUri->GetSpec (spec); + + /* ok, we accept this as a valid favicon for this site */ + g_signal_emit_by_name (mOwner->mEmbed, "ge_favicon", spec.get()); + } + else if (g_ascii_strcasecmp (rel.get (), "search") == 0) + { + linkElement->GetAttribute (NS_LITERAL_STRING ("type"), value); + + nsCString cTypeVal; + NS_UTF16ToCString (value, NS_CSTRING_ENCODING_UTF8, cTypeVal); + + if (g_ascii_strcasecmp (cTypeVal.get (), + "application/opensearchdescription+xml") == 0) + { + rv = linkElement->GetAttribute (NS_LITERAL_STRING ("href"), value); + if (NS_FAILED (rv) || !value.Length()) return NS_ERROR_FAILURE; + + nsCString cLink; + NS_UTF16ToCString (value, NS_CSTRING_ENCODING_UTF8, cLink); + + nsCOMPtr<nsIURI> docUri; + rv = GetDocURI (linkElement, getter_AddRefs (docUri)); + NS_ENSURE_TRUE (NS_SUCCEEDED (rv) && docUri, NS_ERROR_FAILURE); + + nsCString resolvedLink; + rv = docUri->Resolve (cLink, resolvedLink); + NS_ENSURE_SUCCESS (rv, NS_ERROR_FAILURE); + + linkElement->GetAttribute (NS_LITERAL_STRING ("title"), value); + + nsCString cTitle; + NS_UTF16ToCString (value, NS_CSTRING_ENCODING_UTF8, cTitle); + + g_signal_emit_by_name (mOwner->mEmbed, "ge_search_link", + cTypeVal.get(), cTitle.get(), resolvedLink.get()); + } + } + else if (g_ascii_strcasecmp (rel.get (), "alternate") == 0) + { + linkElement->GetAttribute (NS_LITERAL_STRING ("type"), value); + + nsCString cTypeVal; + NS_UTF16ToCString (value, NS_CSTRING_ENCODING_UTF8, cTypeVal); + + if (g_ascii_strcasecmp (cTypeVal.get (), "application/rss+xml") == 0 || + g_ascii_strcasecmp (cTypeVal.get (), "application/atom+xml") == 0) + { + rv = linkElement->GetAttribute (NS_LITERAL_STRING ("href"), value); + if (NS_FAILED (rv) || !value.Length()) return NS_ERROR_FAILURE; + + nsCString cLink; + NS_UTF16ToCString (value, NS_CSTRING_ENCODING_UTF8, cLink); + + nsCOMPtr<nsIURI> docUri; + rv = GetDocURI (linkElement, getter_AddRefs (docUri)); + NS_ENSURE_TRUE (NS_SUCCEEDED (rv) && docUri, NS_ERROR_FAILURE); + + /* Hide password part */ + nsCString user; + docUri->GetUsername (user); + docUri->SetUserPass (user); + + nsCString resolvedLink; + rv = docUri->Resolve (cLink, resolvedLink); + NS_ENSURE_SUCCESS (rv, NS_ERROR_FAILURE); + + linkElement->GetAttribute (NS_LITERAL_STRING ("title"), value); + + nsCString cTitle; + NS_UTF16ToCString (value, NS_CSTRING_ENCODING_UTF8, cTitle); + + g_signal_emit_by_name (mOwner->mEmbed, "ge_feed_link", + cTypeVal.get(), cTitle.get(), resolvedLink.get()); + } + } + + return NS_OK; +} + +NS_IMETHODIMP +EphyMiscDOMEventsListener::HandleEvent (nsIDOMEvent* aDOMEvent) +{ + /* make sure the event is trusted */ + nsCOMPtr<nsIDOMNSEvent> nsEvent (do_QueryInterface (aDOMEvent)); + NS_ENSURE_TRUE (nsEvent, NS_ERROR_FAILURE); + PRBool isTrusted = PR_FALSE; + nsEvent->GetIsTrusted (&isTrusted); + if (!isTrusted) return NS_OK; + + nsresult rv; + nsString type; + rv = aDOMEvent->GetType (type); + NS_ENSURE_SUCCESS (rv, rv); + + nsCString cType; + NS_UTF16ToCString (type, NS_CSTRING_ENCODING_UTF8, cType); + + if (g_ascii_strcasecmp (cType.get(), "DOMContentLoaded") == 0) + { + g_signal_emit_by_name (mOwner->mEmbed, "dom_content_loaded", + (gpointer)aDOMEvent); + } + else if (g_ascii_strcasecmp (cType.get(), "DOMWindowClose") == 0) + { + gboolean prevent = FALSE; + + g_signal_emit_by_name (mOwner->mEmbed, "close-request", &prevent); + + if (prevent) + { + aDOMEvent->PreventDefault (); + } + } + + return NS_OK; +} + +nsresult +EphyDOMLinkEventListener::GetDocURI (nsIDOMElement *aElement, + nsIURI **aDocURI) +{ + nsCOMPtr<nsIDOMDocument> domDoc; + aElement->GetOwnerDocument (getter_AddRefs(domDoc)); + + nsCOMPtr<nsIDOM3Document> doc (do_QueryInterface (domDoc)); + NS_ENSURE_TRUE (doc, NS_ERROR_FAILURE); + + nsresult rv; + nsString spec; + rv = doc->GetDocumentURI (spec); + NS_ENSURE_SUCCESS (rv, rv); + + nsCString encoding; + rv = mOwner->GetEncoding (encoding); + NS_ENSURE_SUCCESS (rv, rv); + + return EphyUtils::NewURI (aDocURI, spec, encoding.get()); +} + +NS_IMETHODIMP +EphyPopupBlockEventListener::HandleEvent (nsIDOMEvent * aDOMEvent) +{ + nsCOMPtr<nsIDOMPopupBlockedEvent> popupEvent = + do_QueryInterface (aDOMEvent); + NS_ENSURE_TRUE (popupEvent, NS_ERROR_FAILURE); + + nsCOMPtr<nsIURI> popupWindowURI; + popupEvent->GetPopupWindowURI (getter_AddRefs (popupWindowURI)); + + nsCString popupWindowURIString; + nsresult rv; + + if (popupWindowURI) + { + rv = popupWindowURI->GetSpec (popupWindowURIString); + NS_ENSURE_SUCCESS (rv, NS_ERROR_FAILURE); + } + + nsString popupWindowFeatures; + rv = popupEvent->GetPopupWindowFeatures (popupWindowFeatures); + NS_ENSURE_SUCCESS (rv, NS_ERROR_FAILURE); + + nsCString popupWindowFeaturesString; + NS_UTF16ToCString (popupWindowFeatures, + NS_CSTRING_ENCODING_UTF8, + popupWindowFeaturesString); + + nsCString popupWindowNameString; +#ifdef HAVE_GECKO_1_9 + nsString popupWindowName; + rv = popupEvent->GetPopupWindowName (popupWindowName); + NS_ENSURE_SUCCESS (rv, NS_ERROR_FAILURE); + + NS_UTF16ToCString (popupWindowName, + NS_CSTRING_ENCODING_UTF8, + popupWindowNameString); +#endif + + g_signal_emit_by_name(mOwner->mEmbed, "ge-popup-blocked", + popupWindowURI == NULL ? NULL : popupWindowURIString.get(), + popupWindowNameString.get(), + popupWindowFeaturesString.get()); + + return NS_OK; +} + +NS_IMETHODIMP +EphyModalAlertEventListener::HandleEvent (nsIDOMEvent * aDOMEvent) +{ + NS_ENSURE_TRUE (mOwner, NS_ERROR_FAILURE); + + nsresult rv; + nsString type; + rv = aDOMEvent->GetType (type); + NS_ENSURE_SUCCESS (rv, rv); + + nsCString cType; + NS_UTF16ToCString (type, NS_CSTRING_ENCODING_UTF8, cType); + + LOG ("ModalAlertListener event %s", cType.get()); + + if (strcmp (cType.get(), "DOMWillOpenModalDialog") == 0) + { + gboolean retval = FALSE; + g_signal_emit_by_name (mOwner->mEmbed, "ge-modal-alert", &retval); + + /* suppress alert */ + if (retval) + { + aDOMEvent->PreventDefault (); + aDOMEvent->StopPropagation(); + } + } + else if (strcmp (cType.get(), "DOMModalDialogClosed") == 0) + { + g_signal_emit_by_name (mOwner->mEmbed, "ge-modal-alert-closed"); + } + + return NS_OK; +} + +NS_IMETHODIMP +EphyDOMScrollEventListener::HandleEvent (nsIDOMEvent * aEvent) +{ + nsresult rv; + nsCOMPtr<nsIDOMMouseEvent> mouseEvent (do_QueryInterface (aEvent, &rv)); + NS_ENSURE_SUCCESS (rv, rv); + + PRBool isAlt = PR_FALSE, isControl = PR_FALSE, isShift = PR_FALSE; + mouseEvent->GetAltKey (&isAlt); + mouseEvent->GetCtrlKey (&isControl); + mouseEvent->GetShiftKey (&isShift); + /* GetMetaKey is always false on gtk2 mozilla */ + + if (isControl && !isAlt && !isShift) + { + PRInt32 detail = 0; + mouseEvent->GetDetail(&detail); + + float zoom; + rv = mOwner->GetZoom (&zoom); + NS_ENSURE_SUCCESS (rv, rv); + + zoom = ephy_zoom_get_changed_zoom_level (zoom, detail > 0 ? 1 : detail < 0 ? -1 : 0); + rv = mOwner->SetZoom (zoom); + if (NS_SUCCEEDED (rv)) + { + g_signal_emit_by_name (mOwner->mEmbed, "ge_zoom_change", zoom); + } + + /* we consumed the event */ + aEvent->PreventDefault(); + } + + return NS_OK; +} + +NS_IMPL_ISUPPORTS1(EphyContextMenuListener, nsIDOMContextMenuListener) + +NS_IMETHODIMP +EphyContextMenuListener::ContextMenu (nsIDOMEvent* aDOMEvent) +{ + nsCOMPtr<nsIDOMMouseEvent> mouseEvent = do_QueryInterface(aDOMEvent); + NS_ENSURE_TRUE (mouseEvent, NS_ERROR_FAILURE); + + MozillaEmbedEvent *info; + info = mozilla_embed_event_new (static_cast<gpointer>(aDOMEvent)); + + nsresult rv; + EventContext context; + context.Init (mOwner); + rv = context.GetMouseEventInfo (mouseEvent, MOZILLA_EMBED_EVENT (info)); + + /* Don't do any magic handling if we can't actually show the context + * menu, this can happen for XUL pages (e.g. about:config) + */ + if (NS_FAILED (rv)) + { + g_object_unref (info); + return NS_OK; + } + + if (info->button == 0) + { + /* Translate relative coordinates to absolute values, and try + * to avoid covering links by adding a little offset + */ + int x, y; + gdk_window_get_origin (GTK_WIDGET (mOwner->mEmbed)->window, &x, &y); + info->x += x + 6; + info->y += y + 6; + + // Set the keycode to something sensible + info->keycode = nsIDOMKeyEvent::DOM_VK_CONTEXT_MENU; + } + + if (info->modifier == GDK_CONTROL_MASK) + { + info->context = EPHY_EMBED_CONTEXT_DOCUMENT; + } + + gboolean retval = FALSE; + nsCOMPtr<nsIDOMDocument> domDoc; + rv = context.GetTargetDocument (getter_AddRefs(domDoc)); + if (NS_SUCCEEDED(rv)) + { + mOwner->PushTargetDocument (domDoc); + + g_signal_emit_by_name (mOwner->mEmbed, "ge_context_menu", + info, &retval); + + mOwner->PopTargetDocument (); + } + + /* We handled the event, block javascript calls */ + if (retval) + { + aDOMEvent->PreventDefault(); + aDOMEvent->StopPropagation(); + } + + g_object_unref (info); + + return NS_OK; +} + +NS_IMETHODIMP +EphyContextMenuListener::HandleEvent (nsIDOMEvent* aDOMEvent) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +EphyBrowser::EphyBrowser () +: mDOMLinkEventListener(nsnull) +, mMiscDOMEventsListener(nsnull) +, mDOMScrollEventListener(nsnull) +, mPopupBlockEventListener(nsnull) +, mModalAlertListener(nsnull) +, mContextMenuListener(nsnull) +, mInitialized(PR_FALSE) +{ + LOG ("EphyBrowser ctor (%p)", this); +} + +EphyBrowser::~EphyBrowser () +{ + LOG ("EphyBrowser dtor (%p)", this); +} + +nsresult EphyBrowser::Init (GeckoEmbed *mozembed) +{ + if (mInitialized) return NS_OK; + + mEmbed = GTK_WIDGET (mozembed); + + gecko_embed_get_nsIWebBrowser (mozembed, + getter_AddRefs(mWebBrowser)); + NS_ENSURE_TRUE (mWebBrowser, NS_ERROR_FAILURE); + + mWebBrowserFocus = do_QueryInterface (mWebBrowser); + NS_ENSURE_TRUE (mWebBrowserFocus, NS_ERROR_FAILURE); + + mWebBrowser->GetContentDOMWindow (getter_AddRefs (mDOMWindow)); + NS_ENSURE_TRUE (mDOMWindow, NS_ERROR_FAILURE); + + /* This will instantiate an about:blank doc if necessary */ + nsresult rv; + nsCOMPtr<nsIDOMDocument> domDocument; + rv = mDOMWindow->GetDocument (getter_AddRefs (domDocument)); + NS_ENSURE_SUCCESS (rv, NS_ERROR_FAILURE); + + mDOMLinkEventListener = new EphyDOMLinkEventListener(this); + if (!mDOMLinkEventListener) return NS_ERROR_OUT_OF_MEMORY; + + mMiscDOMEventsListener = new EphyMiscDOMEventsListener(this); + if (!mMiscDOMEventsListener) return NS_ERROR_OUT_OF_MEMORY; + + mDOMScrollEventListener = new EphyDOMScrollEventListener(this); + if (!mDOMScrollEventListener) return NS_ERROR_OUT_OF_MEMORY; + + mPopupBlockEventListener = new EphyPopupBlockEventListener(this); + if (!mPopupBlockEventListener) return NS_ERROR_OUT_OF_MEMORY; + + mModalAlertListener = new EphyModalAlertEventListener (this); + if (!mModalAlertListener) return NS_ERROR_OUT_OF_MEMORY; + + mContextMenuListener = new EphyContextMenuListener(this); + if (!mContextMenuListener) return NS_ERROR_OUT_OF_MEMORY; + + rv = GetListener(); + NS_ENSURE_SUCCESS (rv, NS_ERROR_FAILURE); + + rv = AttachListeners(); + NS_ENSURE_SUCCESS (rv, NS_ERROR_FAILURE); + +#ifdef HAVE_MOZILLA_PSM + nsCOMPtr<nsIDocShell> docShell (do_GetInterface (mWebBrowser, &rv)); + NS_ENSURE_SUCCESS (rv, rv); + + rv = docShell->GetSecurityUI (getter_AddRefs (mSecurityInfo)); + if (!mSecurityInfo) + { + g_warning ("Failed to get nsISecureBrowserUI!\n"); + } + NS_ENSURE_SUCCESS (rv, rv); +#endif /* HAVE_MOZILLA_PSM */ + + mInitialized = PR_TRUE; + + return NS_OK; +} + +nsresult +EphyBrowser::GetListener (void) +{ + if (mEventTarget) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIDOMWindow> domWindowExternal; + mWebBrowser->GetContentDOMWindow (getter_AddRefs(domWindowExternal)); + + nsCOMPtr<nsIDOMWindow2> domWindow (do_QueryInterface (domWindowExternal)); + NS_ENSURE_TRUE (domWindow, NS_ERROR_FAILURE); + + domWindow->GetWindowRoot (getter_AddRefs(mEventTarget)); + NS_ENSURE_TRUE (mEventTarget, NS_ERROR_FAILURE); + + return NS_OK; +} + +nsresult +EphyBrowser::AttachListeners(void) +{ + NS_ENSURE_TRUE (mEventTarget, NS_ERROR_FAILURE); + + nsresult rv; + nsCOMPtr<nsIDOMNSEventTarget> target (do_QueryInterface (mEventTarget, &rv)); + NS_ENSURE_SUCCESS (rv, rv); + + rv = target->AddEventListener(NS_LITERAL_STRING ("DOMLinkAdded"), + mDOMLinkEventListener, PR_FALSE, PR_FALSE); + rv |= target->AddEventListener(NS_LITERAL_STRING ("DOMContentLoaded"), + mMiscDOMEventsListener, PR_FALSE, PR_FALSE); + rv |= target->AddEventListener(NS_LITERAL_STRING ("DOMWindowClose"), + mMiscDOMEventsListener, PR_FALSE, PR_FALSE); + rv |= target->AddEventListener(NS_LITERAL_STRING ("DOMMouseScroll"), + mDOMScrollEventListener, PR_TRUE /* capture */, PR_FALSE); + rv |= target->AddEventListener(NS_LITERAL_STRING ("DOMPopupBlocked"), + mPopupBlockEventListener, PR_FALSE, PR_FALSE); + rv |= target->AddEventListener(NS_LITERAL_STRING ("DOMWillOpenModalDialog"), + mModalAlertListener, PR_TRUE, PR_FALSE); + rv |= target->AddEventListener(NS_LITERAL_STRING ("DOMModalDialogClosed"), + mModalAlertListener, PR_TRUE, PR_FALSE); + rv |= target->AddEventListener(NS_LITERAL_STRING ("contextmenu"), + mContextMenuListener, PR_TRUE /* capture */, PR_FALSE); + NS_ENSURE_SUCCESS (rv, rv); + + return NS_OK; +} + +nsresult +EphyBrowser::DetachListeners(void) +{ + if (!mEventTarget) return NS_OK; + + nsresult rv; + rv = mEventTarget->RemoveEventListener(NS_LITERAL_STRING ("DOMLinkAdded"), + mDOMLinkEventListener, PR_FALSE); + rv |= mEventTarget->RemoveEventListener(NS_LITERAL_STRING ("DOMContentLoaded"), + mMiscDOMEventsListener, PR_FALSE); + rv |= mEventTarget->RemoveEventListener(NS_LITERAL_STRING ("DOMWindowClose"), + mMiscDOMEventsListener, PR_FALSE); + rv |= mEventTarget->RemoveEventListener(NS_LITERAL_STRING ("DOMMouseScroll"), + mDOMScrollEventListener, PR_TRUE); /* capture */ + rv |= mEventTarget->RemoveEventListener(NS_LITERAL_STRING ("DOMPopupBlocked"), + mPopupBlockEventListener, PR_FALSE); + rv |= mEventTarget->RemoveEventListener(NS_LITERAL_STRING ("DOMWillOpenModalDialog"), + mModalAlertListener, PR_TRUE); + rv |= mEventTarget->RemoveEventListener(NS_LITERAL_STRING ("DOMModalDialogClosed"), + mModalAlertListener, PR_TRUE); + rv |= mEventTarget->RemoveEventListener(NS_LITERAL_STRING ("contextmenu"), + mContextMenuListener, PR_TRUE /* capture */); + NS_ENSURE_SUCCESS (rv, NS_ERROR_FAILURE); + + return NS_OK; +} + +nsresult EphyBrowser::Print () +{ + NS_ENSURE_TRUE (mWebBrowser, NS_ERROR_FAILURE); + + nsCOMPtr<nsIWebBrowserPrint> print(do_GetInterface(mWebBrowser)); + NS_ENSURE_TRUE (print, NS_ERROR_FAILURE); + + nsCOMPtr<nsIPrintSettingsService> printSettingsService + (do_GetService("@mozilla.org/gfx/printsettings-service;1")); + NS_ENSURE_STATE (printSettingsService); + + nsCOMPtr<nsIPrintSettings> settings; + printSettingsService->GetNewPrintSettings (getter_AddRefs (settings)); + NS_ENSURE_STATE (settings); + + nsresult rv; + AutoJSContextStack stack; + rv = stack.Init (); + NS_ENSURE_SUCCESS (rv, rv); + + return print->Print (settings, nsnull); +} + +nsresult EphyBrowser::SetPrintPreviewMode (PRBool previewMode) +{ + nsresult rv; + + NS_ENSURE_TRUE (mWebBrowser, NS_ERROR_FAILURE); + + nsCOMPtr<nsIWebBrowserPrint> print (do_GetInterface (mWebBrowser)); + NS_ENSURE_STATE (print); + + if (previewMode) + { + nsCOMPtr<nsIPrintSettingsService> printSettingsService + (do_GetService("@mozilla.org/gfx/printsettings-service;1")); + NS_ENSURE_STATE (printSettingsService); + + nsCOMPtr<nsIPrintSettings> settings; + printSettingsService->GetNewPrintSettings (getter_AddRefs (settings)); + NS_ENSURE_STATE (settings); + + EphyEmbedShell *shell = ephy_embed_shell_get_default (); + rv = GeckoPrintService::TranslateSettings (ephy_embed_shell_get_print_settings (shell), + ephy_embed_shell_get_page_setup (shell), + NULL, + nsCString(), + nsIPrintSettings::kFramesAsIs, + PR_FALSE, + settings); + + if (NS_SUCCEEDED (rv)) + { + rv = print->PrintPreview (settings, mDOMWindow, nsnull); + } + } + else + { + PRBool isPreview = PR_FALSE; + + rv = print->GetDoingPrintPreview(&isPreview); + NS_ENSURE_SUCCESS (rv, NS_ERROR_FAILURE); + + if (isPreview) + { + rv = print->ExitPrintPreview(); + } + } + + return rv; +} + +nsresult EphyBrowser::PrintPreviewNumPages (int *numPages) +{ + NS_ENSURE_TRUE (mWebBrowser, NS_ERROR_FAILURE); + + nsCOMPtr<nsIWebBrowserPrint> print(do_GetInterface(mWebBrowser)); + NS_ENSURE_TRUE (print, NS_ERROR_FAILURE); + + return print->GetPrintPreviewNumPages(numPages); +} + +nsresult EphyBrowser::PrintPreviewNavigate(PRInt16 navType, PRInt32 pageNum) +{ + NS_ENSURE_TRUE (mWebBrowser, NS_ERROR_FAILURE); + + nsCOMPtr<nsIWebBrowserPrint> print(do_GetInterface(mWebBrowser)); + NS_ENSURE_TRUE (print, NS_ERROR_FAILURE); + + return print->PrintPreviewNavigate(navType, pageNum); +} + +nsresult EphyBrowser::GetSHistory (nsISHistory **aSHistory) +{ + NS_ENSURE_TRUE (mWebBrowser, NS_ERROR_FAILURE); + + nsCOMPtr<nsIWebNavigation> ContentNav = do_QueryInterface (mWebBrowser); + NS_ENSURE_TRUE (ContentNav, NS_ERROR_FAILURE); + + nsCOMPtr<nsISHistory> SessionHistory; + ContentNav->GetSessionHistory (getter_AddRefs (SessionHistory)); + NS_ENSURE_TRUE (SessionHistory, NS_ERROR_FAILURE); + + *aSHistory = SessionHistory.get(); + NS_IF_ADDREF (*aSHistory); + + return NS_OK; +} + +nsresult EphyBrowser::CopySHistory (EphyBrowser *dest, PRBool copy_back, + PRBool copy_forward, PRBool copy_current) +{ + nsresult rv; + + nsCOMPtr<nsISHistory> h_src; + GetSHistory (getter_AddRefs(h_src)); + NS_ENSURE_TRUE (h_src, NS_ERROR_FAILURE); + + PRInt32 count, index; + h_src->GetCount (&count); + h_src->GetIndex (&index); + + nsCOMPtr<nsISHistory> h_dest; + dest->GetSHistory (getter_AddRefs (h_dest)); + NS_ENSURE_TRUE (h_dest, NS_ERROR_FAILURE); + + nsCOMPtr<nsISHistoryInternal> hi_dest = do_QueryInterface (h_dest); + NS_ENSURE_TRUE (hi_dest, NS_ERROR_FAILURE); + + if (count) + { + nsCOMPtr<nsIHistoryEntry> he; + nsCOMPtr<nsISHEntry> she, dhe; + + for (PRInt32 i = (copy_back ? 0 : index + 1); + i < (copy_forward ? count : index + 1); + i++) + { + rv = h_src->GetEntryAtIndex (i, PR_FALSE, + getter_AddRefs (he)); + NS_ENSURE_SUCCESS (rv, rv); + + she = do_QueryInterface (he); + NS_ENSURE_TRUE (she, NS_ERROR_FAILURE); + + rv = she->Clone(getter_AddRefs (dhe)); + NS_ENSURE_SUCCESS (rv, rv); + + rv = hi_dest->AddEntry (dhe, PR_TRUE); + NS_ENSURE_SUCCESS (rv, rv); + } + + if (copy_current) + { + nsCOMPtr<nsIWebNavigation> wn_dest = do_QueryInterface (dest->mWebBrowser); + NS_ENSURE_TRUE (wn_dest, NS_ERROR_FAILURE); + + rv = wn_dest->GotoIndex(index); + if (!NS_SUCCEEDED(rv)) return NS_ERROR_FAILURE; + } + } + + return NS_OK; +} + +nsresult EphyBrowser::Destroy () +{ + DetachListeners (); + + mWebBrowser = nsnull; + mDOMWindow = nsnull; + mEventTarget = nsnull; + mEmbed = nsnull; + + mInitialized = PR_FALSE; + + return NS_OK; +} + +nsresult EphyBrowser::GoToHistoryIndex (PRInt16 index) +{ + NS_ENSURE_TRUE (mWebBrowser, NS_ERROR_FAILURE); + + nsCOMPtr<nsIWebNavigation> ContentNav = do_QueryInterface (mWebBrowser); + NS_ENSURE_TRUE (ContentNav, NS_ERROR_FAILURE); + + return ContentNav->GotoIndex (index); +} + +nsresult EphyBrowser::SetZoom (float aZoom) +{ + NS_ENSURE_TRUE (mWebBrowser, NS_ERROR_FAILURE); + + nsCOMPtr<nsIContentViewer> contentViewer; + GetContentViewer (getter_AddRefs(contentViewer)); + NS_ENSURE_TRUE (contentViewer, NS_ERROR_FAILURE); + + nsCOMPtr<nsIMarkupDocumentViewer> mdv = do_QueryInterface(contentViewer); + NS_ENSURE_TRUE (mdv, NS_ERROR_FAILURE); + + return mdv->SetTextZoom (aZoom); +} + +nsresult EphyBrowser::GetContentViewer (nsIContentViewer **aViewer) +{ + NS_ENSURE_TRUE (mWebBrowser, NS_ERROR_FAILURE); + + nsCOMPtr<nsIDocShell> ourDocShell(do_GetInterface(mWebBrowser)); + NS_ENSURE_TRUE (ourDocShell, NS_ERROR_FAILURE); + + return ourDocShell->GetContentViewer(aViewer); +} + +nsresult EphyBrowser::GetZoom (float *aZoom) +{ + NS_ENSURE_TRUE (mWebBrowser, NS_ERROR_FAILURE); + + nsCOMPtr<nsIContentViewer> contentViewer; + GetContentViewer (getter_AddRefs(contentViewer)); + NS_ENSURE_TRUE (contentViewer, NS_ERROR_FAILURE); + + nsCOMPtr<nsIMarkupDocumentViewer> mdv = do_QueryInterface(contentViewer); + NS_ENSURE_TRUE (mdv, NS_ERROR_FAILURE); + + return mdv->GetTextZoom (aZoom); +} + +nsresult +EphyBrowser::ScrollLines (PRInt32 aNumLines) +{ + nsCOMPtr<nsIDOMWindow> DOMWindow; + + mWebBrowserFocus->GetFocusedWindow (getter_AddRefs(DOMWindow)); + if (!DOMWindow) + { + DOMWindow = mDOMWindow; + } + NS_ENSURE_TRUE (DOMWindow, NS_ERROR_FAILURE); + + return DOMWindow->ScrollByLines (aNumLines); +} + +nsresult +EphyBrowser::ScrollPages (PRInt32 aNumPages) +{ + nsCOMPtr<nsIDOMWindow> DOMWindow; + + mWebBrowserFocus->GetFocusedWindow (getter_AddRefs(DOMWindow)); + if (!DOMWindow) + { + DOMWindow = mDOMWindow; + } + NS_ENSURE_TRUE (DOMWindow, NS_ERROR_FAILURE); + + return DOMWindow->ScrollByPages (aNumPages); +} + +nsresult +EphyBrowser::ScrollPixels (PRInt32 aDeltaX, + PRInt32 aDeltaY) +{ + nsCOMPtr<nsIDOMWindow> DOMWindow; + + mWebBrowserFocus->GetFocusedWindow (getter_AddRefs(DOMWindow)); + if (!DOMWindow) + { + DOMWindow = mDOMWindow; + } + NS_ENSURE_TRUE (DOMWindow, NS_ERROR_FAILURE); + + return DOMWindow->ScrollBy (aDeltaX, aDeltaY); +} + +nsresult +EphyBrowser::GetDocument (nsIDOMDocument **aDOMDocument) +{ + return mDOMWindow->GetDocument (aDOMDocument); +} + +nsresult +EphyBrowser::GetTargetDocument (nsIDOMDocument **aDOMDocument) +{ + NS_ENSURE_TRUE (mWebBrowser, NS_ERROR_FAILURE); + + /* Use the current target document */ + if (mTargetDocument) + { + *aDOMDocument = mTargetDocument.get(); + + NS_IF_ADDREF(*aDOMDocument); + + return NS_OK; + } + + /* Use the focused document */ + nsresult rv; + nsCOMPtr<nsIDOMWindow> DOMWindow; + rv = mWebBrowserFocus->GetFocusedWindow (getter_AddRefs(DOMWindow)); + if (NS_SUCCEEDED (rv) && DOMWindow) + { + return DOMWindow->GetDocument (aDOMDocument); + } + + /* Use the main document */ + return mDOMWindow->GetDocument (aDOMDocument); +} + +nsresult EphyBrowser::GetSHInfo (PRInt32 *count, PRInt32 *index) +{ + NS_ENSURE_TRUE (mWebBrowser, NS_ERROR_FAILURE); + + nsCOMPtr<nsISHistory> SessionHistory; + GetSHistory (getter_AddRefs(SessionHistory)); + NS_ENSURE_TRUE (SessionHistory, NS_ERROR_FAILURE); + + SessionHistory->GetCount (count); + SessionHistory->GetIndex (index); + + return NS_OK; +} + +nsresult EphyBrowser::GetSHTitleAtIndex (PRInt32 index, PRUnichar **title) +{ + NS_ENSURE_TRUE (mWebBrowser, NS_ERROR_FAILURE); + + nsCOMPtr<nsISHistory> SessionHistory; + GetSHistory (getter_AddRefs(SessionHistory)); + NS_ENSURE_TRUE (SessionHistory, NS_ERROR_FAILURE); + + nsCOMPtr<nsIHistoryEntry> he; + SessionHistory->GetEntryAtIndex (index, PR_FALSE, + getter_AddRefs (he)); + NS_ENSURE_TRUE (he, NS_ERROR_FAILURE); + + nsresult rv; + rv = he->GetTitle (title); + NS_ENSURE_TRUE (NS_SUCCEEDED (rv) && title, NS_ERROR_FAILURE); + + return NS_OK; +} + +nsresult EphyBrowser::GetSHUrlAtIndex (PRInt32 index, nsACString &url) +{ + NS_ENSURE_TRUE (mWebBrowser, NS_ERROR_FAILURE); + + nsCOMPtr<nsISHistory> SessionHistory; + GetSHistory (getter_AddRefs(SessionHistory)); + NS_ENSURE_TRUE (SessionHistory, NS_ERROR_FAILURE); + + nsCOMPtr<nsIHistoryEntry> he; + SessionHistory->GetEntryAtIndex (index, PR_FALSE, + getter_AddRefs (he)); + NS_ENSURE_TRUE (he, NS_ERROR_FAILURE); + + nsCOMPtr<nsIURI> uri; + he->GetURI (getter_AddRefs(uri)); + NS_ENSURE_TRUE (uri, NS_ERROR_FAILURE); + + nsresult rv; + rv = uri->GetSpec(url); + NS_ENSURE_TRUE (NS_SUCCEEDED (rv) && url.Length(), NS_ERROR_FAILURE); + + return NS_OK; +} + +nsresult EphyBrowser::GetPageDescriptor(nsISupports **aPageDescriptor) +{ + NS_ENSURE_TRUE (mWebBrowser, NS_ERROR_FAILURE); + + nsCOMPtr<nsIDocShell> ds = do_GetInterface (mWebBrowser); + + nsCOMPtr<nsIWebPageDescriptor> wpd = do_QueryInterface (ds); + NS_ENSURE_TRUE (wpd, NS_ERROR_FAILURE); + + *aPageDescriptor = wpd.get(); + NS_IF_ADDREF (*aPageDescriptor); + + return NS_OK; +} + +nsresult EphyBrowser::GetDOMWindow (nsIDOMWindow **aDOMWindow) +{ + NS_ENSURE_TRUE (mWebBrowser, NS_ERROR_FAILURE); + + NS_IF_ADDREF (*aDOMWindow = mDOMWindow); + + return NS_OK; +} + +nsresult EphyBrowser::GetDocumentURI (nsIURI **aURI) +{ + if (!mDOMWindow) return NS_ERROR_NOT_INITIALIZED; + + nsresult rv; + nsCOMPtr<nsIWebNavigation> webNav (do_GetInterface (mDOMWindow, &rv)); + NS_ENSURE_SUCCESS (rv, rv); + + return webNav->GetCurrentURI (aURI); +} + +nsresult EphyBrowser::GetTargetDocumentURI (nsIURI **aURI) +{ + if (!mWebBrowser) return NS_ERROR_NOT_INITIALIZED; + + nsCOMPtr<nsIDOMDocument> domDoc; + GetTargetDocument (getter_AddRefs(domDoc)); + NS_ENSURE_TRUE (domDoc, NS_ERROR_FAILURE); + + nsCOMPtr<nsIDOMDocumentView> docView (do_QueryInterface (domDoc)); + NS_ENSURE_TRUE (docView, NS_ERROR_FAILURE); + + nsCOMPtr<nsIDOMAbstractView> abstractView; + docView->GetDefaultView (getter_AddRefs (abstractView)); + NS_ENSURE_TRUE (abstractView, NS_ERROR_FAILURE); + /* the abstract view is really the DOM window */ + + nsresult rv; + nsCOMPtr<nsIWebNavigation> webNav (do_GetInterface (abstractView, &rv)); + NS_ENSURE_SUCCESS (rv, rv); + + return webNav->GetCurrentURI (aURI); +} + +nsresult EphyBrowser::ForceEncoding (const char *encoding) +{ + NS_ENSURE_TRUE (mWebBrowser, NS_ERROR_FAILURE); + + nsCOMPtr<nsIContentViewer> contentViewer; + GetContentViewer (getter_AddRefs(contentViewer)); + NS_ENSURE_TRUE (contentViewer, NS_ERROR_FAILURE); + + nsCOMPtr<nsIMarkupDocumentViewer> mdv = do_QueryInterface(contentViewer); + NS_ENSURE_TRUE (mdv, NS_ERROR_FAILURE); + + return mdv->SetForceCharacterSet (nsCString(encoding)); +} + +nsresult EphyBrowser::GetEncoding (nsACString &encoding) +{ + NS_ENSURE_TRUE (mWebBrowser, NS_ERROR_FAILURE); + + nsCOMPtr<nsIDocCharset> docCharset = do_GetInterface (mWebBrowser); + NS_ENSURE_TRUE (docCharset, NS_ERROR_FAILURE); + + char *charset; + docCharset->GetCharset (&charset); + encoding = charset; + nsMemory::Free (charset); + + return NS_OK; +} + +nsresult EphyBrowser::GetForcedEncoding (nsACString &encoding) +{ + NS_ENSURE_TRUE (mWebBrowser, NS_ERROR_FAILURE); + + nsCOMPtr<nsIContentViewer> contentViewer; + GetContentViewer (getter_AddRefs(contentViewer)); + NS_ENSURE_TRUE (contentViewer, NS_ERROR_FAILURE); + + nsCOMPtr<nsIMarkupDocumentViewer> mdv = do_QueryInterface(contentViewer); + NS_ENSURE_TRUE (mdv, NS_ERROR_FAILURE); + + nsresult rv; + rv = mdv->GetForceCharacterSet (encoding); + NS_ENSURE_SUCCESS (rv, NS_ERROR_FAILURE); + + return NS_OK; +} + +nsresult EphyBrowser::PushTargetDocument (nsIDOMDocument *domDoc) +{ + mTargetDocument = domDoc; + + return NS_OK; +} + +nsresult EphyBrowser::PopTargetDocument () +{ + mTargetDocument = nsnull; + + return NS_OK; +} + +nsresult EphyBrowser::DoCommand (const char *command) +{ + NS_ENSURE_TRUE (mWebBrowser, NS_ERROR_FAILURE); + + nsCOMPtr<nsICommandManager> cmdManager; + cmdManager = do_GetInterface (mWebBrowser); + NS_ENSURE_TRUE (cmdManager, NS_ERROR_FAILURE); + + return cmdManager->DoCommand (command, nsnull, nsnull); +} + +nsresult EphyBrowser::GetCommandState (const char *command, PRBool *enabled) +{ + NS_ENSURE_TRUE (mWebBrowser, NS_ERROR_FAILURE); + + nsCOMPtr<nsICommandManager> cmdManager; + cmdManager = do_GetInterface (mWebBrowser); + NS_ENSURE_TRUE (cmdManager, NS_ERROR_FAILURE); + + return cmdManager->IsCommandEnabled (command, nsnull, enabled); +} + +#define NUM_MODIFIED_TEXTFIELDS_REQUIRED 2 + +PRBool +EphyBrowser::CompareFormsText (nsAString &aDefaultText, nsAString &aUserText) +{ + if (aDefaultText.Length() != aUserText.Length()) + { + return FALSE; + } + + /* Mozilla Bug 218277, 195946 and others */ + const PRUnichar *text = aDefaultText.BeginReading(); + for (PRUint32 i = 0; i < aDefaultText.Length(); i++) + { + if (text[i] == 0xa0) + { + aDefaultText.Replace (i, 1, ' '); + } + } + + return (memcmp (aDefaultText.BeginReading(), + aUserText.BeginReading(), + aUserText.Length() * sizeof (PRUnichar)) == 0); +} + +nsresult EphyBrowser::GetDocumentHasModifiedForms (nsIDOMDocument *aDomDoc, PRUint32 *aNumTextFields, PRBool *aHasTextArea) +{ + nsCOMPtr<nsIDOMHTMLDocument> htmlDoc = do_QueryInterface(aDomDoc); + /* it's okay not to be a HTML doc (happens for XUL documents, like about:config) */ + if (!htmlDoc) return NS_OK; + + nsCOMPtr<nsIDOMHTMLCollection> forms; + htmlDoc->GetForms (getter_AddRefs (forms)); + if (!forms) return NS_OK; /* it's ok not to have any forms */ + + nsCOMPtr<nsIDOMDocumentView> docView (do_QueryInterface (aDomDoc)); + nsCOMPtr<nsIDOMViewCSS> defaultCSSView; + if (docView) + { + nsCOMPtr<nsIDOMAbstractView> defaultView; + docView->GetDefaultView (getter_AddRefs (defaultView)); + defaultCSSView = do_QueryInterface (defaultView); + } + + const PRUnichar visibilityLiteral[] = { 'v', 'i', 's', 'i', 'b', 'i', 'l', 'i', 't', 'y', '\0' }; + const PRUnichar visibleLiteral[] = { 'v', 'i', 's', 'i', 'b', 'l', 'e', '\0' }; + nsString visibilityAttr(visibilityLiteral); + nsString visibleAttr(visibleLiteral); + nsString EmptyString; + nsCOMPtr<nsIDOMCSSStyleDeclaration> computedStyle; + nsCOMPtr<nsIDOMCSSValue> cssValue; + nsCOMPtr<nsIDOMCSSPrimitiveValue> primitiveValue; + + PRUint32 formNum; + forms->GetLength (&formNum); + + /* check all forms */ + for (PRUint32 formIndex = 0; formIndex < formNum; formIndex++) + { + nsCOMPtr<nsIDOMNode> formNode; + forms->Item (formIndex, getter_AddRefs (formNode)); + if (!formNode) continue; + + nsCOMPtr<nsIDOMHTMLFormElement> formElement = do_QueryInterface (formNode); + if (!formElement) continue; + + PRBool isVisible = PR_FALSE; + nsresult rv; + computedStyle = nsnull; + + /* Check defaultCSSView for NULL, see bug #327764 */ + if (defaultCSSView && + NS_SUCCEEDED (defaultCSSView->GetComputedStyle (formElement, EmptyString, + getter_AddRefs (computedStyle))) && + computedStyle) + { + rv = computedStyle->GetPropertyCSSValue(visibilityAttr, getter_AddRefs (cssValue)); + if (NS_SUCCEEDED (rv) && cssValue) + { + nsString value; + rv = cssValue->GetCssText (value); + if (NS_SUCCEEDED (rv) && value.Length ()) + { + /* what to do for "collapse" and "inherit" values? */ + isVisible = CompareFormsText (value, visibleAttr); + } + } + } + + if (!isVisible) + { + LOG ("Form node %p is invisible\n", formNode.get()); + continue; + } + + nsCOMPtr<nsIDOMHTMLCollection> formElements; + formElement->GetElements (getter_AddRefs (formElements)); + if (!formElements) continue; + + PRUint32 elementNum; + formElements->GetLength (&elementNum); + + /* check all input elements in the form for user input */ + for (PRUint32 elementIndex = 0; elementIndex < elementNum; elementIndex++) + { + nsCOMPtr<nsIDOMNode> domNode; + formElements->Item (elementIndex, getter_AddRefs (domNode)); + if (!domNode) continue; + + nsCOMPtr<nsIDOMElement> domElement (do_QueryInterface (domNode)); + if (!domElement) continue; + + isVisible = PR_FALSE; + computedStyle = nsnull; + /* Check defaultCSSView for NULL, see bug #327764 */ + if (defaultCSSView && + NS_SUCCEEDED (defaultCSSView->GetComputedStyle (domElement, EmptyString, + getter_AddRefs (computedStyle))) && + computedStyle) + { + rv = computedStyle->GetPropertyCSSValue(visibilityAttr, getter_AddRefs (cssValue)); + if (NS_SUCCEEDED (rv) && cssValue) + { + nsString value; + rv = cssValue->GetCssText (value); + if (NS_SUCCEEDED (rv) && value.Length ()) + { + /* what to do for "collapse" and "inherit" values? */ + isVisible = CompareFormsText (value, visibleAttr); + } + } + } + + if (!isVisible) + { + LOG("Form node %p element %p is invisible\n", formNode.get(), domNode.get()); + continue; + } + + nsCOMPtr<nsIDOMHTMLTextAreaElement> areaElement = do_QueryInterface (domNode); + if (areaElement) + { + PRBool isDisabled = PR_TRUE; + areaElement->GetDisabled (&isDisabled); + if (isDisabled) + { + LOG ("Form node %p element %p [textarea] is disabled\n", formNode.get(), areaElement.get()); + continue; + } + + nsString defaultText, userText; + areaElement->GetDefaultValue (defaultText); + areaElement->GetValue (userText); + + if (!CompareFormsText (defaultText, userText)) + { + *aHasTextArea = PR_TRUE; + return NS_OK; + } + + continue; + } + + nsCOMPtr<nsIDOMHTMLInputElement> inputElement = do_QueryInterface(domNode); + if (!inputElement) continue; + + PRBool isDisabled = PR_TRUE; + inputElement->GetDisabled (&isDisabled); + if (isDisabled) + { + LOG ("Form node %p element %p [input] is disabled\n", formNode.get(), inputElement.get()); + continue; + } + + nsString type; + inputElement->GetType(type); + + nsCString cType; + NS_UTF16ToCString (type, NS_CSTRING_ENCODING_UTF8, cType); + + if (g_ascii_strcasecmp (cType.get(), "text") == 0) + { + nsString defaultText, userText; + PRInt32 max_length; + inputElement->GetDefaultValue (defaultText); + inputElement->GetValue (userText); + inputElement->GetMaxLength (&max_length); + + /* There are forms for which defaultValue is longer than + * userValue. Mozilla consider this not a bug [see WONTFIXed + * bug 232057], but we need to check for this here. + */ + if (defaultText.Length() > (PRUint32)max_length) + { + defaultText.Cut (max_length, PR_UINT32_MAX); + } + + if (!CompareFormsText (defaultText, userText)) + { + (*aNumTextFields)++; + if (*aNumTextFields >= NUM_MODIFIED_TEXTFIELDS_REQUIRED) + { + return NS_OK; + } + } + } + } + } + + return NS_OK; +} + +nsresult EphyBrowser::GetHasModifiedForms (PRBool *modified) +{ + *modified = PR_FALSE; + + NS_ENSURE_TRUE (mWebBrowser, NS_ERROR_FAILURE); + + nsCOMPtr<nsIDocShell> rootDocShell = do_GetInterface (mWebBrowser); + NS_ENSURE_TRUE (rootDocShell, NS_ERROR_FAILURE); + + nsCOMPtr<nsISimpleEnumerator> enumerator; + rootDocShell->GetDocShellEnumerator(nsIDocShellTreeItem::typeContent, + nsIDocShell::ENUMERATE_FORWARDS, + getter_AddRefs(enumerator)); + NS_ENSURE_TRUE (enumerator, NS_ERROR_FAILURE); + + PRBool hasMore; + PRBool hasTextArea = PR_FALSE; + PRUint32 numTextFields = 0; + while (NS_SUCCEEDED(enumerator->HasMoreElements(&hasMore)) && hasMore) + { + nsCOMPtr<nsISupports> element; + enumerator->GetNext (getter_AddRefs(element)); + if (!element) continue; + + nsCOMPtr<nsIDocShell> docShell = do_QueryInterface (element); + if (!docShell) continue; + + nsCOMPtr<nsIContentViewer> contentViewer; + docShell->GetContentViewer (getter_AddRefs(contentViewer)); + if (!contentViewer) continue; + + nsCOMPtr<nsIDOMDocument> domDoc; + contentViewer->GetDOMDocument (getter_AddRefs (domDoc)); + + nsresult rv; + rv = GetDocumentHasModifiedForms (domDoc, &numTextFields, &hasTextArea); + if (NS_SUCCEEDED (rv) && + (numTextFields >= NUM_MODIFIED_TEXTFIELDS_REQUIRED || hasTextArea)) + { + *modified = PR_TRUE; + break; + } + } + + return NS_OK; +} + +nsresult +EphyBrowser::GetSecurityInfo (PRUint32 *aState, nsACString &aDescription) +{ +#ifdef HAVE_MOZILLA_PSM + NS_ENSURE_TRUE (mSecurityInfo, NS_ERROR_FAILURE); + + nsresult rv; + rv = mSecurityInfo->GetState (aState); + NS_ENSURE_SUCCESS (rv, NS_ERROR_FAILURE); + + nsString tooltip; + rv = mSecurityInfo->GetTooltipText (tooltip); + NS_ENSURE_SUCCESS (rv, NS_ERROR_FAILURE); + + NS_UTF16ToCString (tooltip, + NS_CSTRING_ENCODING_UTF8, aDescription); + + return NS_OK; +#else + return NS_ERROR_NOT_IMPLEMENTED; +#endif +} + +nsresult +EphyBrowser::ShowCertificate () +{ +#ifdef HAVE_MOZILLA_PSM + NS_ENSURE_TRUE (mSecurityInfo, NS_ERROR_FAILURE); + + nsCOMPtr<nsISSLStatusProvider> statusProvider (do_QueryInterface (mSecurityInfo)); + NS_ENSURE_TRUE (statusProvider, NS_ERROR_FAILURE); + + nsCOMPtr<nsISSLStatus> SSLStatus; + statusProvider->GetSSLStatus (getter_AddRefs (SSLStatus)); + NS_ENSURE_TRUE (SSLStatus, NS_ERROR_FAILURE); + + nsCOMPtr<nsIX509Cert> serverCert; + SSLStatus->GetServerCert (getter_AddRefs (serverCert)); + NS_ENSURE_TRUE (serverCert, NS_ERROR_FAILURE); + + nsCOMPtr<nsICertificateDialogs> certDialogs (do_GetService (NS_CERTIFICATEDIALOGS_CONTRACTID)); + NS_ENSURE_TRUE (certDialogs, NS_ERROR_FAILURE); + + nsCOMPtr<nsIInterfaceRequestor> requestor(do_QueryInterface (mDOMWindow)); + + return certDialogs->ViewCert (requestor, serverCert); +#else + return NS_OK; +#endif +} + +EphyEmbedDocumentType +EphyBrowser::GetDocumentType () +{ + EphyEmbedDocumentType type = EPHY_EMBED_DOCUMENT_OTHER; + + NS_ENSURE_TRUE (mDOMWindow, type); + + nsresult rv; + nsCOMPtr<nsIDOMDocument> domDoc; + rv = GetDocument (getter_AddRefs (domDoc)); + NS_ENSURE_SUCCESS (rv, type); + + nsCOMPtr<nsIDOMHTMLDocument> htmlDoc (do_QueryInterface (domDoc)); + nsCOMPtr<nsIDOMXMLDocument> xmlDoc (do_QueryInterface (domDoc)); + nsCOMPtr<nsIImageDocument> imgDoc (do_QueryInterface (domDoc)); + + if (xmlDoc) + { + type = EPHY_EMBED_DOCUMENT_XML; + } + else if (imgDoc) + { + type = EPHY_EMBED_DOCUMENT_IMAGE; + } + else if (htmlDoc) + { + type = EPHY_EMBED_DOCUMENT_HTML; + } + + return type; +} + +nsresult +EphyBrowser::Close () +{ + nsCOMPtr<nsIDOMWindowInternal> domWin (do_QueryInterface (mDOMWindow)); + NS_ENSURE_TRUE (domWin, NS_ERROR_FAILURE); + + return domWin->Close(); +} + +nsresult +EphyBrowser::GetPIDOMWindow(nsPIDOMWindow **aPIWin) +{ + *aPIWin = nsnull; + + // get the private DOM window + nsCOMPtr<nsPIDOMWindow> domWindowPrivate = do_QueryInterface(mDOMWindow); + + // and the root window for that DOM window + *aPIWin = domWindowPrivate->GetPrivateRoot(); + + if (*aPIWin) + { + NS_ADDREF(*aPIWin); + return NS_OK; + } + + return NS_ERROR_FAILURE; + +} + +nsresult +EphyBrowser::LoadURI(const char *aURI, + PRUint32 aLoadFlags, + nsIURI *aReferrer) +{ + nsString uURI; + nsresult rv = NS_OK; + + NS_CStringToUTF16 (nsCString (aURI), NS_CSTRING_ENCODING_UTF8, uURI); + + if (uURI.Length() == 0) return NS_OK; + + nsCOMPtr<nsIWebNavigation> contentNav = do_QueryInterface (mWebBrowser); + NS_ENSURE_TRUE (contentNav, NS_ERROR_FAILURE); + + nsCOMPtr<nsPIDOMWindow> piWin; + rv = GetPIDOMWindow(getter_AddRefs(piWin)); + NS_ENSURE_SUCCESS (rv, rv); + + nsAutoPopupStatePusher popupStatePusher(piWin, openAllowed); + + rv = contentNav->LoadURI(uURI.get(), // URI string + aLoadFlags, // Load flags + aReferrer, // Referring URI + nsnull, // Post data + nsnull); // extra headers + + return rv; +} + diff --git a/embed/xulrunner/embed/EphyBrowser.h b/embed/xulrunner/embed/EphyBrowser.h new file mode 100644 index 000000000..1f23d2a73 --- /dev/null +++ b/embed/xulrunner/embed/EphyBrowser.h @@ -0,0 +1,223 @@ +/* + * Copyright © 2000-2004 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#ifndef EPHY_BROWSER_H +#define EPHY_BROWSER_H + +#include "ephy-embed.h" +#include <gtk/gtkwidget.h> + +#include <nsCOMPtr.h> +#include <nsIDOMContextMenuListener.h> +#include <nsIDOMDocument.h> +#include <nsIDOMEventListener.h> +#include <nsIDOMEventTarget.h> +#include <nsIDOMWindow.h> +#include <nsIRequest.h> +#include <nsISHistory.h> +#include <nsIWebBrowserFocus.h> +#include <nsIWebBrowser.h> +#include <nsIWebNavigation.h> +#include <nsPIDOMWindow.h> + +#ifdef ALLOW_PRIVATE_API +#include <nsIContentViewer.h> +#endif + +#ifdef HAVE_MOZILLA_PSM +#include <nsISecureBrowserUI.h> +#endif + +#include "gecko-embed.h" + +class EphyBrowser; + +class EphyEventListener : public nsIDOMEventListener +{ +public: + NS_DECL_ISUPPORTS + + // nsIDOMEventListener + NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent) = 0; + + EphyEventListener(EphyBrowser *aOwner) : mOwner(aOwner) { }; + virtual ~EphyEventListener() { }; + +protected: + EphyBrowser *mOwner; +}; + +class EphyDOMLinkEventListener : public EphyEventListener +{ +public: + NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent); + + EphyDOMLinkEventListener(EphyBrowser *aOwner) : EphyEventListener(aOwner) { }; +private: + nsresult GetDocURI (nsIDOMElement *aElement, + nsIURI **aDocURI); + +}; + +class EphyPopupBlockEventListener : public EphyEventListener +{ +public: + NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent); + + EphyPopupBlockEventListener(EphyBrowser *aOwner) : EphyEventListener(aOwner) { }; +}; + +class EphyModalAlertEventListener : public EphyEventListener +{ +public: + NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent); + + EphyModalAlertEventListener(EphyBrowser *aOwner) : EphyEventListener(aOwner) { }; +}; + +class EphyMiscDOMEventsListener : public EphyEventListener +{ +public: + NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent); + + EphyMiscDOMEventsListener(EphyBrowser *aOwner) : EphyEventListener(aOwner) { }; +}; + +class EphyDOMScrollEventListener : public EphyEventListener +{ +public: + NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent); + + EphyDOMScrollEventListener(EphyBrowser *aOwner) : EphyEventListener(aOwner) { }; +}; + +class EphyContextMenuListener : public nsIDOMContextMenuListener +{ +public: + NS_DECL_ISUPPORTS + + // nsIDOMContextMenuListener + NS_IMETHOD ContextMenu(nsIDOMEvent *aEvent); + NS_IMETHOD HandleEvent(nsIDOMEvent *aEvent); + + EphyContextMenuListener(EphyBrowser *aOwner) : mOwner(aOwner) { }; + virtual ~EphyContextMenuListener() { }; + +protected: + EphyBrowser *mOwner; +}; + +class EphyBrowser +{ +friend class EphyEventListener; +friend class EphyDOMLinkEventListener; +friend class EphyMiscDOMEventsListener; +friend class EphyDOMScrollEventListener; +friend class EphyPopupBlockEventListener; +friend class EphyModalAlertEventListener; +friend class EphyContextMenuListener; +public: + EphyBrowser(); + ~EphyBrowser(); + + nsresult Init (GeckoEmbed *mozembed); + nsresult Destroy (void); + + nsresult DoCommand (const char *command); + nsresult GetCommandState (const char *command, PRBool *enabled); + + nsresult SetZoom (float aTextZoom); + nsresult GetZoom (float *aTextZoom); + + nsresult ScrollLines (PRInt32 aNumLines); + nsresult ScrollPages (PRInt32 aNumPages); + nsresult ScrollPixels (PRInt32 aDeltaX, PRInt32 aDeltaY); + + nsresult Print (); + nsresult SetPrintPreviewMode (PRBool previewMode); + nsresult PrintPreviewNumPages (int *numPages); + nsresult PrintPreviewNavigate(PRInt16 navType, PRInt32 pageNum); + + nsresult GetPageDescriptor(nsISupports **aPageDescriptor); + + nsresult GetSHInfo (PRInt32 *count, PRInt32 *index); + nsresult GetSHTitleAtIndex (PRInt32 index, PRUnichar **title); + nsresult GetSHUrlAtIndex (PRInt32 index, nsACString &url); + nsresult GoToHistoryIndex (PRInt16 index); + + nsresult ForceEncoding (const char *encoding); + nsresult GetEncoding (nsACString &encoding); + nsresult GetForcedEncoding (nsACString &encoding); + + nsresult PushTargetDocument (nsIDOMDocument *domDoc); + nsresult PopTargetDocument (); + + nsresult GetDocument (nsIDOMDocument **aDOMDocument); + nsresult GetTargetDocument (nsIDOMDocument **aDOMDocument); + nsresult GetDocumentURI (nsIURI **aURI); + nsresult GetTargetDocumentURI (nsIURI **aURI); + nsresult GetDOMWindow (nsIDOMWindow **window); + nsresult GetPIDOMWindow(nsPIDOMWindow **aPIWin); + + nsresult GetHasModifiedForms (PRBool *modified); + + nsresult GetSecurityInfo (PRUint32 *aState, nsACString &aDescription); + nsresult ShowCertificate (); + + nsresult CopySHistory (EphyBrowser *dest, PRBool copy_back, + PRBool copy_forward, PRBool copy_current); + + nsresult Close (); + + nsresult LoadURI(const char *aURI, + PRUint32 aLoadFlags = nsIWebNavigation::LOAD_FLAGS_NONE, + nsIURI *aURI = nsnull); + + EphyEmbedDocumentType GetDocumentType (); + + nsCOMPtr<nsIWebBrowser> mWebBrowser; +private: + GtkWidget *mEmbed; + + nsCOMPtr<nsIWebBrowserFocus> mWebBrowserFocus; + nsCOMPtr<nsIDOMDocument> mTargetDocument; + nsCOMPtr<nsIDOMEventTarget> mEventTarget; + nsCOMPtr<nsIDOMWindow> mDOMWindow; + EphyDOMLinkEventListener *mDOMLinkEventListener; + EphyMiscDOMEventsListener *mMiscDOMEventsListener; + EphyDOMScrollEventListener *mDOMScrollEventListener; + EphyPopupBlockEventListener *mPopupBlockEventListener; + EphyModalAlertEventListener *mModalAlertListener; + EphyContextMenuListener *mContextMenuListener; + PRBool mInitialized; +#ifdef HAVE_MOZILLA_PSM + nsCOMPtr<nsISecureBrowserUI> mSecurityInfo; +#endif + + nsresult GetListener (void); + nsresult AttachListeners (void); + nsresult DetachListeners (void); + nsresult GetSHistory (nsISHistory **aSHistory); + nsresult GetContentViewer (nsIContentViewer **aViewer); + nsresult GetDocumentHasModifiedForms (nsIDOMDocument *aDomDoc, PRUint32 *aNumTextFields, PRBool *aHasTextArea); + PRBool CompareFormsText (nsAString &aDefaultText, nsAString &aUserText); +}; + +#endif /* !EPHY_BROWSER_H */ diff --git a/embed/xulrunner/embed/EphyContentPolicy.cpp b/embed/xulrunner/embed/EphyContentPolicy.cpp new file mode 100644 index 000000000..fc367c2b1 --- /dev/null +++ b/embed/xulrunner/embed/EphyContentPolicy.cpp @@ -0,0 +1,244 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright © 2003 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#include "mozilla-config.h" +#include "config.h" + +#include <nsStringAPI.h> + +#include <nsCOMPtr.h> +#include <nsICategoryManager.h> +#include <nsIDOMAbstractView.h> +#include <nsIDOMDocument.h> +#include <nsIDOMDocumentView.h> +#include <nsIDOMNode.h> +#include <nsIDOMWindow.h> +#include <nsIURI.h> +#include <nsServiceManagerUtils.h> +#include <nsXPCOMCID.h> + +#include "eel-gconf-extensions.h" +#include "ephy-adblock-manager.h" +#include "ephy-debug.h" +#include "ephy-embed-shell.h" +#include "ephy-embed-single.h" + +#include "EphyUtils.h" + +#include "EphyContentPolicy.h" + +#define CONF_LOCKDOWN_DISABLE_UNSAFE_PROTOCOLS "/apps/epiphany/lockdown/disable_unsafe_protocols" +#define CONF_LOCKDOWN_ADDITIONAL_SAFE_PROTOCOLS "/apps/epiphany/lockdown/additional_safe_protocols" + +NS_IMPL_ISUPPORTS1(EphyContentPolicy, nsIContentPolicy) + +EphyContentPolicy::EphyContentPolicy() +{ + LOG ("EphyContentPolicy ctor (%p)", this); + + mLocked = eel_gconf_get_boolean (CONF_LOCKDOWN_DISABLE_UNSAFE_PROTOCOLS); + + mSafeProtocols = eel_gconf_get_string_list (CONF_LOCKDOWN_ADDITIONAL_SAFE_PROTOCOLS); +} + +EphyContentPolicy::~EphyContentPolicy() +{ + LOG ("EphyContentPolicy dtor (%p)", this); + + g_slist_foreach (mSafeProtocols, (GFunc) g_free, NULL); + g_slist_free (mSafeProtocols); +} + +GtkWidget * +EphyContentPolicy::GetEmbedFromContext (nsISupports *aContext) +{ + /* + * aContext is either an nsIDOMWindow, an nsIDOMNode, or NULL. If it's + * an nsIDOMNode, we need the nsIDOMWindow to get the EphyEmbed. + */ + if (aContext == NULL) return NULL; + + nsCOMPtr<nsIDOMWindow> window; + + nsCOMPtr<nsIDOMNode> node (do_QueryInterface (aContext)); + if (node != NULL) + { + nsCOMPtr<nsIDOMDocument> domDocument; + + node->GetOwnerDocument (getter_AddRefs (domDocument)); + if (domDocument == NULL) return NULL; /* resource://... */ + + nsCOMPtr<nsIDOMDocumentView> docView = + do_QueryInterface (domDocument); + NS_ENSURE_TRUE (docView, NULL); + + nsCOMPtr<nsIDOMAbstractView> view; + + docView->GetDefaultView (getter_AddRefs (view)); + + window = do_QueryInterface (view); + } + else + { + window = do_QueryInterface (aContext); + } + NS_ENSURE_TRUE (window, NULL); + + GtkWidget *embed = EphyUtils::FindEmbed (window); + if (!EPHY_IS_EMBED (embed)) return NULL; + + return embed; +} + +NS_IMETHODIMP +EphyContentPolicy::ShouldLoad(PRUint32 aContentType, + nsIURI *aContentLocation, + nsIURI *aRequestingLocation, + nsISupports *aContext, + const nsACString &aMimeTypeGuess, + nsISupports *aExtra, + PRInt16 *aDecision) +{ + NS_ENSURE_ARG (aContentLocation); + NS_ENSURE_ARG_POINTER (aDecision); + + *aDecision = nsIContentPolicy::ACCEPT; + + /* We have to always allow these, else forms and scrollbars break */ + PRBool isChrome = PR_FALSE, isResource = PR_FALSE; + aContentLocation->SchemeIs ("chrome", &isChrome); + aContentLocation->SchemeIs ("resource", &isResource); + if (isChrome || isResource) return NS_OK; + + PRBool isHttps = PR_FALSE; + aContentLocation->SchemeIs ("https", &isHttps); + if (isHttps) return NS_OK; + + /* is this url allowed ? */ + nsCString contentSpec; + aContentLocation->GetSpec (contentSpec); + + EphyAdBlockManager *adblock_manager = + EPHY_ADBLOCK_MANAGER (ephy_embed_shell_get_adblock_manager (embed_shell)); + + static PRBool kBlockType[nsIContentPolicy::TYPE_REFRESH + 1] = { + PR_FALSE /* unused/unknown, don't block */, + PR_TRUE /* TYPE_OTHER */, + PR_TRUE /* TYPE_SCRIPT */, + PR_TRUE /* TYPE_IMAGE */, + PR_FALSE /* TYPE_STYLESHEET */, + PR_TRUE /* TYPE_OBJECT */, + PR_FALSE /* TYPE_DOCUMENT */, + PR_TRUE /* TYPE_SUBDOCUMENT */, + PR_TRUE /* TYPE_REFRESH */ + }; + + if (kBlockType[aContentType < G_N_ELEMENTS (kBlockType) ? aContentType : 0]) + { + GtkWidget *embed = GetEmbedFromContext (aContext); + + if (embed && + !ephy_adblock_manager_should_load (adblock_manager, + EPHY_EMBED (embed), + contentSpec.get (), + AdUriCheckType (aContentType))) + { + *aDecision = nsIContentPolicy::REJECT_REQUEST; + + g_signal_emit_by_name (embed, + "content-blocked", + contentSpec.get ()); + return NS_OK; + } + } + + PRBool isHttp = PR_FALSE; + aContentLocation->SchemeIs ("http", &isHttp); + if (isHttp) return NS_OK; + + if (strcmp (contentSpec.get(), "about:blank") == 0) return NS_OK; + + nsCString contentScheme; + aContentLocation->GetScheme (contentScheme); + + /* first general lockdown check */ + if (mLocked && + !g_slist_find_custom (mSafeProtocols, contentScheme.get(), (GCompareFunc) strcmp)) + { + *aDecision = nsIContentPolicy::REJECT_REQUEST; + } + + return NS_OK; +} + +NS_IMETHODIMP +EphyContentPolicy::ShouldProcess(PRUint32 aContentType, + nsIURI *aContentLocation, + nsIURI *aRequestingLocation, + nsISupports *aContext, + const nsACString &aMimeType, + nsISupports *aExtra, + PRInt16 *aDecision) +{ + *aDecision = nsIContentPolicy::ACCEPT; + return NS_OK; +} + + +/* static */ NS_METHOD +EphyContentPolicy::Register (nsIComponentManager* aComponentManager, + nsIFile* aPath, + const char* aRegistryLocation, + const char* aComponentType, + const nsModuleComponentInfo* aInfo) +{ + nsresult rv; + nsCOMPtr<nsICategoryManager> catMan (do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv)); + NS_ENSURE_SUCCESS (rv, rv); + + rv = catMan->AddCategoryEntry ("content-policy", + EPHY_CONTENT_POLICY_CONTRACTID, + EPHY_CONTENT_POLICY_CONTRACTID, + PR_FALSE /* don't persist */, + PR_TRUE /* replace */, + nsnull); + NS_ENSURE_SUCCESS (rv, rv); + + return rv; +} + +/* static */ NS_METHOD +EphyContentPolicy::Unregister (nsIComponentManager* aComponentManager, + nsIFile* aPath, + const char* aRegistryLocation, + const nsModuleComponentInfo* aInfo) +{ + nsresult rv; + nsCOMPtr<nsICategoryManager> catMan (do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv)); + NS_ENSURE_SUCCESS (rv, rv); + + rv = catMan->DeleteCategoryEntry ("content-policy", + EPHY_CONTENT_POLICY_CONTRACTID, + PR_FALSE /* don't persist */); + NS_ENSURE_SUCCESS (rv, rv); + + return rv; +} diff --git a/embed/xulrunner/embed/EphyContentPolicy.h b/embed/xulrunner/embed/EphyContentPolicy.h new file mode 100644 index 000000000..0bc68ced7 --- /dev/null +++ b/embed/xulrunner/embed/EphyContentPolicy.h @@ -0,0 +1,76 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright © 2003 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#ifndef EPHY_CONTENT_POLICY_H +#define EPHY_CONTENT_POLICY_H + +#include <glib.h> +#include <glib-object.h> +#include <gtk/gtkwidget.h> + +#include <nsIContentPolicy.h> + +#include "ephy-embed.h" + +class nsIComponentManager; +class nsIFile; +struct nsModuleComponentInfo; + +#define EPHY_CONTENT_POLICY_CONTRACTID "@gnome.org/projects/epiphany/epiphany-content-policy;1" +#define EPHY_CONTENT_POLICY_CLASSNAME "Epiphany Content Policy Class" + +#define EPHY_CONTENT_POLICY_CID \ +{ /* 6bb60b15-b7bd-4023-a19e-ab691bc3fb43 */ \ + 0x6bb60b15, \ + 0xb7bd, \ + 0x4023, \ + { 0xa1, 0x9e, 0xab, 0x69, 0x1b, 0xc3, 0xfb, 0x43 } \ +} + +class EphyContentPolicy : public nsIContentPolicy +{ + public: + NS_DECL_ISUPPORTS + NS_DECL_NSICONTENTPOLICY + + EphyContentPolicy(); + + static NS_METHOD Register (nsIComponentManager* aComponentManager, + nsIFile* aPath, + const char* aRegistryLocation, + const char* aComponentType, + const nsModuleComponentInfo* aInfo); + + static NS_METHOD Unregister (nsIComponentManager* aComponentManager, + nsIFile* aPath, + const char* aRegistryLocation, + const nsModuleComponentInfo* aInfo); + + private: + ~EphyContentPolicy(); + + static GtkWidget *GetEmbedFromContext (nsISupports *aContext); + + gboolean mLocked; + GSList *mSafeProtocols; +}; + +#endif diff --git a/embed/xulrunner/embed/EphyDirectoryProvider.cpp b/embed/xulrunner/embed/EphyDirectoryProvider.cpp new file mode 100644 index 000000000..f8ec21042 --- /dev/null +++ b/embed/xulrunner/embed/EphyDirectoryProvider.cpp @@ -0,0 +1,106 @@ +/* + * Copyright © 2006 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#include "mozilla-config.h" +#include "config.h" + +#include <string.h> + +#ifndef HAVE_GECKO_1_9 +// for nsNetUtil.h +#define MOZILLA_INTERNAL_API 1 +#endif + +#include <nsStringAPI.h> + +#include <nsAppDirectoryServiceDefs.h> +#include <nsCOMPtr.h> +#include <nsEnumeratorUtils.h> +#include <nsIDirectoryService.h> +#include <nsIIOService.h> +#include <nsILocalFile.h> +#include <nsISupportsArray.h> +#include <nsIToolkitChromeRegistry.h> +#include <nsNetUtil.h> + +#include "EphyDirectoryProvider.h" + +NS_IMPL_ISUPPORTS2 (EphyDirectoryProvider, + nsIDirectoryServiceProvider, + nsIDirectoryServiceProvider2) + + +/* nsIFile getFile (in string prop, out PRBool persistent); */ +NS_IMETHODIMP +EphyDirectoryProvider::GetFile (const char *prop, + PRBool *persistent, + nsIFile **_retval) +{ + return NS_ERROR_FAILURE; +} + +/* nsISimpleEnumerator getFiles (in string prop); */ +NS_IMETHODIMP +EphyDirectoryProvider::GetFiles (const char *prop, + nsISimpleEnumerator **_retval) +{ + nsresult rv = NS_ERROR_FAILURE; + + if (prop && strcmp (prop, NS_CHROME_MANIFESTS_FILE_LIST) == 0) + { + nsCOMPtr<nsILocalFile> manifestDir; + rv = NS_NewNativeLocalFile (nsDependentCString(SHARE_DIR "/chrome"), PR_TRUE, + getter_AddRefs (manifestDir)); + NS_ENSURE_SUCCESS (rv, rv); + + nsCOMPtr<nsISupports> element (do_QueryInterface (manifestDir, &rv)); + NS_ENSURE_SUCCESS (rv, rv); + + /* FIXME: this sucks! + * When we don't implement a directory service provider, + * the chrome registry takes its manifests files from the + * app chrome dir; but it doesn't append this dir when + * we do provide our own (additional) chrome manifest dirs! + * http://lxr.mozilla.org/seamonkey/source/chrome/src/nsChromeRegistry.cpp#1147 + */ + nsCOMPtr<nsIProperties> dirServ (do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv)); + NS_ENSURE_SUCCESS (rv, rv); + + nsCOMPtr<nsIFile> chromeDir; + rv = dirServ->Get (NS_APP_CHROME_DIR, NS_GET_IID (nsIFile), + getter_AddRefs (chromeDir)); + NS_ENSURE_SUCCESS (rv, rv); + + nsCOMPtr<nsISupportsArray> array; + rv = NS_NewISupportsArray (getter_AddRefs (array)); + NS_ENSURE_SUCCESS (rv, rv); + + rv = array->AppendElement (manifestDir); + rv |= array->AppendElement (chromeDir); + NS_ENSURE_SUCCESS (rv, rv); + + rv = NS_NewArrayEnumerator (_retval, array); + NS_ENSURE_SUCCESS (rv, rv); + + rv = NS_SUCCESS_AGGREGATE_RESULT; + } + + return rv; +} diff --git a/embed/xulrunner/embed/EphyDirectoryProvider.h b/embed/xulrunner/embed/EphyDirectoryProvider.h new file mode 100644 index 000000000..ca66f9d4d --- /dev/null +++ b/embed/xulrunner/embed/EphyDirectoryProvider.h @@ -0,0 +1,37 @@ +/* + * Copyright © 2006 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#ifndef EPHY_DIRECTORY_PROVIDER_H +#define EPHY_DIRECTORY_PROVIDER_H + +#include <nsIDirectoryService.h> + +class EphyDirectoryProvider : public nsIDirectoryServiceProvider2 +{ + public: + NS_DECL_ISUPPORTS + NS_DECL_NSIDIRECTORYSERVICEPROVIDER + NS_DECL_NSIDIRECTORYSERVICEPROVIDER2 + + EphyDirectoryProvider() { } + virtual ~EphyDirectoryProvider() { } +}; + +#endif /* EPHY_DIRECTORY_PROVIDER_H */ diff --git a/embed/xulrunner/embed/EphyFind.cpp b/embed/xulrunner/embed/EphyFind.cpp new file mode 100644 index 000000000..344d4251e --- /dev/null +++ b/embed/xulrunner/embed/EphyFind.cpp @@ -0,0 +1,267 @@ +/* + * Copyright © 2005 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#include "mozilla-config.h" +#include "config.h" + +#include <glib.h> + +#include <nsStringAPI.h> + +#include <nsComponentManagerUtils.h> +#include <nsCOMPtr.h> +#include <nsIDocShell.h> +#include <nsIDOMAbstractView.h> +#include <nsIDOMDocumentEvent.h> +#include <nsIDOMDocument.h> +#include <nsIDOMDocumentView.h> +#include <nsIDOMElement.h> +#include <nsIDOMEvent.h> +#include <nsIDOMEventTarget.h> +#include <nsIDOMHTMLAnchorElement.h> +#include <nsIDOMKeyEvent.h> +#include <nsIDOMNode.h> +#include <nsIDOMWindow.h> +#include <nsIInterfaceRequestorUtils.h> +#include <nsISelectionController.h> +#include <nsISelectionDisplay.h> +#include <nsITypeAheadFind.h> +#include <nsIWebBrowserFocus.h> +#include <nsIWebBrowser.h> +#include <nsServiceManagerUtils.h> + +#ifndef HAVE_GECKO_1_9 +#include <nsIDocShellTreeItem.h> +#include <nsISimpleEnumerator.h> +#endif + +#include "gecko-embed-private.h" + +#include "ephy-debug.h" + +#include "EphyFind.h" + +#define NS_TYPEAHEADFIND_CONTRACTID "@mozilla.org/typeaheadfind;1" + +static const PRUnichar kKeyEvents[] = { 'K', 'e', 'y', 'E', 'v', 'e', 'n', 't', 's', '\0' }; +static const PRUnichar kKeyPress[] = { 'k', 'e', 'y', 'p', 'r', 'e', 's', 's', '\0' }; + +EphyFind::EphyFind () +: mCurrentEmbed(nsnull) +, mAttention(PR_FALSE) +{ + LOG ("EphyFind ctor [%p]", this); +} + +EphyFind::~EphyFind () +{ + LOG ("EphyFind dtor [%p]", this); +} + +nsresult +EphyFind::SetEmbed (EphyEmbed *aEmbed) +{ + nsresult rv = NS_OK; + if (aEmbed == mCurrentEmbed) return rv; + + SetSelectionAttention (PR_FALSE); + + mCurrentEmbed = nsnull; + mWebBrowser = nsnull; + + rv = NS_ERROR_FAILURE; + gecko_embed_get_nsIWebBrowser (GECKO_EMBED (aEmbed), + getter_AddRefs (mWebBrowser)); + NS_ENSURE_TRUE (mWebBrowser, rv); + + nsCOMPtr<nsIDocShell> docShell (do_GetInterface (mWebBrowser, &rv)); + NS_ENSURE_SUCCESS (rv, rv); + + if (!mFinder) { + mFinder = do_CreateInstance (NS_TYPEAHEADFIND_CONTRACTID, &rv); + NS_ENSURE_SUCCESS (rv, rv); + + rv = mFinder->Init (docShell); +#ifdef HAVE_GECKO_1_9 +// mFinder->SetSelectionModeAndRepaint (nsISelectionController::SELECTION_ON); +#else + mFinder->SetFocusLinks (PR_TRUE); +#endif + } else { + rv = mFinder->SetDocShell (docShell); + } + NS_ENSURE_SUCCESS (rv, rv); + + mCurrentEmbed = aEmbed; + + return rv; +} + +void +EphyFind::SetFindProperties (const char *aSearchString, + PRBool aCaseSensitive) +{ + if (!mFinder) return; + + mFinder->SetCaseSensitive (aCaseSensitive); + /* search string is set on ::Find */ +} + +void +EphyFind::SetSelectionAttention (PRBool aAttention) +{ + if (aAttention == mAttention) return; + + mAttention = aAttention; + + PRInt16 display; + if (aAttention) { + display = nsISelectionController::SELECTION_ATTENTION; + } else { + display = nsISelectionController::SELECTION_ON; + } + +#ifdef HAVE_GECKO_1_9 + if (mFinder) { + mFinder->SetSelectionModeAndRepaint (display); + } +#else + nsresult rv; + nsCOMPtr<nsIDocShell> shell (do_GetInterface (mWebBrowser, &rv)); + /* It's okay for this to fail, if the tab is closing, or if + * we weren't attached to any tab yet + */ + if (NS_FAILED (rv) || !shell) return; + + nsCOMPtr<nsISimpleEnumerator> enumerator; + rv = shell->GetDocShellEnumerator (nsIDocShellTreeItem::typeContent, + nsIDocShell::ENUMERATE_FORWARDS, + getter_AddRefs (enumerator)); + NS_ENSURE_SUCCESS (rv, ); + + PRBool hasMore = PR_FALSE; + while (NS_SUCCEEDED (enumerator->HasMoreElements (&hasMore)) && hasMore) { + nsCOMPtr<nsISupports> element; + enumerator->GetNext (getter_AddRefs (element)); + if (!element) continue; + + nsCOMPtr<nsISelectionDisplay> sd (do_GetInterface (element)); + if (!sd) continue; + + nsCOMPtr<nsISelectionController> controller (do_QueryInterface (sd)); + if (!controller) continue; + + controller->SetDisplaySelection (display); + } +#endif /* HAVE_GECKO_1_9 */ +} + +EphyEmbedFindResult +EphyFind::Find (const char *aSearchString, + PRBool aLinksOnly) +{ + if (!mFinder) return EPHY_EMBED_FIND_NOTFOUND; + + nsString uSearchString; + NS_CStringToUTF16 (nsCString (aSearchString ? aSearchString : ""), + NS_CSTRING_ENCODING_UTF8, uSearchString); + + SetSelectionAttention (PR_TRUE); + + nsresult rv; + PRUint16 found = nsITypeAheadFind::FIND_NOTFOUND; + rv = mFinder->Find (uSearchString, aLinksOnly, &found); + + return (EphyEmbedFindResult) found; +} + +EphyEmbedFindResult +EphyFind::FindAgain (PRBool aForward, + PRBool aLinksOnly) +{ + if (!mFinder) return EPHY_EMBED_FIND_NOTFOUND; + + SetSelectionAttention (PR_TRUE); + + nsresult rv; + PRUint16 found = nsITypeAheadFind::FIND_NOTFOUND; +#ifdef HAVE_GECKO_1_9 + rv = mFinder->FindAgain (!aForward, aLinksOnly, &found); +#else + if (aForward) { + rv = mFinder->FindNext (&found); + } else { + rv = mFinder->FindPrevious (&found); + } +#endif + + return (EphyEmbedFindResult) found; +} + +PRBool +EphyFind::ActivateLink (GdkModifierType aMask) +{ + nsresult rv; + nsCOMPtr<nsIDOMElement> link; + rv = mFinder->GetFoundLink (getter_AddRefs (link)); + if (NS_FAILED (rv) || !link) return FALSE; + + nsCOMPtr<nsIDOMDocument> doc; + rv = link->GetOwnerDocument (getter_AddRefs (doc)); + NS_ENSURE_TRUE (doc, FALSE); + + nsCOMPtr<nsIDOMDocumentView> docView (do_QueryInterface (doc)); + NS_ENSURE_TRUE (docView, FALSE); + + nsCOMPtr<nsIDOMAbstractView> abstractView; + docView->GetDefaultView (getter_AddRefs (abstractView)); + NS_ENSURE_TRUE (abstractView, FALSE); + + nsCOMPtr<nsIDOMDocumentEvent> docEvent (do_QueryInterface (doc)); + NS_ENSURE_TRUE (docEvent, FALSE); + + nsCOMPtr<nsIDOMEvent> event; + rv = docEvent->CreateEvent (nsString(kKeyEvents), getter_AddRefs (event)); + NS_ENSURE_SUCCESS (rv, FALSE); + + nsCOMPtr<nsIDOMKeyEvent> keyEvent (do_QueryInterface (event)); + NS_ENSURE_TRUE (keyEvent, FALSE); + + rv = keyEvent->InitKeyEvent (nsString (kKeyPress), + PR_TRUE /* bubble */, + PR_TRUE /* cancelable */, + abstractView, + (aMask & GDK_CONTROL_MASK) != 0, + (aMask & GDK_MOD1_MASK) != 0 /* Alt */, + (aMask & GDK_SHIFT_MASK) != 0, + /* FIXME when we upgrade to gtk 2.10 */ + PR_FALSE /* Meta */, + nsIDOMKeyEvent::DOM_VK_RETURN, + 0); + NS_ENSURE_SUCCESS (rv, FALSE); + + nsCOMPtr<nsIDOMEventTarget> target (do_QueryInterface (link)); + NS_ENSURE_TRUE (target, FALSE); + + PRBool defaultPrevented = PR_FALSE; + rv = target->DispatchEvent (event, &defaultPrevented); + + return NS_SUCCEEDED (rv) && defaultPrevented; +} diff --git a/embed/xulrunner/embed/EphyFind.h b/embed/xulrunner/embed/EphyFind.h new file mode 100644 index 000000000..34c30517d --- /dev/null +++ b/embed/xulrunner/embed/EphyFind.h @@ -0,0 +1,60 @@ +/* + * Copyright © 2005 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#ifndef TYPEAHEADFIND_H +#define TYPEAHEADFIND_H + +#include <gdk/gdktypes.h> + +class nsITypeAheadFind; +class nsIWebBrowser; +class nsIWebBrowserFind; + +#include <nsCOMPtr.h> + +#include "ephy-embed.h" +#include "ephy-embed-find.h" + +class EphyFind +{ + public: + EphyFind (); + ~EphyFind (); + + nsresult SetEmbed (EphyEmbed *aEmbed); + void SetFindProperties (const char *aSearchString, + PRBool aCaseSensitive); + void SetSelectionAttention (PRBool aAttention); + EphyEmbedFindResult Find (const char *aSearchString, + PRBool aLinksOnly); + EphyEmbedFindResult FindAgain (PRBool aForward, + PRBool aLinksOnly); + PRBool ActivateLink (GdkModifierType aMask); + + private: + EphyEmbed *mCurrentEmbed; + + nsCOMPtr<nsIWebBrowser> mWebBrowser; + + nsCOMPtr<nsITypeAheadFind> mFinder; + PRPackedBool mAttention; +}; + +#endif /* !TYPEAHEADFIND_H */ diff --git a/embed/xulrunner/embed/EphyHeaderSniffer.cpp b/embed/xulrunner/embed/EphyHeaderSniffer.cpp new file mode 100644 index 000000000..6ef9318de --- /dev/null +++ b/embed/xulrunner/embed/EphyHeaderSniffer.cpp @@ -0,0 +1,442 @@ +/* ***** 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 Chimera code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright © 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * David Hyatt <hyatt@netscape.com> + * Simon Fraser <sfraser@netscape.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** + * + * $Id$ + */ + +#include "mozilla-config.h" +#include "config.h" + +#include <glib/gi18n.h> +#include <libgnomevfs/gnome-vfs-utils.h> + +#include <nsStringAPI.h> + +#include <nsComponentManagerUtils.h> +#include <nsIChannel.h> +#include <nsIDOMDocument.h> +#include <nsIDOMHTMLDocument.h> +#include <nsIDownload.h> +#include <nsIHttpChannel.h> +#include <nsIInputStream.h> +#include <nsILocalFile.h> +#include <nsIMIMEHeaderParam.h> +#include <nsIMIMEInfo.h> +#include <nsIMIMEService.h> +#include <nsIPrefService.h> +#include <nsIPromptService.h> +#include <nsIURI.h> +#include <nsIURL.h> +#include <nsIWebBrowserPersist.h> +#include <nsIWindowWatcher.h> +#include <nsServiceManagerUtils.h> +#include <nsXPCOMCID.h> + +#include "eel-gconf-extensions.h" +#include "ephy-debug.h" +#include "ephy-file-chooser.h" +#include "ephy-gui.h" +#include "ephy-prefs.h" + +#include "EphyBadCertRejector.h" +#include "MozDownload.h" + +#include "EphyHeaderSniffer.h" + +EphyHeaderSniffer::EphyHeaderSniffer (nsIWebBrowserPersist* aPersist, MozillaEmbedPersist *aEmbedPersist, + nsIFile* aFile, nsIURI* aURL, nsIDOMDocument* aDocument, nsIInputStream* aPostData, + EphyEmbedSingle *single) +: mPersist(aPersist) +, mEmbedPersist(aEmbedPersist) +, mTmpFile(aFile) +, mURL(aURL) +, mOriginalURI(nsnull) +, mDocument(aDocument) +, mPostData(aPostData) +{ + LOG ("EphyHeaderSniffer ctor (%p)", this); + + nsCOMPtr<nsIWindowWatcher> watcher + (do_GetService("@mozilla.org/embedcomp/window-watcher;1")); + if (!watcher) return; + + watcher->GetNewAuthPrompter (nsnull, getter_AddRefs (mAuthPrompt)); + + mSingle = single; + g_object_add_weak_pointer (G_OBJECT (mSingle), + (gpointer *)&mSingle); +} + +EphyHeaderSniffer::~EphyHeaderSniffer() +{ + LOG ("EphyHeaderSniffer dtor (%p)", this); + + if (mSingle) + { + g_object_remove_weak_pointer (G_OBJECT (mSingle), + (gpointer *)&mSingle); + } +} + +NS_IMPL_ISUPPORTS3 (EphyHeaderSniffer, + nsIWebProgressListener, + nsIInterfaceRequestor, + nsIAuthPrompt) + +NS_IMETHODIMP +EphyHeaderSniffer::HandleContent () +{ + gboolean handled = FALSE; + nsCString uriSpec; + + if (mPostData || !mSingle) return NS_ERROR_FAILURE; + + mURL->GetSpec (uriSpec); + + g_signal_emit_by_name (mSingle, "handle_content", mContentType.get(), + uriSpec.get(), &handled); + + return handled ? NS_OK : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +EphyHeaderSniffer::OnStateChange (nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRUint32 aStateFlags, + PRUint32 aStatus) +{ + if (aStateFlags & nsIWebProgressListener::STATE_START) + { + /* be sure to keep it alive while we save since it owns + us as a listener and keep ourselves alive */ + nsCOMPtr<nsIWebBrowserPersist> kungFuDeathGrip(mPersist); + nsCOMPtr<nsIWebProgressListener> kungFuSuicideGrip(this); + + nsresult rv; + nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest, &rv); + if (!channel) return rv; + channel->GetContentType(mContentType); + + nsCOMPtr<nsIURI> origURI; + channel->GetOriginalURI(getter_AddRefs(origURI)); + + nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel)); + if (httpChannel) + { + httpChannel->GetResponseHeader(nsCString("content-disposition"), + mContentDisposition); + } + + mPersist->CancelSave(); + + PRBool exists; + mTmpFile->Exists(&exists); + if (exists) + { + mTmpFile->Remove(PR_FALSE); + } + + rv = HandleContent (); + if (NS_SUCCEEDED (rv)) return NS_OK; + + rv = PerformSave(origURI); + if (NS_FAILED(rv)) + { + /* FIXME put up some UI */ + + } + } + + return NS_OK; +} + +NS_IMETHODIMP +EphyHeaderSniffer::OnProgressChange (nsIWebProgress *aWebProgress, + nsIRequest *aRequest, + PRInt32 aCurSelfProgress, + PRInt32 aMaxSelfProgress, + PRInt32 aCurTotalProgress, + PRInt32 aMaxTotalProgress) +{ + return NS_OK; +} + +NS_IMETHODIMP +EphyHeaderSniffer::OnLocationChange (nsIWebProgress *aWebProgress, + nsIRequest *aRequest, + nsIURI *location) +{ + return NS_OK; +} + +NS_IMETHODIMP +EphyHeaderSniffer::OnStatusChange (nsIWebProgress *aWebProgress, + nsIRequest *aRequest, + nsresult aStatus, + const PRUnichar *aMessage) +{ + return NS_OK; +} + +NS_IMETHODIMP +EphyHeaderSniffer::OnSecurityChange (nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRUint32 state) +{ + return NS_OK; +} + +/* void getInterface (in nsIIDRef uuid, [iid_is (uuid), retval] out nsQIResult result); */ +NS_IMETHODIMP +EphyHeaderSniffer::GetInterface(const nsIID & uuid, void * *result) +{ + if (uuid.Equals (NS_GET_IID (nsIBadCertListener)) && + mEmbedPersist) + { + EphyEmbedPersistFlags flags; + + g_object_get (mEmbedPersist, "flags", &flags, (char *) NULL); + + if (flags & EPHY_EMBED_PERSIST_NO_CERTDIALOGS) + { + EphyBadCertRejector *badCertRejector = new EphyBadCertRejector (); + if (!badCertRejector) return NS_ERROR_OUT_OF_MEMORY; + + *result = static_cast<nsIBadCertListener*>(badCertRejector); + NS_ADDREF (badCertRejector); + + return NS_OK; + } + } + + return NS_ERROR_NO_INTERFACE; +} + +static void +filechooser_response_cb (GtkWidget *dialog, + gint response, + EphyHeaderSniffer* sniffer) +{ + if (response == GTK_RESPONSE_ACCEPT) + { + char *filename; + + filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog)); + + if (ephy_gui_check_location_writable (dialog, filename) == FALSE) + { + g_free (filename); + return; + } + + nsCOMPtr<nsILocalFile> destFile = do_CreateInstance (NS_LOCAL_FILE_CONTRACTID); + if (destFile) + { + destFile->InitWithNativePath (nsCString (filename)); + + sniffer->InitiateDownload (destFile); + } + + g_free (filename); + } + + // FIXME how to inform user of failed save ? + + gtk_widget_destroy (GTK_WIDGET (dialog)); +} + +nsresult EphyHeaderSniffer::PerformSave (nsIURI* inOriginalURI) +{ + nsresult rv; + EphyEmbedPersistFlags flags; + PRBool askDownloadDest; + + mOriginalURI = inOriginalURI; + + flags = ephy_embed_persist_get_flags (EPHY_EMBED_PERSIST (mEmbedPersist)); + askDownloadDest = flags & EPHY_EMBED_PERSIST_ASK_DESTINATION; + + nsString defaultFileName; + + if (!defaultFileName.Length() && mContentDisposition.Length()) + { + /* 1 Use the HTTP header suggestion. */ + nsCOMPtr<nsIMIMEHeaderParam> mimehdrpar = + do_GetService("@mozilla.org/network/mime-hdrparam;1"); + + if (mimehdrpar) + { + nsCString fallbackCharset; + if (mURL) + { + mURL->GetOriginCharset(fallbackCharset); + } + + nsString fileName; + + rv = mimehdrpar->GetParameter (mContentDisposition, "filename", + fallbackCharset, PR_TRUE, nsnull, + fileName); + if (NS_FAILED(rv) || !fileName.Length()) + { + rv = mimehdrpar->GetParameter (mContentDisposition, "name", + fallbackCharset, PR_TRUE, nsnull, + fileName); + } + + if (NS_SUCCEEDED(rv) && fileName.Length()) + { + defaultFileName = fileName; + } + } + } + + if (!defaultFileName.Length()) + { + /* 2 For file URLs, use the file name. */ + + nsCOMPtr<nsIURL> url(do_QueryInterface(mURL)); + if (url) + { + nsCString fileNameCString; + url->GetFileName(fileNameCString); + NS_CStringToUTF16 (fileNameCString, NS_CSTRING_ENCODING_UTF8, + defaultFileName); + } + } + + if (!defaultFileName.Length() && mDocument) + { + /* 3 Use the title of the document. */ + + nsCOMPtr<nsIDOMHTMLDocument> htmlDoc(do_QueryInterface(mDocument)); + if (htmlDoc) + { + htmlDoc->GetTitle(defaultFileName); + } + } + + if (!defaultFileName.Length() && mURL) + { + /* 4 Use the host. */ + nsCString hostName; + mURL->GetHost(hostName); + NS_CStringToUTF16 (hostName, NS_CSTRING_ENCODING_UTF8, + defaultFileName); + } + + /* 5 One last case to handle about:blank and other untitled pages. */ + if (!defaultFileName.Length()) + { + NS_CStringToUTF16 (nsCString(_("Untitled")), + NS_CSTRING_ENCODING_UTF8, defaultFileName); + } + + /* Validate the file name to ensure legality. */ + nsCString cDefaultFileName; + NS_UTF16ToCString (defaultFileName, NS_CSTRING_ENCODING_UTF8, + cDefaultFileName); + char *default_name = g_strdup (cDefaultFileName.get()); + default_name = g_strdelimit (default_name, "/\\:", ' '); + + const char *key; + key = ephy_embed_persist_get_persist_key (EPHY_EMBED_PERSIST (mEmbedPersist)); + + /* FIXME: do better here by using nsITextToSubURI service, like in + * http://lxr.mozilla.org/seamonkey/source/xpfe/communicator/resources/content/contentAreaUtils.js#763 + */ + char *filename; + filename = gnome_vfs_unescape_string (default_name, NULL); + + if (!g_utf8_validate (filename, -1, NULL)) + { + g_free (filename); + filename = g_strdup (default_name); + } + + g_free (default_name); + + if (askDownloadDest) + { + EphyFileChooser *dialog; + GtkWindow *window; + const char *title; + guint32 user_time; + + title = ephy_embed_persist_get_fc_title (EPHY_EMBED_PERSIST (mEmbedPersist)); + window = ephy_embed_persist_get_fc_parent (EPHY_EMBED_PERSIST (mEmbedPersist)); + + user_time = ephy_embed_persist_get_user_time (EPHY_EMBED_PERSIST (mEmbedPersist)); + if (user_time == 0) + { + g_warning ("EphyHeaderSniffer::PerformSave without valid user time!\n"); + } + + dialog = ephy_file_chooser_new (title ? title: _("Save"), + GTK_WIDGET (window), + GTK_FILE_CHOOSER_ACTION_SAVE, + key ? key : CONF_STATE_SAVE_DIR, + EPHY_FILE_FILTER_ALL_SUPPORTED); + gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), TRUE); + + gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), + filename); + + g_signal_connect (dialog, "response", + G_CALLBACK (filechooser_response_cb), this); + + ephy_gui_window_update_user_time (GTK_WIDGET (dialog), user_time); + gtk_widget_show (GTK_WIDGET (dialog)); + + g_free (filename); + return NS_OK; + } + /* FIXME: how to inform user of failed save ? */ + + nsCOMPtr<nsILocalFile> destFile; + BuildDownloadPath (filename, getter_AddRefs (destFile)); + g_free (filename); + NS_ENSURE_TRUE (destFile, NS_ERROR_FAILURE); + + return InitiateDownload (destFile); +} + +nsresult EphyHeaderSniffer::InitiateDownload (nsILocalFile *aDestFile) +{ + LOG ("Initiating download"); + + return InitiateMozillaDownload (mDocument, mURL, aDestFile, + mContentType.get(), mOriginalURI, mEmbedPersist, + mPostData, nsnull, -1); +} diff --git a/embed/xulrunner/embed/EphyHeaderSniffer.h b/embed/xulrunner/embed/EphyHeaderSniffer.h new file mode 100644 index 000000000..ec73c3164 --- /dev/null +++ b/embed/xulrunner/embed/EphyHeaderSniffer.h @@ -0,0 +1,95 @@ +/* ***** 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 Chimera code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright © 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * David Hyatt <hyatt@netscape.com> + * Simon Fraser <sfraser@netscape.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** + * + * $Id$ + */ + +#ifndef EPHY_HEADER_SNIFFER_H +#define EPHY_HEADER_SNIFFER_H + +class nsIDOMDocument; +class nsIFile; +class nsIInputStream; +class nsILocalFile; +class nsIURI; +class nsIWebBrowserPersist; + +#include <nsCOMPtr.h> +#include <nsIAuthPrompt.h> +#include <nsIInterfaceRequestor.h> +#include <nsIWebProgressListener.h> + +#include "mozilla-embed-persist.h" +#include "ephy-embed-single.h" + +class EphyHeaderSniffer : public nsIWebProgressListener, + public nsIInterfaceRequestor, + public nsIAuthPrompt +{ +public: + EphyHeaderSniffer (nsIWebBrowserPersist* aPersist, MozillaEmbedPersist *aEmbedPersist, + nsIFile* aFile, nsIURI* aURL, nsIDOMDocument* aDocument, + nsIInputStream* aPostData, EphyEmbedSingle *single); + virtual ~EphyHeaderSniffer (); + + NS_DECL_ISUPPORTS + NS_DECL_NSIWEBPROGRESSLISTENER + NS_FORWARD_SAFE_NSIAUTHPROMPT(mAuthPrompt) + NS_DECL_NSIINTERFACEREQUESTOR + + nsresult InitiateDownload (nsILocalFile *aDestFile); + +protected: + nsresult PerformSave (nsIURI* inOriginalURI); + nsresult HandleContent (); + +private: + nsIWebBrowserPersist* mPersist; /* Weak. It owns us as a listener. */ + MozillaEmbedPersist *mEmbedPersist; + EphyEmbedSingle *mSingle; + nsCOMPtr<nsIFile> mTmpFile; + nsCOMPtr<nsIURI> mURL; + nsCOMPtr<nsIURI> mOriginalURI; + nsCOMPtr<nsIDOMDocument> mDocument; + nsCOMPtr<nsIInputStream> mPostData; + nsCString mContentType; + nsCString mContentDisposition; + nsCOMPtr<nsIAuthPrompt> mAuthPrompt; +}; + +#endif /* !EPHY_HEADER_SNIFFER_H */ diff --git a/embed/xulrunner/embed/EphyHistoryListener.cpp b/embed/xulrunner/embed/EphyHistoryListener.cpp new file mode 100644 index 000000000..232c3ccb9 --- /dev/null +++ b/embed/xulrunner/embed/EphyHistoryListener.cpp @@ -0,0 +1,170 @@ +/* + * Copyright © 2004 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#include "mozilla-config.h" +#include "config.h" + +#include <nsStringAPI.h> + +#include <nsCOMPtr.h> +#include <nsCURILoader.h> +#include <nsIChannel.h> +#include <nsIDocumentLoader.h> +#include <nsIHttpChannel.h> +#include <nsIRequest.h> +#include <nsIRequestObserver.h> +#include <nsISupportsUtils.h> +#include <nsIURI.h> +#include <nsIWebProgress.h> +#include <nsNetCID.h> +#include <nsServiceManagerUtils.h> + +#include "EphyUtils.h" + +#include "ephy-debug.h" + +#include "EphyHistoryListener.h" + +EphyHistoryListener::EphyHistoryListener () +{ + LOG ("EphyHistoryListener ctor"); +} + +EphyHistoryListener::~EphyHistoryListener () +{ + LOG ("EphyHistoryListener dtor"); +} + +nsresult +EphyHistoryListener::Init (EphyHistory *aHistory) +{ + mHistory = aHistory; + + nsresult rv; + nsCOMPtr<nsIWebProgress> webProgress + (do_GetService(NS_DOCUMENTLOADER_SERVICE_CONTRACTID, &rv)); + NS_ENSURE_TRUE (NS_SUCCEEDED (rv) && webProgress, rv); + + rv = webProgress->AddProgressListener + (static_cast<nsIWebProgressListener*>(this), + nsIWebProgress::NOTIFY_STATE_REQUEST); + + return rv; +} + +NS_IMPL_ISUPPORTS2 (EphyHistoryListener, + nsIWebProgressListener, + nsISupportsWeakReference) + +/* void onStateChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long aStateFlags, in nsresult aStatus); */ +NS_IMETHODIMP +EphyHistoryListener::OnStateChange (nsIWebProgress *aWebProgress, + nsIRequest *aRequest, + PRUint32 aStateFlags, + nsresult aStatus) +{ + nsresult rv = NS_OK; + + /* we only care about redirects */ + if (! (aStateFlags & nsIWebProgressListener::STATE_REDIRECTING)) + { + return rv; + } + + nsCOMPtr<nsIChannel> channel (do_QueryInterface (aRequest)); + nsCOMPtr<nsIHttpChannel> httpChannel (do_QueryInterface (channel)); + if (!httpChannel) return rv; + + PRUint32 status = 0; + rv = httpChannel->GetResponseStatus (&status); + if (rv == NS_ERROR_NOT_AVAILABLE) return NS_OK; + NS_ENSURE_SUCCESS (rv, rv); + + /* we're only interested in 301 redirects (moved permanently) */ + if (status != 301) return NS_OK; + + nsCOMPtr<nsIURI> fromURI; + rv = channel->GetURI (getter_AddRefs (fromURI)); + NS_ENSURE_TRUE (NS_SUCCEEDED (rv) && fromURI, rv); + + nsCString location; + rv = httpChannel->GetResponseHeader + (nsCString ("Location"), location); + NS_ENSURE_TRUE (NS_SUCCEEDED (rv) && location.Length(), rv); + + nsCOMPtr<nsIURI> toURI; + rv = EphyUtils::NewURI (getter_AddRefs (toURI), location, + nsnull /* use origin charset of fromURI */, fromURI); + NS_ENSURE_TRUE (NS_SUCCEEDED (rv) && toURI, rv); + + nsCString fromSpec, toSpec; + rv = fromURI->GetSpec (fromSpec); + rv |= toURI->GetSpec(toSpec); + NS_ENSURE_SUCCESS (rv, rv); + + g_signal_emit_by_name (mHistory, "redirect", + fromSpec.get(), toSpec.get()); + + return rv; +} + +/* void onProgressChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long aCurSelfProgress, in long aMaxSelfProgress, in long aCurTotalProgress, in long aMaxTotalProgress); */ +NS_IMETHODIMP +EphyHistoryListener::OnProgressChange (nsIWebProgress *aWebProgress, + nsIRequest *aRequest, + PRInt32 aCurSelfProgress, + PRInt32 aMaxSelfProgress, + PRInt32 aCurTotalProgress, + PRInt32 aMaxTotalProgress) +{ + NS_NOTREACHED("notification excluded in AddProgressListener(...)"); + return NS_OK; +} + +/* void onLocationChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsIURI location); */ +NS_IMETHODIMP +EphyHistoryListener::OnLocationChange (nsIWebProgress *aWebProgress, + nsIRequest *aRequest, + nsIURI *location) +{ + NS_NOTREACHED("notification excluded in AddProgressListener(...)"); + return NS_OK; +} + +/* void onStatusChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsresult aStatus, in wstring aMessage); */ +NS_IMETHODIMP +EphyHistoryListener::OnStatusChange (nsIWebProgress *aWebProgress, + nsIRequest *aRequest, + nsresult aStatus, + const PRUnichar *aMessage) +{ + NS_NOTREACHED("notification excluded in AddProgressListener(...)"); + return NS_OK; +} + +/* void onSecurityChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in unsigned long state); */ +NS_IMETHODIMP +EphyHistoryListener::OnSecurityChange (nsIWebProgress *aWebProgress, + nsIRequest *aRequest, + PRUint32 state) +{ + NS_NOTREACHED("notification excluded in AddProgressListener(...)"); + return NS_OK; +} diff --git a/embed/xulrunner/embed/EphyHistoryListener.h b/embed/xulrunner/embed/EphyHistoryListener.h new file mode 100644 index 000000000..23f955f05 --- /dev/null +++ b/embed/xulrunner/embed/EphyHistoryListener.h @@ -0,0 +1,49 @@ +/* + * Copyright © 2004 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#ifndef EPHY_REDIRECT_LISTENER_H +#define EPHY_REDIRECT_LISTENER_H + +#include "ephy-history.h" + +#include <nsIWebProgressListener.h> +#include <nsWeakReference.h> + +/* 6a9533c6-f068-4e63-8225-5feba0b54d6b */ +#define EPHY_REDIRECTLISTENER_CID \ +{ 0x6a9533c6, 0xf068, 0x4e63, { 0x82, 0x25, 0x5f, 0xeb, 0xa0, 0xb5, 0x4d, 0x6b } } +#define EPHY_REDIRECTLISTENER_CLASSNAME "Epiphany Redirect Listener Class" + +class EphyHistoryListener : public nsIWebProgressListener, + public nsSupportsWeakReference +{ + public: + EphyHistoryListener(); + virtual ~EphyHistoryListener(); + + nsresult Init (EphyHistory *aHistory); + + NS_DECL_ISUPPORTS + NS_DECL_NSIWEBPROGRESSLISTENER + private: + EphyHistory *mHistory; +}; + +#endif /* EPHY_REDIRECT_LISTENER_H */ diff --git a/embed/xulrunner/embed/EphyPromptService.cpp b/embed/xulrunner/embed/EphyPromptService.cpp new file mode 100644 index 000000000..29813f300 --- /dev/null +++ b/embed/xulrunner/embed/EphyPromptService.cpp @@ -0,0 +1,888 @@ +/* + * Copyright © 2005, 2006 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#include "mozilla-config.h" +#include "config.h" + +#include <glib.h> +#include <glib-object.h> +#include <glib/gi18n.h> +#include <gtk/gtk.h> + +#include <nsStringAPI.h> + +#include <nsCOMPtr.h> +#include <nsIDOMWindow.h> +#include <nsServiceManagerUtils.h> + +#include "ephy-embed-shell.h" +#include "ephy-gui.h" +#include "ephy-debug.h" + +#include "AutoJSContextStack.h" +#include "AutoWindowModalState.h" +#include "EphyUtils.h" + +#include "EphyPromptService.h" + +#define TIMEOUT 1000 /* ms */ +#define TIMEOUT_DATA_KEY "timeout" + +#define MAX_MESSAGE_LENGTH 512 +#define MAX_TITLE_LENGTH 256 +#define MAX_BUTTON_TEXT_LENGTH 128 + +enum +{ + RESPONSE_ABORT_SCRIPT = 42 +}; + +class Prompter +{ +public: + Prompter (const char*, nsIDOMWindow*, const PRUnichar*, const PRUnichar*); + ~Prompter(); + + void AddStockButton (const char*, int); + void AddButtonWithFlags (PRInt32, PRUint32, const PRUnichar*, PRUint32); + void AddButtonsWithFlags (PRUint32, const PRUnichar*, const PRUnichar*, const PRUnichar*); + void AddCheckbox (const PRUnichar*, PRBool*); + void GetCheckboxState (PRBool *); + void AddEntry (const char *, const PRUnichar *, PRBool); + void GetText (PRUint32, PRUnichar **); + void AddSelect (PRUint32, const PRUnichar **, PRInt32); + void GetSelected (PRInt32*); + + PRInt32 Run (PRBool * = nsnull); + void Show (); + + PRBool IsCalledFromScript (); + void PerformScriptAbortion (); + + char *ConvertAndTruncateString (const PRUnichar *, PRInt32 = -1); + char* ConvertAndEscapeButtonText (const PRUnichar *, PRInt32 = -1); + +private: + nsCOMPtr<nsIDOMWindow> mWindow; + GtkDialog *mDialog; + GtkWidget *mVBox; + GtkWidget *mCheck; + GtkSizeGroup *mSizeGroup; + GtkWidget *mEntries[2]; + GtkWidget *mCombo; + PRInt32 mNumButtons; + PRInt32 mNumEntries; + PRInt32 mDefaultResponse; + PRInt32 mUnaffirmativeResponse; + PRInt32 mResponse; + PRBool mSuccess; + PRBool mDelay; +}; + +Prompter::Prompter (const char *aStock, + nsIDOMWindow *aParent, + const PRUnichar *aTitle, + const PRUnichar *aText) + : mWindow (aParent) + , mDialog(nsnull) + , mVBox(nsnull) + , mCheck(nsnull) + , mSizeGroup(nsnull) + , mCombo(nsnull) + , mNumButtons(0) + , mNumEntries(0) + , mDefaultResponse(GTK_RESPONSE_ACCEPT) + , mUnaffirmativeResponse(0) + , mResponse(GTK_RESPONSE_CANCEL) + , mSuccess(PR_FALSE) + , mDelay(PR_FALSE) +{ + GtkWidget *parent, *hbox, *label, *image; + + g_object_ref (ephy_embed_shell_get_default ()); + + mEntries[0] = mEntries[1] = nsnull; + + mDialog = GTK_DIALOG (gtk_dialog_new ()); + g_object_ref_sink (mDialog); + + char *title = NULL; + if (aTitle) + { + title = ConvertAndTruncateString (aTitle, MAX_TITLE_LENGTH); + } + + gtk_window_set_title (GTK_WINDOW (mDialog), title ? title : ""); + g_free (title); + + gtk_window_set_modal (GTK_WINDOW (mDialog), TRUE); + + parent = EphyUtils::FindGtkParent (aParent); + if (GTK_IS_WINDOW (parent)) + { + gtk_window_set_transient_for (GTK_WINDOW (mDialog), + GTK_WINDOW (parent)); + + gtk_window_group_add_window (ephy_gui_ensure_window_group (GTK_WINDOW (parent)), + GTK_WINDOW (mDialog)); + } + + gtk_dialog_set_has_separator (mDialog, FALSE); + gtk_window_set_resizable (GTK_WINDOW (mDialog), FALSE); + gtk_container_set_border_width (GTK_CONTAINER (mDialog), 5); + gtk_box_set_spacing (GTK_BOX (mDialog->vbox), 14); /* 2 * 5 + 14 = 24 */ + + hbox = gtk_hbox_new (FALSE, 12); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); + gtk_container_add (GTK_CONTAINER (GTK_DIALOG (mDialog)->vbox), hbox); + + image = gtk_image_new_from_stock (aStock, GTK_ICON_SIZE_DIALOG); + gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0.0); + gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0); + + mVBox = gtk_vbox_new (FALSE, 12); + gtk_box_pack_start (GTK_BOX (hbox), mVBox, TRUE, TRUE, 0); + + char *text = NULL; + if (aText) + { + text = ConvertAndTruncateString (aText, MAX_MESSAGE_LENGTH); + } + + label = gtk_label_new (text); + g_free (text); + + gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); + /* Guard against overlong nonbreakable text (exploit) */ + gtk_label_set_line_wrap_mode (GTK_LABEL (label), PANGO_WRAP_WORD_CHAR); + gtk_label_set_selectable (GTK_LABEL (label), TRUE); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.0); + + gtk_box_pack_start (GTK_BOX (mVBox), label, FALSE, FALSE, 0); + gtk_widget_show (label); + + if (IsCalledFromScript ()) + { + gtk_dialog_add_button (GTK_DIALOG (mDialog), + _("_Abort Script"), + RESPONSE_ABORT_SCRIPT); + } + + gtk_widget_show (image); + gtk_widget_show (mVBox); + gtk_widget_show (hbox); +} + +Prompter::~Prompter () +{ + if (mSizeGroup) + { + g_object_unref (mSizeGroup); + } + + gtk_widget_destroy (GTK_WIDGET (mDialog)); + g_object_unref (mDialog); + + g_object_unref (ephy_embed_shell_get_default ()); +} + +void +Prompter::AddStockButton (const char *aStock, + int aResponse) +{ + gtk_dialog_add_button (GTK_DIALOG (mDialog), + aStock, aResponse); + ++mNumButtons; +} + +void +Prompter::AddButtonWithFlags (PRInt32 aNum, + PRUint32 aFlags, + const PRUnichar *aText, + PRUint32 aDefault) +{ + if (aFlags == 0) return; + + const char *label = NULL; + char *freeme = NULL; + gboolean isAffirmative = FALSE; + switch (aFlags) + { + case nsIPromptService::BUTTON_TITLE_OK: + label = GTK_STOCK_OK; + isAffirmative = TRUE; + break; + + case nsIPromptService::BUTTON_TITLE_CANCEL: + label = GTK_STOCK_CANCEL; + break; + + case nsIPromptService::BUTTON_TITLE_YES: + label = GTK_STOCK_YES; + isAffirmative = TRUE; + break; + + case nsIPromptService::BUTTON_TITLE_NO: + label = GTK_STOCK_NO; + break; + + case nsIPromptService::BUTTON_TITLE_SAVE: + label = GTK_STOCK_SAVE; + isAffirmative = TRUE; + break; + + case nsIPromptService::BUTTON_TITLE_DONT_SAVE: + label = _("Don't Save"); + break; + + case nsIPromptService::BUTTON_TITLE_REVERT: + label = GTK_STOCK_REVERT_TO_SAVED; + break; + + case nsIPromptService::BUTTON_TITLE_IS_STRING: + default: + label = freeme = ConvertAndEscapeButtonText (aText, MAX_BUTTON_TEXT_LENGTH); + /* We can't tell, so assume it's affirmative */ + isAffirmative = TRUE; + break; + } + + if (label == NULL) return; + + gtk_dialog_add_button (mDialog, label, aNum); + ++mNumButtons; + + if (isAffirmative && mDelay) + { + gtk_dialog_set_response_sensitive (mDialog, aNum, FALSE); + } + + if (!isAffirmative) + { + mUnaffirmativeResponse = aNum; + } + + if (aDefault) + { + mDefaultResponse = aNum; + } + + g_free (freeme); +} + +void +Prompter::AddButtonsWithFlags (PRUint32 aFlags, + const PRUnichar *aText0, + const PRUnichar *aText1, + const PRUnichar *aText2) +{ + mDelay = (aFlags & nsIPromptService::BUTTON_DELAY_ENABLE) != 0; + mDefaultResponse = -1; + + /* Reverse the order, on the assumption that what we passed is the + * 'windows' button order, and we want HIG order. + */ + AddButtonWithFlags (2, ((aFlags / nsIPromptService::BUTTON_POS_2) & 0xff), aText2, + aFlags & nsIPromptService::BUTTON_POS_2_DEFAULT); + AddButtonWithFlags (1, ((aFlags / nsIPromptService::BUTTON_POS_1) & 0xff), aText1, + aFlags & nsIPromptService::BUTTON_POS_1_DEFAULT); + AddButtonWithFlags (0, ((aFlags / nsIPromptService::BUTTON_POS_0) & 0xff), aText0, + aFlags & nsIPromptService::BUTTON_POS_0_DEFAULT); + + /* If no default was set, use the 'rightmost' unaffirmative response. + * This happens with the suite's password manager prompt. + */ + if (mDefaultResponse == -1) + { + mDefaultResponse = mUnaffirmativeResponse; + } +} + +void +Prompter::AddCheckbox (const PRUnichar *aText, + PRBool *aState) +{ + if (!aState || !aText) return; + + char *label = ConvertAndEscapeButtonText (aText, 2 * MAX_BUTTON_TEXT_LENGTH); + mCheck = gtk_check_button_new_with_mnemonic (label); + g_free (label); + + gtk_label_set_line_wrap (GTK_LABEL (GTK_BIN (mCheck)->child), TRUE); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mCheck), *aState); + gtk_box_pack_start (GTK_BOX (mVBox), mCheck, FALSE, FALSE, 0); + gtk_widget_show (mCheck); +} + +void +Prompter::GetCheckboxState (PRBool *aState) +{ + if (!aState || !mCheck) return; + + *aState = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (mCheck)); +} + +void +Prompter::AddEntry (const char *aLabel, + const PRUnichar *aValue, + PRBool aIsPassword) +{ + if (!mSizeGroup) + { + mSizeGroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); + } + + GtkWidget *hbox = gtk_hbox_new (FALSE, 12); + gtk_box_pack_start (GTK_BOX (mVBox), hbox, FALSE, FALSE, 0); + + GtkWidget *label = nsnull; + if (aLabel) + { + label = gtk_label_new_with_mnemonic (aLabel); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); + gtk_size_group_add_widget (mSizeGroup, label); + } + + GtkWidget *entry = mEntries[mNumEntries++] = gtk_entry_new (); + gtk_entry_set_visibility (GTK_ENTRY (entry), !aIsPassword); + gtk_entry_set_activates_default(GTK_ENTRY (entry), TRUE); + + if (aValue) + { + nsCString cValue; + NS_UTF16ToCString (nsDependentString(aValue), + NS_CSTRING_ENCODING_UTF8, cValue); + + gtk_entry_set_text (GTK_ENTRY (entry), cValue.get()); + } + + if (label) + { + gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry); + } + + gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0); + gtk_widget_show_all (hbox); +} + +void +Prompter::GetText (PRUint32 aNum, + PRUnichar **aValue) +{ + if (!aValue || !mEntries[aNum]) return; + + const char *text = gtk_entry_get_text (GTK_ENTRY (mEntries[aNum])); + if (!text) return; + + nsString value; + NS_CStringToUTF16 (nsDependentCString (text), + NS_CSTRING_ENCODING_UTF8, value); + + *aValue = NS_StringCloneData (value); +} + +void +Prompter::AddSelect (PRUint32 aCount, + const PRUnichar **aList, + PRInt32 aDefault) +{ + mCombo = gtk_combo_box_new_text (); + + for (PRUint32 i = 0; i < aCount; i++) + { + /* FIXME: use "" instead in this case? */ + if (!aList[i] || !aList[i][0]) continue; + + nsCString cData; + NS_UTF16ToCString (nsDependentString(aList[i]), NS_CSTRING_ENCODING_UTF8, cData); + + gtk_combo_box_append_text (GTK_COMBO_BOX (mCombo), cData.get()); + } + + gtk_combo_box_set_active (GTK_COMBO_BOX (mCombo), aDefault); + + gtk_box_pack_start (GTK_BOX (mVBox), mCombo, FALSE, FALSE, 0); + gtk_widget_show (mCombo); +} + +void +Prompter::GetSelected (PRInt32 *aSelected) +{ + if (!aSelected || !mCombo) return; + + *aSelected = gtk_combo_box_get_active (GTK_COMBO_BOX (mCombo)); +} + +static gboolean +EnableResponse (GtkDialog *aDialog) +{ + g_object_steal_data (G_OBJECT (aDialog), TIMEOUT_DATA_KEY); + + gtk_dialog_set_response_sensitive (aDialog, 0, TRUE); + gtk_dialog_set_response_sensitive (aDialog, 1, TRUE); + gtk_dialog_set_response_sensitive (aDialog, 2, TRUE); + + return FALSE; +} + +static void +RemoveTimeout (gpointer idptr) +{ + guint timeout = GPOINTER_TO_UINT (idptr); + + g_return_if_fail (timeout != 0); + + g_source_remove (timeout); +} + +PRInt32 +Prompter::Run (PRBool *aSuccess) +{ +#if 0 + AutoEventQueue queue; + if (NS_FAILED (queue.Init())) + { + if (aSuccess) + { + *aSuccess = PR_FALSE; + } + mSuccess = PR_FALSE; + + return GTK_RESPONSE_CANCEL; + } +#endif + + nsresult rv; + AutoJSContextStack stack; + rv = stack.Init (); + if (NS_FAILED (rv)) return rv; + + AutoWindowModalState modalState (mWindow); + + if (mDelay) + { + guint timeout = g_timeout_add (TIMEOUT, + (GSourceFunc) EnableResponse, + mDialog); + g_object_set_data_full (G_OBJECT (mDialog), TIMEOUT_DATA_KEY, + GUINT_TO_POINTER (timeout), + (GDestroyNotify) RemoveTimeout); + } + + gtk_dialog_set_default_response (GTK_DIALOG (mDialog), mDefaultResponse); + + GtkWidget *widget = GTK_WIDGET (mDialog); + gtk_widget_show (widget); + mResponse = gtk_dialog_run (mDialog); + gtk_widget_hide (widget); + + g_object_set_data (G_OBJECT (mDialog), TIMEOUT_DATA_KEY, NULL); + + mSuccess = (GTK_RESPONSE_ACCEPT == mResponse); + if (aSuccess) + { + *aSuccess = mSuccess; + } + + if (mResponse == RESPONSE_ABORT_SCRIPT) + { + PerformScriptAbortion (); + } + + return mResponse; +} + +static void +DeletePrompter (gpointer aPromptPtr, + GObject *aZombie) +{ + Prompter *prompt = static_cast<Prompter*>(aPromptPtr); + + delete prompt; +} + +void +Prompter::Show () +{ + /* We don't need it anymore */ + mWindow = nsnull; + + gtk_window_set_modal (GTK_WINDOW (mDialog), FALSE); + + g_signal_connect (mDialog, "response", + G_CALLBACK (gtk_widget_destroy), NULL); + g_object_weak_ref (G_OBJECT (mDialog), + (GWeakNotify) DeletePrompter, + static_cast<gpointer>(this)); + + gtk_widget_show (GTK_WIDGET (mDialog)); +} + +PRBool +Prompter::IsCalledFromScript() +{ +#if 0 + nsCOMPtr<nsIXPConnect> xpconnect (do_GetService (nsIXPConnect::GetCID())); + NS_ENSURE_TRUE (xpconnect, PR_FALSE); + + nsresult rv; + nsCOMPtr<nsIXPCNativeCallContext> ncc; + rv = xpconnect->GetCurrentNativeCallContext (getter_AddRefs (ncc)); + NS_ENSURE_SUCCESS (rv, PR_FALSE); + + if (!ncc) return PR_FALSE; + + JSContext *cx = nsnull; + rv = ncc->GetJSContext (&cx); + g_print ("GetJSContext rv=%x, cx=%p\n", rv, cx); + + NS_ENSURE_SUCCESS (rv, PR_FALSE); + + return cx != nsnull; +#endif + return PR_FALSE; +} + +void +Prompter::PerformScriptAbortion() +{ +#if 0 + /* FIXME: can we only stop the calling script, not all scripts in the context? */ + + nsCOMPtr<nsIXPConnect> xpconnect (do_GetService (nsIXPConnect::GetCID())); + NS_ENSURE_TRUE (xpconnect, ); + + nsresult rv; + nsCOMPtr<nsIXPCNativeCallContext> ncc; + rv = xpconnect->GetCurrentNativeCallContext (getter_AddRefs (ncc)); + NS_ENSURE_SUCCESS (rv, ); + NS_ENSURE_TRUE (ncc, ); + + JSContext *cx = nsnull; + rv = ncc->GetJSContext (&cx); + g_print ("GetJSContext rv=%x, cx=%p\n", rv, cx); + NS_ENSURE_SUCCESS (rv, ); + NS_ENSURE_TRUE (cx, ); + + g_print ("Would now disable scripts\n"); +// MozillaPrivate::SetScriptsEnabled (cx, PR_FALSE, PR_FALSE); +#endif +} + +char * +Prompter::ConvertAndTruncateString (const PRUnichar *aText, + PRInt32 aMaxLength) +{ + if (aText == nsnull) return NULL; + + /* This depends on the assumption that + * typeof(PRUnichar) == typeof (gunichar2) == uint16, + * which should be pretty safe. + */ + glong n_read = 0, n_written = 0; + char *converted = g_utf16_to_utf8 ((gunichar2*) aText, aMaxLength, + &n_read, &n_written, NULL); + /* FIXME loop from the end while !g_unichar_isspace (char)? */ + + return converted; +} + +char * +Prompter::ConvertAndEscapeButtonText(const PRUnichar *aText, + PRInt32 aMaxLength) +{ + char *converted = ConvertAndTruncateString (aText, aMaxLength); + if (converted == NULL) return NULL; + + char *escaped = (char*) g_malloc (strlen (converted) + 1); + char *q = escaped; + for (const char *p = converted; *p; ++p, ++q) + { + if (*p == '&') + { + if (*(p+1) == '&') + { + *q = '&'; + ++p; + } + else + { + *q = '_'; + } + } + else + { + *q = *p; + } + } + + /* Null termination */ + *q = '\0'; + + g_free (converted); + + return escaped; +} + +/* FIXME: needs THREADSAFE? */ +#if HAVE_NSINONBLOCKINGALERTSERVICE_H +NS_IMPL_ISUPPORTS2 (EphyPromptService, + nsIPromptService, + nsINonBlockingAlertService) +#else +NS_IMPL_ISUPPORTS1 (EphyPromptService, + nsIPromptService) +#endif + +EphyPromptService::EphyPromptService() +{ + LOG ("EphyPromptService ctor (%p)", this); +} + +EphyPromptService::~EphyPromptService() +{ + LOG ("EphyPromptService dtor (%p)", this); +} + +/* nsIPromptService implementation */ + +/* void alert (in nsIDOMWindow aParent, in wstring aDialogTitle, in wstring aText); */ +NS_IMETHODIMP +EphyPromptService::Alert (nsIDOMWindow *aParent, + const PRUnichar *aDialogTitle, + const PRUnichar *aText) +{ + Prompter prompt (GTK_STOCK_DIALOG_INFO, aParent, aDialogTitle, aText); + prompt.AddStockButton (GTK_STOCK_OK, GTK_RESPONSE_ACCEPT); + prompt.Run (); + + return NS_OK; +} + +/* void alertCheck (in nsIDOMWindow aParent, in wstring aDialogTitle, in wstring aText, in wstring aCheckMsg, inout boolean aCheckState); */ +NS_IMETHODIMP +EphyPromptService::AlertCheck (nsIDOMWindow *aParent, + const PRUnichar *aDialogTitle, + const PRUnichar *aText, + const PRUnichar *aCheckMsg, + PRBool *aCheckState) +{ + Prompter prompt (GTK_STOCK_DIALOG_INFO, aParent, aDialogTitle, aText); + prompt.AddStockButton (GTK_STOCK_OK, GTK_RESPONSE_ACCEPT); + prompt.AddCheckbox (aCheckMsg, aCheckState); + + prompt.Run (); + prompt.GetCheckboxState (aCheckState); + + return NS_OK; +} + +/* boolean confirm (in nsIDOMWindow aParent, in wstring aDialogTitle, in wstring aText); */ +NS_IMETHODIMP +EphyPromptService::Confirm (nsIDOMWindow *aParent, + const PRUnichar *aDialogTitle, + const PRUnichar *aText, + PRBool *_retval) +{ + NS_ENSURE_ARG_POINTER (_retval); + + Prompter prompt (GTK_STOCK_DIALOG_QUESTION, aParent, aDialogTitle, aText); + prompt.AddStockButton (GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); + prompt.AddStockButton (GTK_STOCK_OK, GTK_RESPONSE_ACCEPT); + prompt.Run (_retval); + + return NS_OK; +} + +/* boolean confirmCheck (in nsIDOMWindow aParent, in wstring aDialogTitle, in wstring aText, in wstring aCheckMsg, inout boolean aCheckState); */ +NS_IMETHODIMP +EphyPromptService::ConfirmCheck (nsIDOMWindow *aParent, + const PRUnichar *aDialogTitle, + const PRUnichar *aText, + const PRUnichar *aCheckMsg, + PRBool *aCheckState, + PRBool *_retval) +{ + NS_ENSURE_ARG_POINTER (_retval); + + Prompter prompt (GTK_STOCK_DIALOG_QUESTION, aParent, aDialogTitle, aText); + prompt.AddStockButton (GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); + prompt.AddStockButton (GTK_STOCK_OK, GTK_RESPONSE_ACCEPT); + prompt.AddCheckbox (aCheckMsg, aCheckState); + + prompt.Run (_retval); + prompt.GetCheckboxState (aCheckState); + + return NS_OK; +} + +/* PRInt32 confirmEx (in nsIDOMWindow aParent, in wstring aDialogTitle, in wstring aText, in unsigned long aButtonFlags, in wstring aButton0Title, in wstring aButton1Title, in wstring aButton2Title, in wstring aCheckMsg, inout boolean aCheckState); */ +NS_IMETHODIMP +EphyPromptService::ConfirmEx (nsIDOMWindow *aParent, + const PRUnichar *aDialogTitle, + const PRUnichar *aText, + PRUint32 aButtonFlags, + const PRUnichar *aButton0Title, + const PRUnichar *aButton1Title, + const PRUnichar *aButton2Title, + const PRUnichar *aCheckMsg, + PRBool *aCheckState, + PRInt32 *_retval) +{ + NS_ENSURE_ARG_POINTER (_retval); + + Prompter prompt (GTK_STOCK_DIALOG_QUESTION, aParent, aDialogTitle, aText); + prompt.AddButtonsWithFlags (aButtonFlags, aButton0Title, + aButton1Title, aButton2Title); + prompt.AddCheckbox (aCheckMsg, aCheckState); + + *_retval = prompt.Run (nsnull); + prompt.GetCheckboxState (aCheckState); + + return NS_OK; +} + +/* boolean prompt (in nsIDOMWindow aParent, in wstring aDialogTitle, in wstring aText, inout wstring aValue, in wstring aCheckMsg, inout boolean aCheckState); */ +NS_IMETHODIMP +EphyPromptService::Prompt (nsIDOMWindow *aParent, + const PRUnichar *aDialogTitle, + const PRUnichar *aText, + PRUnichar **aValue, + const PRUnichar *aCheckMsg, + PRBool *aCheckState, + PRBool *_retval) +{ + NS_ENSURE_ARG_POINTER (_retval); + NS_ENSURE_ARG_POINTER (aValue); + + Prompter prompt (GTK_STOCK_DIALOG_QUESTION, aParent, aDialogTitle, aText); + prompt.AddStockButton (GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); + prompt.AddStockButton (GTK_STOCK_OK, GTK_RESPONSE_ACCEPT); + prompt.AddEntry (nsnull, *aValue, PR_FALSE); + prompt.AddCheckbox (aCheckMsg, aCheckState); + + prompt.Run (_retval); + prompt.GetText (0, aValue); + prompt.GetCheckboxState (aCheckState); + + return NS_OK; +} + +/* boolean promptUsernameAndPassword (in nsIDOMWindow aParent, in wstring aDialogTitle, in wstring aText, inout wstring aUsername, inout wstring aPassword, in wstring aCheckMsg, inout boolean aCheckState); */ +NS_IMETHODIMP +EphyPromptService::PromptUsernameAndPassword (nsIDOMWindow *aParent, + const PRUnichar *aDialogTitle, + const PRUnichar *aText, + PRUnichar **aUsername, + PRUnichar **aPassword, + const PRUnichar *aCheckMsg, + PRBool *aCheckState, + PRBool *_retval) +{ + NS_ENSURE_ARG_POINTER (_retval); + NS_ENSURE_ARG_POINTER (aUsername); + NS_ENSURE_ARG_POINTER (aPassword); + + Prompter prompt (GTK_STOCK_DIALOG_AUTHENTICATION, aParent, aDialogTitle, aText); + prompt.AddStockButton (GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); + prompt.AddStockButton (GTK_STOCK_OK, GTK_RESPONSE_ACCEPT); + prompt.AddEntry (_("_Username:"), *aUsername, PR_FALSE); + prompt.AddEntry (_("_Password:"), *aPassword, PR_TRUE); + prompt.AddCheckbox (aCheckMsg, aCheckState); + + prompt.Run (_retval); + prompt.GetText (0, aUsername); + prompt.GetText (1, aPassword); + prompt.GetCheckboxState (aCheckState); + + return NS_OK; +} + +/* boolean promptPassword (in nsIDOMWindow aParent, in wstring aDialogTitle, in wstring aText, inout wstring aPassword, in wstring aCheckMsg, inout boolean aCheckState); */ +NS_IMETHODIMP +EphyPromptService::PromptPassword (nsIDOMWindow *aParent, + const PRUnichar *aDialogTitle, + const PRUnichar *aText, + PRUnichar **aPassword, + const PRUnichar *aCheckMsg, + PRBool *aCheckState, + PRBool *_retval) +{ + NS_ENSURE_ARG_POINTER (_retval); + NS_ENSURE_ARG_POINTER (aPassword); + + Prompter prompt (GTK_STOCK_DIALOG_AUTHENTICATION, aParent, aDialogTitle, aText); + prompt.AddStockButton (GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); + prompt.AddStockButton (GTK_STOCK_OK, GTK_RESPONSE_ACCEPT); + prompt.AddEntry (_("_Password:"), *aPassword, PR_TRUE); + prompt.AddCheckbox (aCheckMsg, aCheckState); + + // FIXME: Add a CAPSLOCK indicator? + + prompt.Run (_retval); + prompt.GetText (0, aPassword); + prompt.GetCheckboxState (aCheckState); + + return NS_OK; +} + +/* boolean select (in nsIDOMWindow aParent, in wstring aDialogTitle, in wstring aText, in PRUint32 aCount, [array, size_is (aCount)] in wstring aSelectList, out long aOutSelection); */ +NS_IMETHODIMP +EphyPromptService::Select (nsIDOMWindow *aParent, + const PRUnichar *aDialogTitle, + const PRUnichar *aText, + PRUint32 aCount, + const PRUnichar **aSelectList, + PRInt32 *aOutSelection, + PRBool *_retval) +{ + NS_ENSURE_ARG_POINTER (_retval); + NS_ENSURE_ARG_POINTER (aOutSelection); + + Prompter prompt (GTK_STOCK_DIALOG_QUESTION, aParent, aDialogTitle, aText); + prompt.AddStockButton (GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); + prompt.AddStockButton (GTK_STOCK_OK, GTK_RESPONSE_ACCEPT); + prompt.AddSelect (aCount, aSelectList, *aOutSelection); + + prompt.Run (_retval); + prompt.GetSelected (aOutSelection); + + return NS_OK; +} + +#if HAVE_NSINONBLOCKINGALERTSERVICE_H + +/* showNonBlockingAlert (in nsIDOMWindow aParent, in wstring aDialogTitle, in wstring aText); */ +NS_IMETHODIMP +EphyPromptService::ShowNonBlockingAlert (nsIDOMWindow *aParent, + const PRUnichar *aDialogTitle, + const PRUnichar *aText) +{ + Prompter *prompt = new Prompter (GTK_STOCK_DIALOG_INFO, aParent, aDialogTitle, aText); + if (!prompt) return NS_ERROR_OUT_OF_MEMORY; + + prompt->AddStockButton (GTK_STOCK_OK, GTK_RESPONSE_ACCEPT); + prompt->Show (); + + return NS_OK; +} + +#endif /* HAVE_NSINONBLOCKINGALERTSERVICE_H */ diff --git a/embed/xulrunner/embed/EphyPromptService.h b/embed/xulrunner/embed/EphyPromptService.h new file mode 100644 index 000000000..2416e5318 --- /dev/null +++ b/embed/xulrunner/embed/EphyPromptService.h @@ -0,0 +1,53 @@ +/* + * Copyright © 2005, 2006 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#ifndef EPHY_PROMPT_SERVICE_H +#define EPHY_PROMPT_SERVICE_H + +#include <nsIPromptService.h> + +#if HAVE_NSINONBLOCKINGALERTSERVICE_H +#include <nsINonBlockingAlertService.h> +#endif + +#define EPHY_PROMPT_SERVICE_IID \ +{ /* 6e8b90d4-78a6-41c5-98da-b1559a40d30d */ \ + 0x6e8b90d4, 0x78a6, 0x41c5, \ + { 0x98, 0xda, 0xb1, 0x55, 0x9a, 0x40, 0xd3, 0x0d } } + +#define EPHY_PROMPT_SERVICE_CLASSNAME "Epiphany Prompt Service" + +class EphyPromptService : public nsIPromptService +#if HAVE_NSINONBLOCKINGALERTSERVICE_H + , public nsINonBlockingAlertService +#endif +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIPROMPTSERVICE +#if HAVE_NSINONBLOCKINGALERTSERVICE_H + NS_DECL_NSINONBLOCKINGALERTSERVICE +#endif + + EphyPromptService(); + virtual ~EphyPromptService(); +}; + +#endif /* EPHY_PROMPT_SERVICE_H */ diff --git a/embed/xulrunner/embed/EphyRedirectChannel.cpp b/embed/xulrunner/embed/EphyRedirectChannel.cpp new file mode 100644 index 000000000..6e493bfad --- /dev/null +++ b/embed/xulrunner/embed/EphyRedirectChannel.cpp @@ -0,0 +1,32 @@ +/* + * Copyright © 2005 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#include "mozilla-config.h" +#include "config.h" + +#include "EphyRedirectChannel.h" + +NS_IMPL_ISUPPORTS2 (EphyWrappedChannel, nsIRequest, nsIChannel) + +NS_IMETHODIMP +EphyRedirectChannel::SetLoadFlags(nsLoadFlags aFlags) +{ + return mChannel->SetLoadFlags (aFlags | LOAD_REPLACE); +} diff --git a/embed/xulrunner/embed/EphyRedirectChannel.h b/embed/xulrunner/embed/EphyRedirectChannel.h new file mode 100644 index 000000000..bcec1f1e5 --- /dev/null +++ b/embed/xulrunner/embed/EphyRedirectChannel.h @@ -0,0 +1,50 @@ +/* + * Copyright © 2005 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#ifndef EPHY_REDIRECT_CHANNEL_H +#define EPHY_REDIRECT_CHANNEL_H + +#include <nsCOMPtr.h> +#include <nsIChannel.h> + +class EphyWrappedChannel : public nsIChannel +{ + public: + NS_DECL_ISUPPORTS + NS_FORWARD_NSIREQUEST (mChannel->) + NS_FORWARD_NSICHANNEL (mChannel->) + + EphyWrappedChannel (nsIChannel *aChannel) : mChannel (aChannel) { } + virtual ~EphyWrappedChannel () { } + + protected: + nsCOMPtr<nsIChannel> mChannel; +}; + +class EphyRedirectChannel : public EphyWrappedChannel +{ + public: + EphyRedirectChannel (nsIChannel *aChannel) : EphyWrappedChannel (aChannel) { } + virtual ~EphyRedirectChannel () { } + + NS_IMETHOD SetLoadFlags (nsLoadFlags aFlags); +}; + +#endif /* !EPHY_REDIRECT_CHANNEL_H */ diff --git a/embed/xulrunner/embed/EphySidebar.cpp b/embed/xulrunner/embed/EphySidebar.cpp new file mode 100644 index 000000000..94bd52b8a --- /dev/null +++ b/embed/xulrunner/embed/EphySidebar.cpp @@ -0,0 +1,168 @@ +/* + * Copyright © 2002 Philip Langdale + * Copyright © 2004 Crispin Flowerday + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#include "mozilla-config.h" +#include "config.h" + +#include <nsStringAPI.h> + +#include <nsICategoryManager.h> +#include <nsIScriptNameSpaceManager.h> +#include <nsMemory.h> +#include <nsServiceManagerUtils.h> +#include <nsXPCOMCID.h> + +#ifdef HAVE_GECKO_1_9 +#include <nsIClassInfoImpl.h> +#endif + +#include "ephy-debug.h" +#include "ephy-embed-shell.h" +#include "ephy-embed-single.h" + +#include "EphySidebar.h" + +NS_IMPL_ISUPPORTS1_CI(EphySidebar, nsISidebar) + +EphySidebar::EphySidebar() +{ +} + +EphySidebar::~EphySidebar() +{ +} + +/* void addPanel (in wstring aTitle, in string aContentURL, in string aCustomizeURL); */ +NS_IMETHODIMP +EphySidebar::AddPanel (const PRUnichar *aTitle, + const char *aContentURL, + const char *aCustomizeURL) +{ + NS_ENSURE_ARG (aTitle); + NS_ENSURE_ARG (aContentURL); + + nsCString title; + EphyEmbedSingle *single; + + /* FIXME: length-limit string */ + NS_UTF16ToCString (nsDependentString(aTitle), + NS_CSTRING_ENCODING_UTF8, title); + + LOG ("Adding sidebar, url=%s title=%s", aContentURL, title.get()); + + single = EPHY_EMBED_SINGLE (ephy_embed_shell_get_embed_single (embed_shell)); + + gboolean result = FALSE; + g_signal_emit_by_name (single, "add-sidebar", + aContentURL, title.get(), &result); + + return NS_OK; +} + +/* void addPersistentPanel (in wstring aTitle, in string aContentURL, in string aCustomizeURL); */ +NS_IMETHODIMP +EphySidebar::AddPersistentPanel (const PRUnichar *aTitle, + const char *aContentURL, + const char *aCustomizeURL) +{ + return AddPanel (aTitle, aContentURL, aCustomizeURL); +} + +/* void addSearchEngine (in string engineURL, in string iconURL, in wstring suggestedTitle, in wst +ring suggestedCategory); */ +NS_IMETHODIMP +EphySidebar::AddSearchEngine (const char *aEngineURL, + const char *aIconURL, + const PRUnichar *aSuggestedTitle, + const PRUnichar *aSuggestedCategory) +{ + NS_ENSURE_ARG (aSuggestedTitle); + NS_ENSURE_ARG (aIconURL); + NS_ENSURE_ARG (aEngineURL); + + nsCString title; + EphyEmbedSingle *single; + + /* FIXME: length-limit string */ + NS_UTF16ToCString (nsDependentString(aSuggestedTitle), + NS_CSTRING_ENCODING_UTF8, title); + + LOG ("Adding search engine, engineurl=%s iconurl=%s title=%s", aEngineURL, aIconURL, title.get()); + + single = EPHY_EMBED_SINGLE (ephy_embed_shell_get_embed_single (embed_shell)); + + gboolean result = FALSE; + g_signal_emit_by_name (single, "add-search-engine", + aEngineURL, aIconURL, title.get(), &result); + + return NS_OK; +} + +#ifdef HAVE_GECKO_1_9 + +/* void addMicrosummaryGenerator (in string generatorURL); */ +NS_IMETHODIMP +EphySidebar::AddMicrosummaryGenerator (const char *generatorURL) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +#endif /* HAVE_GECKO_1_9 */ + +/* static */ NS_METHOD +EphySidebar::Register (nsIComponentManager* aComponentManager, + nsIFile* aPath, + const char* aRegistryLocation, + const char* aComponentType, + const nsModuleComponentInfo* aInfo) +{ + nsresult rv; + nsCOMPtr<nsICategoryManager> catMan (do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv)); + NS_ENSURE_SUCCESS (rv, rv); + + rv = catMan->AddCategoryEntry (JAVASCRIPT_GLOBAL_PROPERTY_CATEGORY, + "sidebar", + NS_SIDEBAR_CONTRACTID, + PR_FALSE /* don't persist */, + PR_TRUE /* replace */, + nsnull); + NS_ENSURE_SUCCESS (rv, rv); + + return rv; +} + +/* static */ NS_METHOD +EphySidebar::Unregister (nsIComponentManager* aComponentManager, + nsIFile* aPath, + const char* aRegistryLocation, + const nsModuleComponentInfo* aInfo) +{ + nsresult rv; + nsCOMPtr<nsICategoryManager> catMan (do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv)); + NS_ENSURE_SUCCESS (rv, rv); + + rv = catMan->DeleteCategoryEntry (JAVASCRIPT_GLOBAL_PROPERTY_CATEGORY, + "sidebar", + PR_FALSE /* don't persist */); + NS_ENSURE_SUCCESS (rv, rv); + + return rv; +} diff --git a/embed/xulrunner/embed/EphySidebar.h b/embed/xulrunner/embed/EphySidebar.h new file mode 100644 index 000000000..37efa0bf8 --- /dev/null +++ b/embed/xulrunner/embed/EphySidebar.h @@ -0,0 +1,66 @@ +/* + * Copyright © 2002 Philip Langdale + * Copyright © 2004 Crispin Flowerday + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#ifndef EPHY_SIDEBAR_H +#define EPHY_SIDEBAR_H + +#include <nsISidebar.h> + +class nsIComponentManager; +class nsIFile; +struct nsModuleComponentInfo; + +#define EPHY_SIDEBAR_CLASSNAME \ + "Epiphany's Sidebar Implementation" + +#define EPHY_SIDEBAR_CID \ +{ /* {50f13159-f9b9-44b3-b18e-6ee5d85a202a} */ \ + 0x50f13159, \ + 0xf9b9, \ + 0x44b3, \ + {0xb1, 0x8e, 0x6e, 0xe5, 0xd8, 0x5a, 0x20, 0x2a} \ +} + +class EphySidebar : public nsISidebar +{ + public: + NS_DECL_ISUPPORTS + NS_DECL_NSISIDEBAR + + EphySidebar(); + + static NS_METHOD Register (nsIComponentManager* aComponentManager, + nsIFile* aPath, + const char* aRegistryLocation, + const char* aComponentType, + const nsModuleComponentInfo* aInfo); + + static NS_METHOD Unregister (nsIComponentManager* aComponentManager, + nsIFile* aPath, + const char* aRegistryLocation, + const nsModuleComponentInfo* aInfo); + + private: + ~EphySidebar(); +}; + +#endif /* ! EPHY_SIDEBAR_H */ + diff --git a/embed/xulrunner/embed/EphySingle.cpp b/embed/xulrunner/embed/EphySingle.cpp new file mode 100644 index 000000000..74eaf21d6 --- /dev/null +++ b/embed/xulrunner/embed/EphySingle.cpp @@ -0,0 +1,396 @@ +/* + * Copyright © 2003 Christian Persch + * Copyright © 2003 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#include "mozilla-config.h" +#include "config.h" + +#include <nsStringAPI.h> + +#include <nsICookie.h> +#include <nsICookie2.h> +#include <nsICookieManager.h> +#include <nsIHttpChannel.h> +#include <nsIObserverService.h> +#include <nsIPermission.h> +#include <nsIPermissionManager.h> +#include <nsIPropertyBag2.h> +#include <nsIServiceManager.h> +#include <nsIURI.h> +#include <nsServiceManagerUtils.h> +#include <nsWeakReference.h> + +#ifdef ALLOW_PRIVATE_API +#include <nsIIDNService.h> +#endif + +#include "ephy-debug.h" + +#include "EphySingle.h" + +NS_IMPL_ISUPPORTS1(EphySingle, nsIObserver) + +EphySingle::EphySingle() +: mOwner(nsnull) +, mIsOnline(PR_TRUE) /* nsIOService doesn't send an initial notification, assume we start on-line */ +{ + LOG ("EphySingle ctor"); +} + +nsresult +EphySingle::Init (EphyEmbedSingle *aOwner) +{ + mObserverService = do_GetService ("@mozilla.org/observer-service;1"); + NS_ENSURE_TRUE (mObserverService, NS_ERROR_FAILURE); + + nsresult rv; + rv = mObserverService->AddObserver (this, "cookie-changed", PR_FALSE); + rv |= mObserverService->AddObserver (this, "cookie-rejected", PR_FALSE); + rv |= mObserverService->AddObserver (this, "perm-changed", PR_FALSE); + rv |= mObserverService->AddObserver (this, "network:offline-status-changed", PR_FALSE); + rv |= mObserverService->AddObserver (this, "signonChanged", PR_FALSE); + rv |= mObserverService->AddObserver (this, "http-on-examine-response", PR_FALSE); + rv |= mObserverService->AddObserver (this, "http-on-modify-request", PR_FALSE); + NS_ENSURE_SUCCESS (rv, NS_ERROR_FAILURE); + + mOwner = aOwner; + + LOG ("EphySingle::Init"); + + return NS_OK; +} + +nsresult +EphySingle::Detach () +{ + LOG ("EphySingle::Detach"); + + if (mObserverService) + { + mObserverService->RemoveObserver (this, "cookie-changed"); + mObserverService->RemoveObserver (this, "cookie-rejected"); + mObserverService->RemoveObserver (this, "perm-changed"); + mObserverService->RemoveObserver (this, "signonChanged"); + mObserverService->RemoveObserver (this, "network:offline-status-changed"); + mObserverService->RemoveObserver (this, "http-on-examine-response"); + mObserverService->RemoveObserver (this, "http-on-modify-request"); + +#if 1 + /* HACK: Work around https://bugzilla.mozilla.org/show_bug.cgi?id=292699 */ + mObserverService->NotifyObservers(nsnull, "profile-change-net-teardown", nsnull); +#endif + } + + return NS_OK; +} + +EphySingle::~EphySingle() +{ + LOG ("EphySingle dtor"); + + mOwner = nsnull; +} + +nsresult +EphySingle::EmitCookieNotification (const char *name, + nsISupports *aSubject) +{ + LOG ("EmitCookieNotification %s", name); + + nsCOMPtr<nsICookie> cookie = do_QueryInterface (aSubject); + NS_ENSURE_TRUE (cookie, NS_ERROR_FAILURE); + + EphyCookie *info = mozilla_cookie_to_ephy_cookie (cookie); + + g_signal_emit_by_name (EPHY_COOKIE_MANAGER (mOwner), name, info); + + ephy_cookie_free (info); + + return NS_OK; +} + +nsresult +EphySingle::EmitPermissionNotification (const char *name, + nsISupports *aSubject) +{ + LOG ("EmitPermissionNotification %s", name); + + nsCOMPtr<nsIPermission> perm = do_QueryInterface (aSubject); + NS_ENSURE_TRUE (perm, NS_ERROR_FAILURE); + + EphyPermissionInfo *info = + mozilla_permission_to_ephy_permission (perm); + + g_signal_emit_by_name (EPHY_PERMISSION_MANAGER (mOwner), name, info); + + ephy_permission_info_free (info); + + return NS_OK; +} + +nsresult +EphySingle::ExamineCookies (nsISupports *aSubject) +{ + PRBool isBlockingCookiesChannel = PR_FALSE; + + nsCOMPtr<nsIPropertyBag2> props (do_QueryInterface(aSubject)); + if (props && + NS_SUCCEEDED (props->GetPropertyAsBool( + NS_LITERAL_STRING("epiphany-blocking-cookies"), + &isBlockingCookiesChannel)) && + isBlockingCookiesChannel) + { + nsCOMPtr<nsIHttpChannel> httpChannel (do_QueryInterface(aSubject)); + + if (httpChannel) + httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Cookie"), + EmptyCString(), PR_FALSE); + } + + return NS_OK; +} + +nsresult +EphySingle::ExamineResponse (nsISupports *aSubject) +{ + return ExamineCookies (aSubject); +} + +nsresult +EphySingle::ExamineRequest (nsISupports *aSubject) +{ + return ExamineCookies (aSubject); +} + +/* void observe (in nsISupports aSubject, in string aTopic, in wstring aData); */ +NS_IMETHODIMP EphySingle::Observe(nsISupports *aSubject, + const char *aTopic, + const PRUnichar *aData) +{ + nsresult rv = NS_OK; + + LOG ("EphySingle::Observe topic %s", aTopic); + + if (strcmp (aTopic, "http-on-examine-response") == 0) + { + rv = ExamineResponse (aSubject); + } + else if (strcmp (aTopic, "http-on-modify-request") == 0) + { + rv = ExamineRequest (aSubject); + } + else if (strcmp (aTopic, "cookie-changed") == 0) + { + /* "added" */ + if (aData[0] == 'a') + { + rv = EmitCookieNotification ("cookie-added", aSubject); + } + /* "deleted" */ + else if (aData[0] == 'd') + { + rv = EmitCookieNotification ("cookie-deleted", aSubject); + } + /* "changed" */ + else if (aData[0] == 'c' && aData[1] == 'h') + { + rv = EmitCookieNotification ("cookie-changed", aSubject); + } + /* "cleared" */ + else if (aData[0] == 'c' && aData[1] == 'l') + { + LOG ("EphySingle::cookie-changed::cleared"); + + g_signal_emit_by_name (EPHY_COOKIE_MANAGER (mOwner), "cookies-cleared"); + } + else + { + g_warning ("EphySingle unexpected data!\n"); + rv = NS_ERROR_FAILURE; + } + } + else if (strcmp (aTopic, "cookie-rejected") == 0) + { + LOG ("EphySingle::cookie-rejected"); + + nsCOMPtr<nsIURI> uri = do_QueryInterface (aSubject); + if (uri) + { + nsCString spec; + uri->GetSpec (spec); + + g_signal_emit_by_name (EPHY_COOKIE_MANAGER (mOwner), "cookie-rejected", spec.get()); + } + else + { + rv = NS_ERROR_FAILURE; + } + } + else if (strcmp (aTopic, "perm-changed") == 0) + { + /* "added" */ + if (aData[0] == 'a') + { + rv = EmitPermissionNotification ("permission-added", aSubject); + } + /* "deleted" */ + else if (aData[0] == 'd') + { + rv = EmitPermissionNotification ("permission-deleted", aSubject); + } + /* "changed" */ + else if (aData[0] == 'c' && aData[1] == 'h') + { + rv = EmitPermissionNotification ("permission-changed", aSubject); + } + /* "cleared" */ + else if (aData[0] == 'c' && aData[1] == 'l') + { + LOG ("EphySingle::perm-changed::cleared"); + + g_signal_emit_by_name (EPHY_PERMISSION_MANAGER (mOwner), "permissions-cleared"); + } + else + { + g_warning ("EphySingle unexpected data!\n"); + rv = NS_ERROR_FAILURE; + } + } + else if (strcmp (aTopic, "signonChanged") == 0) + { + /* aData can be PRUnichar[] "signons", "rejects", "nocaptures" and "nopreviews" */ + if (aData[0] == 's') + { + g_signal_emit_by_name (mOwner, "passwords-changed"); + } + } + else if (strcmp (aTopic, "network:offline-status-changed") == 0) + { + /* aData is either (PRUnichar[]) "offline" or "online" */ + mIsOnline = (aData && aData[0] == 'o' && aData[1] == 'n'); + + g_object_notify (G_OBJECT (mOwner), "network-status"); + } + else + { + g_warning ("EphySingle observed unknown topic '%s'!\n", aTopic); + rv = NS_ERROR_FAILURE; + } + + LOG ("EphySingle::Observe %s", NS_SUCCEEDED (rv) ? "success" : "FAILURE"); + + return rv; +} + +EphyCookie * +mozilla_cookie_to_ephy_cookie (nsICookie *cookie) +{ + EphyCookie *info; + + nsCString transfer; + + cookie->GetHost (transfer); + + nsCOMPtr<nsIIDNService> idnService + (do_GetService ("@mozilla.org/network/idn-service;1")); + NS_ENSURE_TRUE (idnService, nsnull); + + nsCString decoded; + /* ToUTF8 never fails, no need to check return value */ + idnService->ConvertACEtoUTF8 (transfer, decoded); + + info = ephy_cookie_new (); + info->domain = g_strdup (decoded.get()); + + cookie->GetName (transfer); + info->name = g_strdup (transfer.get()); + cookie->GetValue (transfer); + info->value = g_strdup (transfer.get()); + cookie->GetPath (transfer); + info->path = g_strdup (transfer.get()); + + PRBool isSecure; + cookie->GetIsSecure (&isSecure); + info->is_secure = isSecure != PR_FALSE; + + PRUint64 dateTime; + cookie->GetExpires (&dateTime); + info->expires = dateTime; + + nsCOMPtr<nsICookie2> cookie2 = do_QueryInterface (cookie); + NS_ENSURE_TRUE (cookie2, info); + + PRBool isSession; + cookie2->GetIsSession (&isSession); + info->is_session = isSession != PR_FALSE; + + if (!isSession) + { + PRInt64 expiry; + cookie2->GetExpiry (&expiry); + info->real_expires = expiry; + } + +#ifdef HAVE_GECKO_1_9 + PRBool isHttpOnly = PR_FALSE; + cookie2->GetIsHttpOnly (&isHttpOnly); + info->is_http_only = isHttpOnly != PR_FALSE; +#endif + + return info; +} + +EphyPermissionInfo * +mozilla_permission_to_ephy_permission (nsIPermission *perm) +{ + nsresult rv; + nsCString type; + rv = perm->GetType(type); + NS_ENSURE_SUCCESS (rv, NULL); + + PRUint32 cap; + perm->GetCapability(&cap); + EphyPermission permission; + switch (cap) + { + case nsIPermissionManager::ALLOW_ACTION: + permission = EPHY_PERMISSION_ALLOWED; + break; + case nsIPermissionManager::DENY_ACTION: + permission = EPHY_PERMISSION_DENIED; + break; + case nsIPermissionManager::UNKNOWN_ACTION: + default : + permission = EPHY_PERMISSION_DEFAULT; + break; + } + + nsCString host; + perm->GetHost(host); + + nsCOMPtr<nsIIDNService> idnService + (do_GetService ("@mozilla.org/network/idn-service;1")); + NS_ENSURE_TRUE (idnService, nsnull); + + nsCString decodedHost; + idnService->ConvertACEtoUTF8 (host, decodedHost); + + return ephy_permission_info_new (decodedHost.get(), type.get(), permission); +} diff --git a/embed/xulrunner/embed/EphySingle.h b/embed/xulrunner/embed/EphySingle.h new file mode 100644 index 000000000..f30d7340a --- /dev/null +++ b/embed/xulrunner/embed/EphySingle.h @@ -0,0 +1,67 @@ +/* + * Copyright © 2003 Christian Persch + * Copyright © 2003 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#ifndef EPHY_SINGLE_H +#define EPHY_SINGLE_H + +#include <nsCOMPtr.h> +#include <nsIObserver.h> +#include <nsIObserverService.h> + +#include "ephy-cookie-manager.h" +#include "ephy-embed-single.h" +#include "ephy-permission-manager.h" + +class nsICookie; +class nsIPermission; + +class EphySingle : public nsIObserver +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIOBSERVER + + EphySingle(); + virtual ~EphySingle(); + + nsresult Init (EphyEmbedSingle *aOwner); + nsresult Detach (); + + PRBool IsOnline() { return mIsOnline; } + +protected: + nsresult EmitCookieNotification (const char *name, nsISupports *aSubject); + nsresult EmitPermissionNotification (const char *name, nsISupports *aSubject); + nsresult ExamineResponse (nsISupports *aSubject); + nsresult ExamineRequest (nsISupports *aSubject); + nsresult ExamineCookies (nsISupports *aSubject); + +private: + nsCOMPtr<nsIObserverService> mObserverService; + EphyEmbedSingle *mOwner; + PRBool mIsOnline; +}; + +EphyCookie *mozilla_cookie_to_ephy_cookie (nsICookie *cookie); + +EphyPermissionInfo *mozilla_permission_to_ephy_permission (nsIPermission *perm); + +#endif diff --git a/embed/xulrunner/embed/EphyUtils.cpp b/embed/xulrunner/embed/EphyUtils.cpp new file mode 100644 index 000000000..3f1b23687 --- /dev/null +++ b/embed/xulrunner/embed/EphyUtils.cpp @@ -0,0 +1,218 @@ +/* + * Copyright © 2004 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#include "mozilla-config.h" +#include "config.h" + +#include <nsStringAPI.h> + +#include <gtkmozembed.h> +#include <nsCOMPtr.h> +#include <nsIDOMWindow.h> +#include <nsIEmbeddingSiteWindow.h> +#include <nsIFile.h> +#include <nsIIOService.h> +#include <nsIServiceManager.h> +#include <nsIURI.h> +#include <nsIWebBrowserChrome.h> +#include <nsIWindowWatcher.h> +#include <nsIXPConnect.h> +#include <nsServiceManagerUtils.h> +#include <nsXPCOM.h> + +#ifdef HAVE_GECKO_1_9 +#include <nsPIDOMWindow.h> +#include <nsDOMJSUtils.h> /* for GetScriptContextFromJSContext */ +#include <nsIScriptContext.h> +#include <nsIScriptGlobalObject.h> +#endif + +#include "ephy-embed-shell.h" +#include "ephy-embed-single.h" +#include "ephy-file-helpers.h" + +#include "EphyUtils.h" + +nsresult +EphyUtils::GetIOService (nsIIOService **ioService) +{ + nsresult rv; + + nsCOMPtr<nsIServiceManager> mgr; + NS_GetServiceManager (getter_AddRefs (mgr)); + if (!mgr) return NS_ERROR_FAILURE; + + rv = mgr->GetServiceByContractID ("@mozilla.org/network/io-service;1", + NS_GET_IID (nsIIOService), + (void **)ioService); + return rv; +} + +nsresult +EphyUtils::NewURI (nsIURI **result, + const nsAString &spec, + const char *charset, + nsIURI *baseURI) +{ + nsCString cSpec; + NS_UTF16ToCString (spec, NS_CSTRING_ENCODING_UTF8, cSpec); + + return NewURI (result, cSpec, charset, baseURI); +} + +nsresult +EphyUtils::NewURI (nsIURI **result, + const nsACString &spec, + const char *charset, + nsIURI *baseURI) +{ + nsresult rv; + nsCOMPtr<nsIIOService> ioService; + rv = EphyUtils::GetIOService (getter_AddRefs (ioService)); + NS_ENSURE_SUCCESS (rv, rv); + + return ioService->NewURI (spec, charset, baseURI, result); +} + +nsresult +EphyUtils::NewFileURI (nsIURI **result, + nsIFile *spec) +{ + nsresult rv; + nsCOMPtr<nsIIOService> ioService; + rv = EphyUtils::GetIOService (getter_AddRefs (ioService)); + NS_ENSURE_SUCCESS (rv, rv); + + return ioService->NewFileURI (spec, result); +} + +GtkWidget * +EphyUtils::FindEmbed (nsIDOMWindow *aDOMWindow) +{ + if (!aDOMWindow) return nsnull; + + nsCOMPtr<nsIWindowWatcher> wwatch + (do_GetService("@mozilla.org/embedcomp/window-watcher;1")); + NS_ENSURE_TRUE (wwatch, nsnull); + + /* this DOM window may belong to some inner frame, we need + * to get the topmost DOM window to get the embed + */ + nsCOMPtr<nsIDOMWindow> topWindow; + aDOMWindow->GetTop (getter_AddRefs (topWindow)); + if (!topWindow) return nsnull; + + nsCOMPtr<nsIWebBrowserChrome> windowChrome; + wwatch->GetChromeForWindow (topWindow, getter_AddRefs(windowChrome)); + NS_ENSURE_TRUE (windowChrome, nsnull); + + nsCOMPtr<nsIEmbeddingSiteWindow> window (do_QueryInterface(windowChrome)); + NS_ENSURE_TRUE (window, nsnull); + + nsresult rv; + GtkWidget *mozembed; + rv = window->GetSiteWindow ((void **)&mozembed); + NS_ENSURE_SUCCESS (rv, nsnull); + + return mozembed; +} + +GtkWidget * +EphyUtils::FindGtkParent (nsIDOMWindow *aDOMWindow) +{ + GtkWidget *embed = FindEmbed (aDOMWindow); + if (!embed) return nsnull; + + GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (embed)); + if (!GTK_WIDGET_TOPLEVEL (toplevel)) return nsnull; + + return toplevel; +} + +char * +EphyUtils::ConvertUTF16toUTF8 (const PRUnichar *aText, + PRInt32 aMaxLength) +{ + if (aText == nsnull) return NULL; + + /* This depends on the assumption that + * typeof(PRUnichar) == typeof (gunichar2) == uint16, + * which should be pretty safe. + */ + glong n_read = 0, n_written = 0; + char *converted = g_utf16_to_utf8 ((gunichar2*) aText, aMaxLength, + &n_read, &n_written, NULL); + /* FIXME loop from the end while !g_unichar_isspace (char)? */ + + return converted; +} + +/* This isn't completely accurate: if you do window.prompt in one window, then + * call this in another window, it still returns TRUE ! Those are the wonders + * of recursive mainloops :-( + */ +PRBool +EphyJSUtils::IsCalledFromScript () +{ + nsresult rv; + nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(), &rv)); + NS_ENSURE_SUCCESS (rv, PR_FALSE); + + nsCOMPtr<nsIXPCNativeCallContext> ncc; + rv = xpc->GetCurrentNativeCallContext (getter_AddRefs (ncc)); + NS_ENSURE_SUCCESS(rv, PR_FALSE); + + return nsnull != ncc; +} + +/* NOTE: Only call this when we're SURE that we're called directly from JS! */ +nsIDOMWindow * +EphyJSUtils::GetDOMWindowFromCallContext () +{ + /* TODO: We can do this on 1.8 too, but we'd need to use headers which include private string API + * so we'll have to move this to MozillaPrivate + */ +#ifdef HAVE_GECKO_1_9 + nsresult rv; + nsCOMPtr<nsIXPConnect> xpc (do_GetService(nsIXPConnect::GetCID(), &rv)); + NS_ENSURE_SUCCESS (rv, nsnull); + + nsCOMPtr<nsIXPCNativeCallContext> ncc; + rv = xpc->GetCurrentNativeCallContext (getter_AddRefs (ncc)); + NS_ENSURE_SUCCESS (rv, nsnull); + + JSContext *cx = nsnull; + rv = ncc->GetJSContext(&cx); + NS_ENSURE_TRUE (NS_SUCCEEDED (rv) && cx, nsnull); + + nsIScriptContext* scriptContext = GetScriptContextFromJSContext (cx); + if (!scriptContext) return nsnull; + + nsIScriptGlobalObject *globalObject = scriptContext->GetGlobalObject(); + if (!globalObject) return nsnull; + + nsCOMPtr<nsPIDOMWindow> piWindow (do_QueryInterface (globalObject)); + if (!piWindow) return nsnull; + + return piWindow->GetOuterWindow (); +#else + return nsnull; +#endif +} diff --git a/embed/xulrunner/embed/EphyUtils.h b/embed/xulrunner/embed/EphyUtils.h new file mode 100644 index 000000000..9d69fbb27 --- /dev/null +++ b/embed/xulrunner/embed/EphyUtils.h @@ -0,0 +1,71 @@ +/* + * Copyright © 2004 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#ifndef EPHY_UTILS_H +#define EPHY_UTILS_H + +// cannot include EphyUtils with internal strings! +#ifdef MOZILLA_INTERNAL_API +#error Cannot use EphyUtils with MOZILLA_INTERNAL_API +#endif + +#include <nscore.h> + +#include <gtk/gtkwidget.h> + +class nsACString; +class nsAString; +class nsIDOMWindow; +class nsIFile; +class nsIIOService; +class nsIURI; + +namespace EphyUtils +{ + nsresult GetIOService (nsIIOService **ioService); + + nsresult NewURI (nsIURI **result, + const nsAString &spec, + const char *charset = nsnull, + nsIURI *baseURI = nsnull); + + nsresult NewURI (nsIURI **result, + const nsACString &spec, + const char *charset = nsnull, + nsIURI *baseURI = nsnull); + + nsresult NewFileURI (nsIURI **result, + nsIFile *spec); + + GtkWidget *FindEmbed (nsIDOMWindow *aDOMWindow); + + GtkWidget *FindGtkParent (nsIDOMWindow *aDOMWindow); + + char * ConvertUTF16toUTF8 (const PRUnichar*, PRInt32); +} + +namespace EphyJSUtils +{ + PRBool IsCalledFromScript (); + + /* not addref'd! */ nsIDOMWindow* GetDOMWindowFromCallContext (); +} + +#endif diff --git a/embed/xulrunner/embed/EventContext.cpp b/embed/xulrunner/embed/EventContext.cpp new file mode 100644 index 000000000..6e22fce8a --- /dev/null +++ b/embed/xulrunner/embed/EventContext.cpp @@ -0,0 +1,1105 @@ +/* + * Copyright © 2000-2004 Marco Pesenti Gritti + * Copyright © 2003, 2004 Christian Persch + * Copyright © 2004 Crispin Flowerday + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#include "mozilla-config.h" +#include "config.h" + +#include <gdk/gdkkeysyms.h> + +#include <nsStringAPI.h> + +#include <nsComponentManagerUtils.h> +#include <nsIDOM3Node.h> +#include <nsIDOMAbstractView.h> +#include <nsIDOMCharacterData.h> +#include <nsIDOMCSSPrimitiveValue.h> +#include <nsIDOMCSSStyleDeclaration.h> +#include <nsIDOMDocument.h> +#include <nsIDOMDocumentView.h> +#include <nsIDOMElementCSSInlineStyle.h> +#include <nsIDOMElement.h> +#include <nsIDOMEvent.h> +#include <nsIDOMEventTarget.h> +#include <nsIDOMEventTarget.h> +#include <nsIDOMHTMLAnchorElement.h> +#include <nsIDOMHTMLAreaElement.h> +#include <nsIDOMHTMLBodyElement.h> +#include <nsIDOMHTMLButtonElement.h> +#include <nsIDOMHTMLEmbedElement.h> +#include <nsIDOMHTMLImageElement.h> +#include <nsIDOMHTMLInputElement.h> +#include <nsIDOMHTMLIsIndexElement.h> +#include <nsIDOMHTMLLabelElement.h> +#include <nsIDOMHTMLLegendElement.h> +#include <nsIDOMHTMLMapElement.h> +#include <nsIDOMHTMLObjectElement.h> +#include <nsIDOMHTMLSelectElement.h> +#include <nsIDOMHTMLTextAreaElement.h> +#include <nsIDOMKeyEvent.h> +#include <nsIDOMMouseEvent.h> +#include <nsIDOMNode.h> +#include <nsIDOMNodeList.h> +#include <nsIDOMNSHTMLDocument.h> +#include <nsIDOMNSUIEvent.h> +#include <nsIInterfaceRequestor.h> +#include <nsIInterfaceRequestorUtils.h> +#include <nsIServiceManager.h> +#include <nsIURI.h> + +#ifdef ALLOW_PRIVATE_API +#include <nsIDOMNSEvent.h> +#include <nsIDOMNSHTMLElement.h> +#include <nsIDOMViewCSS.h> +#include <nsIDOMViewCSS.h> +#include <nsIDOMXULDocument.h> +#include <nsITextToSubURI.h> +#endif + +#include "ephy-debug.h" + +#include "EphyBrowser.h" +#include "EphyUtils.h" + +#include "EventContext.h" + + +#define KEY_CODE 256 + +EventContext::EventContext () +{ + LOG ("EventContext ctor [%p]", this); +} + +EventContext::~EventContext () +{ + LOG ("EventContext dtor [%p]", this); +} + +nsresult EventContext::Init (EphyBrowser *browser) +{ + mBrowser = browser; + mDOMDocument = nsnull; + + return NS_OK; +} + +nsresult EventContext::GatherTextUnder (nsIDOMNode* aNode, nsAString& aResult) +{ + nsString text; + nsCOMPtr<nsIDOMNode> node; + aNode->GetFirstChild(getter_AddRefs(node)); + PRUint32 depth = 1; + + while (node && depth) + { + nsCOMPtr<nsIDOMCharacterData> charData(do_QueryInterface(node)); + PRUint16 nodeType; + + node->GetNodeType(&nodeType); + if (charData && nodeType == nsIDOMNode::TEXT_NODE) + { + /* Add this text to our collection. */ + text += ' '; + nsString data; + charData->GetData(data); + text += data; + } + else + { + nsCOMPtr<nsIDOMHTMLImageElement> img(do_QueryInterface(node)); + if (img) + { + nsString altText; + img->GetAlt(altText); + if (altText.Length()) + { + text = altText; + break; + } + } + } + + /* Find the next node to test. */ + PRBool hasChildNodes; + node->HasChildNodes(&hasChildNodes); + if (hasChildNodes) + { + nsCOMPtr<nsIDOMNode> temp = node; + temp->GetFirstChild(getter_AddRefs(node)); + depth++; + } + else + { + nsCOMPtr<nsIDOMNode> nextSibling; + node->GetNextSibling(getter_AddRefs(nextSibling)); + if (nextSibling) + { + node = nextSibling; + } + else + { + nsCOMPtr<nsIDOMNode> parentNode; + node->GetParentNode(getter_AddRefs(parentNode)); + if (!parentNode) + { + node = nsnull; + } + else + { + parentNode->GetNextSibling(getter_AddRefs(nextSibling)); + node = nextSibling; + depth--; + } + } + } + } + + /* FIXME we should trim spaces here */ + + aResult = text; + + return NS_OK; +} + +/* FIXME: we should resolve against the element's base, not the document's base */ +nsresult EventContext::ResolveBaseURL (const nsAString &relurl, nsACString &url) +{ + nsCString cRelURL; + NS_UTF16ToCString (relurl, NS_CSTRING_ENCODING_UTF8, cRelURL); + + return mBaseURI->Resolve (cRelURL, url); +} + +nsresult EventContext::Unescape (const nsACString &aEscaped, nsACString &aUnescaped) +{ + if (!aEscaped.Length()) return NS_ERROR_FAILURE; + + nsCOMPtr<nsITextToSubURI> escaper + (do_CreateInstance ("@mozilla.org/intl/texttosuburi;1")); + NS_ENSURE_TRUE (escaper, NS_ERROR_FAILURE); + + nsresult rv; + nsCString encoding; + rv = mBrowser->GetEncoding (encoding); + NS_ENSURE_SUCCESS (rv, NS_ERROR_FAILURE); + + nsString unescaped; + rv = escaper->UnEscapeURIForUI (encoding, aEscaped, unescaped); + NS_ENSURE_TRUE (NS_SUCCEEDED (rv) && unescaped.Length(), NS_ERROR_FAILURE); + + NS_UTF16ToCString (unescaped, NS_CSTRING_ENCODING_UTF8, aUnescaped); + + return NS_OK; +} + +nsresult EventContext::GetEventContext (nsIDOMEventTarget *EventTarget, + MozillaEmbedEvent *info) +{ + nsresult rv; + + const PRUnichar hrefLiteral[] = {'h', 'r', 'e', 'f', '\0'}; + const PRUnichar imgLiteral[] = {'i', 'm', 'g', '\0'}; + const PRUnichar typeLiteral[] = {'t', 'y', 'p', 'e', '\0'}; + const PRUnichar xlinknsLiteral[] = {'h', 't', 't', 'p', ':', '/', '/','w', + 'w', 'w', '.', 'w', '3', '.', 'o', 'r', + 'g', '/', '1', '9', '9', '9', '/', 'x', + 'l', 'i', 'n', 'k', '\0'}; + const PRUnichar bodyLiteral[] = { 'b', 'o', 'd', 'y', '\0' }; + + mEmbedEvent = info; + + info->context = EPHY_EMBED_CONTEXT_DOCUMENT; + + nsCOMPtr<nsIDOMNode> node = do_QueryInterface(EventTarget, &rv); + if (NS_FAILED(rv) || !node) return NS_ERROR_FAILURE; + + /* Is page xul ? then do not display context menus + * FIXME I guess there is an easier way ... */ + /* From philipl: This test needs to be here otherwise we + * arrogantly assume we can QI to a HTMLElement, which is + * not true for xul content. */ + + nsCOMPtr<nsIDOMDocument> domDoc; + rv = node->GetOwnerDocument(getter_AddRefs(domDoc)); + if (NS_FAILED(rv) || !domDoc) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIDOMXULDocument> xul_document = do_QueryInterface(domDoc); + if (xul_document) + { + info->context = EPHY_EMBED_CONTEXT_NONE; + return NS_ERROR_FAILURE; + } + + mDOMDocument = domDoc; + + rv = mBrowser->GetEncoding (mCharset); + NS_ENSURE_SUCCESS (rv, rv); + + /* Get base URI and CSS view */ + nsCOMPtr<nsIDOMDocumentView> docView (do_QueryInterface (domDoc)); + NS_ENSURE_TRUE (docView, NS_ERROR_FAILURE); + + nsCOMPtr<nsIDOMAbstractView> abstractView; + docView->GetDefaultView (getter_AddRefs (abstractView)); + NS_ENSURE_TRUE (abstractView, NS_ERROR_FAILURE); + /* the abstract view is really the DOM window */ + + mViewCSS = do_QueryInterface (abstractView); + NS_ENSURE_TRUE (mViewCSS, NS_ERROR_FAILURE); + + nsCOMPtr<nsIWebNavigation> webNav (do_GetInterface (abstractView, &rv)); + NS_ENSURE_SUCCESS (rv, rv); + + rv = webNav->GetCurrentURI (getter_AddRefs (mBaseURI)); + NS_ENSURE_SUCCESS (rv, rv); + + // 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; + + PRBool has_image = PR_FALSE; + + nsCOMPtr<nsIDOMHTMLElement> element = do_QueryInterface(node); + if ((nsIDOMNode::ELEMENT_NODE == type) && element) + { + nsString uTag; + rv = element->GetLocalName(uTag); + if (NS_FAILED(rv)) return NS_ERROR_FAILURE; + + nsCString tag; + NS_UTF16ToCString (uTag, NS_CSTRING_ENCODING_UTF8, tag); + + if (g_ascii_strcasecmp (tag.get(), "img") == 0) + { + nsString img; + nsCOMPtr <nsIDOMHTMLImageElement> image = + do_QueryInterface(node, &rv); + if (NS_FAILED(rv) || !image) return NS_ERROR_FAILURE; + + rv = image->GetSrc (img); + if (NS_FAILED(rv)) return NS_ERROR_FAILURE; + + SetStringProperty ("image", img); + info->context |= EPHY_EMBED_CONTEXT_IMAGE; + has_image = PR_TRUE; + } + else if (g_ascii_strcasecmp (tag.get(), "area") == 0) + { + nsCOMPtr <nsIDOMHTMLAreaElement> area = + do_QueryInterface(node, &rv); + if (NS_FAILED(rv) || !area) return NS_ERROR_FAILURE; + + // Parent node is the map itself + nsCOMPtr<nsIDOMNode> parentNode; + node->GetParentNode (getter_AddRefs(parentNode)); + + nsCOMPtr <nsIDOMHTMLMapElement> map = + do_QueryInterface(parentNode, &rv); + if (NS_FAILED(rv) || !area) return NS_ERROR_FAILURE; + + nsString mapName; + rv = map->GetName (mapName); + if (NS_FAILED(rv)) return NS_ERROR_FAILURE; + + // Now we are searching for all the images with a usemap attribute + nsCOMPtr<nsIDOMNodeList> imgs; + rv = mDOMDocument->GetElementsByTagName (nsString(imgLiteral), + getter_AddRefs (imgs)); + if (NS_FAILED(rv)) return NS_ERROR_FAILURE; + + PRUint32 imgs_count; + rv = imgs->GetLength (&imgs_count); + if (NS_FAILED (rv)) return NS_ERROR_FAILURE; + + for (PRUint32 i = 0; i < imgs_count; i++) + { + nsCOMPtr<nsIDOMNode> aNode; + rv = imgs->Item (i, getter_AddRefs (aNode)); + if (NS_FAILED (rv)) continue; + + nsCOMPtr<nsIDOMHTMLImageElement> img = + do_QueryInterface(aNode, &rv); + if (NS_FAILED(rv) || !img) continue; + + nsString imgMapName; + rv = img->GetUseMap (imgMapName); + if (NS_FAILED (rv)) continue; + + // usemap always starts with # + imgMapName.Cut (0,1); + + // Check if the current image is attached to the map we are looking for + if (imgMapName.Equals(mapName)) + { + nsString imgSrc; + rv = img->GetSrc (imgSrc); + if (NS_FAILED(rv)) continue; + + SetStringProperty ("image", imgSrc); + info->context |= EPHY_EMBED_CONTEXT_IMAGE; + has_image = PR_TRUE; + + break; + } + } + } + else if (g_ascii_strcasecmp (tag.get(), "input") == 0) + { + CheckInput (node); + } + else if (g_ascii_strcasecmp (tag.get(), "textarea") == 0) + { + info->context |= EPHY_EMBED_CONTEXT_INPUT; + } + else if (g_ascii_strcasecmp (tag.get(), "object") == 0) + { + nsCOMPtr<nsIDOMHTMLObjectElement> object; + object = do_QueryInterface (node); + if (!element) return NS_ERROR_FAILURE; + + nsString value; + object->GetType(value); + + nsCString cValue; + NS_UTF16ToCString (value, NS_CSTRING_ENCODING_UTF8, cValue); + + // MIME types are always lower case + if (g_str_has_prefix (cValue.get(), "image/")) + { + nsString img; + + rv = object->GetData (img); + if (NS_FAILED(rv)) return NS_ERROR_FAILURE; + + nsCString cImg; + rv = ResolveBaseURL (img, cImg); + if (NS_FAILED (rv)) return NS_ERROR_FAILURE; + + SetStringProperty ("image", cImg.get()); + info->context |= EPHY_EMBED_CONTEXT_IMAGE; + has_image = PR_TRUE; + } + else + { + info->context = EPHY_EMBED_CONTEXT_NONE; + return NS_OK; + } + } + else if (g_ascii_strcasecmp (tag.get(), "html") == 0) + { + /* Clicked on part of the page without a <body>, so + * look for a background image in the body tag */ + nsCOMPtr<nsIDOMNodeList> nodeList; + + rv = mDOMDocument->GetElementsByTagName (nsString(bodyLiteral), + getter_AddRefs (nodeList)); + if (NS_SUCCEEDED (rv) && nodeList) + { + nsCOMPtr<nsIDOMNode> bodyNode; + nodeList->Item (0, getter_AddRefs (bodyNode)); + + nsString cssurl; + rv = GetCSSBackground (bodyNode, cssurl); + if (NS_SUCCEEDED (rv)) + { + nsCString bgimg; + rv = ResolveBaseURL (cssurl, bgimg); + if (NS_FAILED (rv)) + return NS_ERROR_FAILURE; + + SetStringProperty ("image", bgimg.get()); + info->context |= EPHY_EMBED_CONTEXT_IMAGE; + has_image = PR_TRUE; + } + } + } + } + + /* Is page framed ? */ + PRBool framed; + IsPageFramed (node, &framed); + SetIntProperty ("framed_page", framed); + + /* Bubble out, looking for items of interest */ + while (node) + { + nsCOMPtr <nsIDOMElement> dom_elem = do_QueryInterface(node); + if (dom_elem) + { + nsString value; + dom_elem->GetAttributeNS (nsString(xlinknsLiteral), + nsString(typeLiteral), value); + + nsCString cValue; + NS_UTF16ToCString (value, NS_CSTRING_ENCODING_UTF8, cValue); + + if (g_ascii_strcasecmp (cValue.get(), "simple") == 0) + { + info->context |= EPHY_EMBED_CONTEXT_LINK; + dom_elem->GetAttributeNS (nsString(xlinknsLiteral), + nsString(hrefLiteral), value); + + SetURIProperty (node, "link", value); + CheckLinkScheme (value); + } + } + + rv = node->GetNodeType(&type); + if (NS_FAILED(rv)) return NS_ERROR_FAILURE; + + element = do_QueryInterface(node); + if ((nsIDOMNode::ELEMENT_NODE == type) && element) + { + nsString uTag; + rv = element->GetLocalName(uTag); + if (NS_FAILED(rv)) return NS_ERROR_FAILURE; + + nsCString tag; + NS_UTF16ToCString (uTag, NS_CSTRING_ENCODING_UTF8, tag); + + /* Link */ + if (g_ascii_strcasecmp (tag.get(), "a") == 0) + { + nsString tmp; + + rv = GatherTextUnder (node, tmp); + if (NS_SUCCEEDED(rv)) + SetStringProperty ("linktext", tmp); + + nsCOMPtr <nsIDOMHTMLAnchorElement> anchor = + do_QueryInterface(node); + + nsCString href; + anchor->GetHref (tmp); + NS_UTF16ToCString (tmp, NS_CSTRING_ENCODING_UTF8, href); + + if (g_str_has_prefix (href.get(), "mailto:")) + { + /* cut "mailto:" */ + href.Cut (0, 7); + + char *str = g_strdup (href.get()); + g_strdelimit (str, "?", '\0'); + + nsCString unescapedHref; + rv = Unescape (nsCString(str), unescapedHref); + if (NS_SUCCEEDED (rv) && unescapedHref.Length()) + { + SetStringProperty ("email", unescapedHref.get()); + info->context |= EPHY_EMBED_CONTEXT_EMAIL_LINK; + } + g_free (str); + } + + if (anchor && tmp.Length()) + { + info->context |= EPHY_EMBED_CONTEXT_LINK; + + SetURIProperty (node, "link", tmp); + CheckLinkScheme (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); + + nsCString linkType; + NS_UTF16ToCString (tmp, NS_CSTRING_ENCODING_UTF8, linkType); + + if (g_ascii_strcasecmp (linkType.get(), "text/smartbookmark") == 0) + { + SetIntProperty ("link_is_smart", TRUE); + + nsCOMPtr<nsIDOMNode> childNode; + node->GetFirstChild (getter_AddRefs(childNode)); + if (childNode) + { + nsCOMPtr <nsIDOMHTMLImageElement> image = + do_QueryInterface(childNode, &rv); + + if (image) + { + nsString img; + rv = image->GetSrc (img); + if (!NS_FAILED(rv)) + { + SetStringProperty ("image", img); + } + } + } + } + else + { + SetIntProperty ("link_is_smart", FALSE); + } + } + + } + else if (g_ascii_strcasecmp (tag.get(), "option") == 0) + { + info->context = EPHY_EMBED_CONTEXT_NONE; + return NS_OK; + } + else if (g_ascii_strcasecmp (tag.get(), "area") == 0) + { + info->context |= EPHY_EMBED_CONTEXT_LINK; + nsCOMPtr <nsIDOMHTMLAreaElement> area = + do_QueryInterface(node, &rv); + if (NS_SUCCEEDED(rv) && area) + { + nsString href; + rv = area->GetHref (href); + if (NS_FAILED(rv)) + return NS_ERROR_FAILURE; + + SetURIProperty (node, "link", href); + CheckLinkScheme (href); + } + } + else if (g_ascii_strcasecmp (tag.get(), "input") == 0) + { + CheckInput (node); + } + else if (g_ascii_strcasecmp (tag.get(), "textarea") == 0) + { + info->context |= EPHY_EMBED_CONTEXT_INPUT; + } + + if (!has_image) + { + nsString cssurl; + rv = GetCSSBackground (node, cssurl); + if (NS_SUCCEEDED (rv)) + { + nsCString bgimg; + + rv = ResolveBaseURL (cssurl, bgimg); + if (NS_FAILED (rv)) + return NS_ERROR_FAILURE; + SetStringProperty ("image", bgimg.get()); + info->context |= EPHY_EMBED_CONTEXT_IMAGE; + has_image = PR_TRUE; + } + } + } + + nsCOMPtr<nsIDOMNode> parentNode; + node->GetParentNode (getter_AddRefs(parentNode)); + node = parentNode; + } + + return NS_OK; +} + +nsresult EventContext::GetCSSBackground (nsIDOMNode *node, nsAString& url) +{ + if (!mViewCSS) return NS_ERROR_NOT_INITIALIZED; + + nsresult rv; + + const PRUnichar bgimage[] = {'b', 'a', 'c', 'k', 'g', 'r', 'o', 'u', 'n', 'd', + '-', 'i', 'm', 'a', 'g', 'e', '\0'}; + + nsCOMPtr<nsIDOMElement> element = do_QueryInterface (node); + NS_ENSURE_TRUE (element, NS_ERROR_FAILURE); + + nsCOMPtr<nsIDOMCSSStyleDeclaration> decl; + mViewCSS->GetComputedStyle (element, nsString(), + getter_AddRefs (decl)); + NS_ENSURE_TRUE (decl, NS_ERROR_FAILURE); + + nsCOMPtr<nsIDOMCSSValue> CSSValue; + decl->GetPropertyCSSValue (nsString(bgimage), + getter_AddRefs (CSSValue)); + + nsCOMPtr<nsIDOMCSSPrimitiveValue> primitiveValue = + do_QueryInterface (CSSValue); + if (!primitiveValue) return NS_ERROR_FAILURE; + + PRUint16 type; + rv = primitiveValue->GetPrimitiveType (&type); + NS_ENSURE_SUCCESS (rv, NS_ERROR_FAILURE); + + if (type != nsIDOMCSSPrimitiveValue::CSS_URI) return NS_ERROR_FAILURE; + + rv = primitiveValue->GetStringValue (url); + NS_ENSURE_SUCCESS (rv, NS_ERROR_FAILURE); + + return NS_OK; +} + +nsresult EventContext::GetTargetCoords (nsIDOMEventTarget *aTarget, PRInt32 *aX, PRInt32 *aY) +{ + /* Calculate the node coordinates relative to the widget origin */ + nsCOMPtr<nsIDOMNSHTMLElement> elem (do_QueryInterface(aTarget)); + + PRInt32 x = 0, y = 0; + while (elem) + { + PRInt32 val; + elem->GetOffsetTop(&val); y += val; + elem->GetScrollTop(&val); y -= val; + elem->GetOffsetLeft(&val); x += val; + elem->GetScrollLeft(&val); x -= val; + + nsCOMPtr<nsIDOMElement> parent; + elem->GetOffsetParent (getter_AddRefs (parent)); + elem = do_QueryInterface(parent); + } + + *aX = x; + *aY = y; + + return NS_OK; +} + +nsresult EventContext::GetMouseEventInfo (nsIDOMMouseEvent *aMouseEvent, MozillaEmbedEvent *info) +{ + /* FIXME: casting 32-bit guint* to PRUint16* below will break on big-endian */ + PRUint16 btn = 1729; + aMouseEvent->GetButton (&btn); + + switch (btn) + { + /* mozilla's button counting is one-off from gtk+'s */ + case 0: + info->button = 1; + break; + case 1: + info->button = 2; + break; + case 2: + info->button = 3; + break; + + case (PRUint16) -1: + /* when the user submits a form with Return, mozilla synthesises + * a _mouse_ click event with btn=65535 (-1). + */ + default: + info->button = 0; + break; + } + + if (info->button != 0) + { + /* OTOH, casting only between (un)signedness is safe */ + aMouseEvent->GetScreenX ((PRInt32*)&info->x); + aMouseEvent->GetScreenY ((PRInt32*)&info->y); + } + else /* this is really a keyboard event */ + { + nsCOMPtr<nsIDOMEventTarget> eventTarget; + aMouseEvent->GetTarget (getter_AddRefs (eventTarget)); + + GetTargetCoords (eventTarget, (PRInt32*)&info->x, (PRInt32*)&info->y); + } + + /* be sure we are not clicking on the scroolbars */ + + nsCOMPtr<nsIDOMNSEvent> nsEvent = do_QueryInterface(aMouseEvent); + if (!nsEvent) return NS_ERROR_FAILURE; + +#ifdef MOZ_NSIDOMNSEVENT_GETISTRUSTED + /* make sure the event is trusted */ + PRBool isTrusted = PR_FALSE; + nsEvent->GetIsTrusted (&isTrusted); + if (!isTrusted) return NS_ERROR_UNEXPECTED; +#endif /* MOZ_NSIDOMNSEVENT_GETISTRUSTED */ + + nsresult rv; + nsCOMPtr<nsIDOMEventTarget> OriginalTarget; + rv = nsEvent->GetOriginalTarget(getter_AddRefs(OriginalTarget)); + if (NS_FAILED (rv) || !OriginalTarget) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIDOMNode> OriginalNode = do_QueryInterface(OriginalTarget); + if (!OriginalNode) return NS_ERROR_FAILURE; + + nsString nodename; + OriginalNode->GetNodeName(nodename); + nsCString cNodeName; + NS_UTF16ToCString (nodename, NS_CSTRING_ENCODING_UTF8, cNodeName); + + if (g_ascii_strcasecmp (cNodeName.get(), "xul:scrollbarbutton") == 0 || + g_ascii_strcasecmp (cNodeName.get(), "xul:thumb") == 0 || + g_ascii_strcasecmp (cNodeName.get(), "xul:vbox") == 0 || + g_ascii_strcasecmp (cNodeName.get(), "xul:spacer") == 0 || + g_ascii_strcasecmp (cNodeName.get(), "xul:slider") == 0) + return NS_ERROR_FAILURE; + + nsCOMPtr<nsIDOMEventTarget> EventTarget; + rv = aMouseEvent->GetTarget(getter_AddRefs(EventTarget)); + if (NS_FAILED (rv) || !EventTarget) return NS_ERROR_FAILURE; + + rv = GetEventContext (EventTarget, info); + if (NS_FAILED (rv)) return rv; + + /* 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; + + /* no need to check GetMetaKey, it's always PR_FALSE, + * see widget/src/gtk2/nsWindow.cpp:InitMouseEvent + */ + + aMouseEvent->GetCtrlKey(&mod_key); + if (mod_key) info->modifier |= GDK_CONTROL_MASK; + + return NS_OK; +} + +nsresult EventContext::GetKeyEventInfo (nsIDOMKeyEvent *aKeyEvent, MozillaEmbedEvent *info) +{ +#ifdef MOZ_NSIDOMNSEVENT_GETISTRUSTED + /* make sure the event is trusted */ + nsCOMPtr<nsIDOMNSEvent> nsEvent (do_QueryInterface (aKeyEvent)); + NS_ENSURE_TRUE (nsEvent, NS_ERROR_FAILURE); + + PRBool isTrusted = PR_FALSE; + nsEvent->GetIsTrusted (&isTrusted); + if (!isTrusted) return NS_ERROR_UNEXPECTED; +#endif /* MOZ_NSIDOMNSEVENT_GETISTRUSTED */ + + + info->button = 0; + + nsresult rv; + PRUint32 keyCode; + rv = aKeyEvent->GetKeyCode(&keyCode); + if (NS_FAILED(rv)) return rv; + info->keycode = keyCode; + + nsCOMPtr<nsIDOMEventTarget> target; + rv = aKeyEvent->GetTarget(getter_AddRefs(target)); + if (NS_FAILED(rv) || !target) return NS_ERROR_FAILURE; + + GetTargetCoords (target, (PRInt32*)&info->x, (PRInt32*)&info->y); + + /* Context */ + rv = GetEventContext (target, info); + if (NS_FAILED(rv)) return rv; + + /* Get the modifier */ + + PRBool mod_key; + + info->modifier = 0; + + aKeyEvent->GetAltKey(&mod_key); + if (mod_key) info->modifier |= GDK_MOD1_MASK; + + aKeyEvent->GetShiftKey(&mod_key); + if (mod_key) info->modifier |= GDK_SHIFT_MASK; + + aKeyEvent->GetMetaKey(&mod_key); + if (mod_key) info->modifier |= GDK_MOD2_MASK; + + aKeyEvent->GetCtrlKey(&mod_key); + if (mod_key) info->modifier |= GDK_CONTROL_MASK; + + return NS_OK; +} + +nsresult EventContext::IsPageFramed (nsIDOMNode *node, PRBool *Framed) +{ + nsresult rv; + + nsCOMPtr<nsIDOMDocument> mainDocument; + rv = mBrowser->GetDocument (getter_AddRefs(mainDocument)); + if (NS_FAILED (rv) || !mainDocument) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIDOMDocument> nodeDocument; + rv = node->GetOwnerDocument (getter_AddRefs(nodeDocument)); + if (NS_FAILED (rv) || !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::CheckInput (nsIDOMNode *aNode) +{ + const PRUnichar typeLiteral[] = { 't', 'y', 'p', 'e', '\0' }; + + nsCOMPtr<nsIDOMElement> element; + element = do_QueryInterface (aNode); + if (!element) return NS_ERROR_FAILURE; + + nsString uValue; + element->GetAttribute (nsString(typeLiteral), uValue); + + nsCString value; + NS_UTF16ToCString (uValue, NS_CSTRING_ENCODING_UTF8, value); + + if (g_ascii_strcasecmp (value.get(), "image") == 0) + { + mEmbedEvent->context |= EPHY_EMBED_CONTEXT_IMAGE; + nsCOMPtr<nsIDOMHTMLInputElement> input; + input = do_QueryInterface (aNode); + if (!input) return NS_ERROR_FAILURE; + + nsresult rv; + nsString img; + rv = input->GetSrc (img); + if (NS_FAILED(rv)) return NS_ERROR_FAILURE; + + nsCString cImg; + rv = ResolveBaseURL (img, cImg); + if (NS_FAILED(rv)) return NS_ERROR_FAILURE; + SetStringProperty ("image", cImg.get()); + } + else if (g_ascii_strcasecmp (value.get(), "radio") != 0 && + g_ascii_strcasecmp (value.get(), "submit") != 0 && + g_ascii_strcasecmp (value.get(), "reset") != 0 && + g_ascii_strcasecmp (value.get(), "hidden") != 0 && + g_ascii_strcasecmp (value.get(), "button") != 0 && + g_ascii_strcasecmp (value.get(), "checkbox") != 0) + { + mEmbedEvent->context |= EPHY_EMBED_CONTEXT_INPUT; + + if (g_ascii_strcasecmp (value.get(), "password") == 0) + { + mEmbedEvent->context |= EPHY_EMBED_CONTEXT_INPUT_PASSWORD; + } + } + + return NS_OK; +} + +nsresult EventContext::CheckLinkScheme (const nsAString &link) +{ + nsCOMPtr<nsIURI> uri; + EphyUtils::NewURI (getter_AddRefs (uri), link); + if (!uri) return NS_ERROR_FAILURE; + + nsresult rv; + nsCString scheme; + rv = uri->GetScheme (scheme); + if (NS_FAILED (rv)) return NS_ERROR_FAILURE; + + if (g_ascii_strcasecmp (scheme.get(), "http") == 0 || + g_ascii_strcasecmp (scheme.get(), "https") == 0 || + g_ascii_strcasecmp (scheme.get(), "ftp") == 0 || + g_ascii_strcasecmp (scheme.get(), "file") == 0 || + g_ascii_strcasecmp (scheme.get(), "smb") == 0 || + g_ascii_strcasecmp (scheme.get(), "sftp") == 0 || + g_ascii_strcasecmp (scheme.get(), "ssh") == 0 || + g_ascii_strcasecmp (scheme.get(), "data") == 0 || + g_ascii_strcasecmp (scheme.get(), "resource") == 0 || + g_ascii_strcasecmp (scheme.get(), "about") == 0 || + g_ascii_strcasecmp (scheme.get(), "gopher") == 0) + { + SetIntProperty ("link-has-web-scheme", TRUE); + } + + 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); + + mozilla_embed_event_set_property (mEmbedEvent, 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); + + mozilla_embed_event_set_property (mEmbedEvent, name, val); + + return NS_OK; +} + +nsresult EventContext::SetStringProperty (const char *name, const nsAString &value) +{ + nsCString cValue; + NS_UTF16ToCString (value, NS_CSTRING_ENCODING_UTF8, cValue); + return SetStringProperty (name, cValue.get()); +} + +nsresult EventContext::SetURIProperty (nsIDOMNode *node, const char *name, const nsACString &value) +{ + nsresult rv; + nsCOMPtr<nsIURI> uri; + rv = EphyUtils::NewURI (getter_AddRefs (uri), value, mCharset.Length () ? mCharset.get() : nsnull, mBaseURI); + if (NS_SUCCEEDED (rv) && uri) + { + /* Hide password part */ + nsCString user; + uri->GetUsername (user); + uri->SetUserPass (user); + + nsCString spec; + uri->GetSpec (spec); + rv = SetStringProperty (name, spec.get()); + } + else + { + rv = SetStringProperty (name, nsCString(value).get()); + } + + return rv; +} + +nsresult EventContext::SetURIProperty (nsIDOMNode *node, const char *name, const nsAString &value) +{ + nsCString cValue; + NS_UTF16ToCString (value, NS_CSTRING_ENCODING_UTF8, cValue); + return SetURIProperty (node, name, cValue); +} + +/* static */ +PRBool +EventContext::CheckKeyPress (nsIDOMKeyEvent *aEvent) +{ + PRBool retval = PR_FALSE; + + /* make sure the event is trusted */ + nsCOMPtr<nsIDOMNSEvent> nsEvent (do_QueryInterface (aEvent)); + NS_ENSURE_TRUE (nsEvent, retval); + PRBool isTrusted = PR_FALSE; + nsEvent->GetIsTrusted (&isTrusted); + if (!isTrusted) return retval; + + /* check for alt/ctrl */ + PRBool isCtrl = PR_FALSE, isAlt = PR_FALSE; + aEvent->GetCtrlKey (&isCtrl); + aEvent->GetAltKey (&isAlt); + if (isCtrl || isAlt) return retval; + + nsCOMPtr<nsIDOMNSUIEvent> uiEvent (do_QueryInterface (aEvent)); + NS_ENSURE_TRUE (uiEvent, retval); + + /* check for already handled event */ + PRBool isPrevented = PR_FALSE; + uiEvent->GetPreventDefault (&isPrevented); + if (isPrevented) return retval; + + /* check for form controls */ + nsresult rv; + nsCOMPtr<nsIDOMEventTarget> target; + rv = aEvent->GetTarget (getter_AddRefs (target)); + NS_ENSURE_SUCCESS (rv, retval); + + nsCOMPtr<nsIDOMHTMLInputElement> inputElement (do_QueryInterface (target)); + if (inputElement) + { + nsString type; + inputElement->GetType (type); + + nsCString (cType); + NS_UTF16ToCString (type, NS_CSTRING_ENCODING_UTF8, cType); + + if (g_ascii_strcasecmp (cType.get(), "text") == 0 || + g_ascii_strcasecmp (cType.get(), "password") == 0 || + g_ascii_strcasecmp (cType.get(), "file") == 0) return retval; + } + + nsCOMPtr<nsIDOMHTMLTextAreaElement> textArea; + nsCOMPtr<nsIDOMHTMLSelectElement> selectElement; + nsCOMPtr<nsIDOMHTMLIsIndexElement> indexElement; + nsCOMPtr<nsIDOMHTMLObjectElement> objectElement; + nsCOMPtr<nsIDOMHTMLEmbedElement> embedElement; + + if ((textArea = do_QueryInterface (target)) || + (selectElement = do_QueryInterface (target)) || + (indexElement = do_QueryInterface (target)) || + (objectElement = do_QueryInterface (target)) || + (embedElement = do_QueryInterface (target))) return retval; + + /* check for design mode */ + nsCOMPtr<nsIDOMNode> node (do_QueryInterface (target, &rv)); + NS_ENSURE_SUCCESS (rv, PR_FALSE); + + nsCOMPtr<nsIDOMDocument> doc; + rv = node->GetOwnerDocument (getter_AddRefs (doc)); + NS_ENSURE_SUCCESS (rv, retval); + + nsCOMPtr<nsIDOMXULDocument> xul_document (do_QueryInterface(doc, &rv)); + if (xul_document) return retval; + + nsCOMPtr<nsIDOMNSHTMLDocument> htmlDoc (do_QueryInterface (doc)); + if (htmlDoc) + { + nsString uDesign; + rv = htmlDoc->GetDesignMode (uDesign); + NS_ENSURE_SUCCESS (rv, retval); + + nsCString design; + NS_UTF16ToCString (uDesign, NS_CSTRING_ENCODING_UTF8, design); + + retval = g_ascii_strcasecmp (design.get(), "on") != 0; + } + else + { + retval = PR_TRUE; + } + + return retval; +} diff --git a/embed/xulrunner/embed/EventContext.h b/embed/xulrunner/embed/EventContext.h new file mode 100644 index 000000000..ddffcf1fc --- /dev/null +++ b/embed/xulrunner/embed/EventContext.h @@ -0,0 +1,78 @@ +/* + * Copyright © 2000-2004 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#ifndef EVENT_CONTEXT_H +#define EVENT_CONTEXT_H + +#include "ephy-embed.h" +#include "mozilla-embed-event.h" + +class EphyBrowser; +class nsIDOMDocument; +class nsIDOMEvent; +class nsIDOMEventTarget; +class nsIDOMHTMLAnchorElement; +class nsIDOMHTMLAreaElement; +class nsIDOMHTMLBodyElement; +class nsIDOMKeyEvent; +class nsIDOMMouseEvent; +class nsIDOMNode; +class nsIDOMViewCSS; +class nsIURI; + +class EventContext +{ +public: + EventContext(); + ~EventContext(); + + nsresult Init (EphyBrowser *wrapper); + nsresult GetMouseEventInfo (nsIDOMMouseEvent *event, MozillaEmbedEvent *info); + nsresult GetKeyEventInfo (nsIDOMKeyEvent *event, MozillaEmbedEvent *info); + nsresult GetTargetDocument (nsIDOMDocument **domDoc); + + static PRBool CheckKeyPress (nsIDOMKeyEvent *aEvent); + +private: + EphyBrowser *mBrowser; + MozillaEmbedEvent *mEmbedEvent; + nsCOMPtr<nsIDOMDocument> mDOMDocument; + nsCOMPtr<nsIDOMViewCSS> mViewCSS; + nsCOMPtr<nsIURI> mBaseURI; + nsCString mCharset; + + nsresult GetTargetCoords (nsIDOMEventTarget *aTarget, PRInt32 *aX, PRInt32 *aY); + nsresult GatherTextUnder (nsIDOMNode* aNode, nsAString& aResult); + nsresult ResolveBaseURL (const nsAString &relurl, nsACString &url); + nsresult Unescape (const nsACString &aEscaped, nsACString &aUnescaped); + nsresult GetEventContext (nsIDOMEventTarget *EventTarget, + MozillaEmbedEvent *info); + nsresult GetCSSBackground (nsIDOMNode *node, nsAString& url); + nsresult IsPageFramed (nsIDOMNode *node, PRBool *Framed); + nsresult CheckInput (nsIDOMNode *node); + nsresult CheckLinkScheme (const nsAString &link); + nsresult SetIntProperty (const char *name, int value); + nsresult SetStringProperty (const char *name, const char *value); + nsresult SetStringProperty (const char *name, const nsAString &value); + nsresult SetURIProperty (nsIDOMNode *node, const char *name, const nsAString &value); + nsresult SetURIProperty (nsIDOMNode *node, const char *name, const nsACString &value); +}; + +#endif diff --git a/embed/xulrunner/embed/FilePicker.cpp b/embed/xulrunner/embed/FilePicker.cpp new file mode 100644 index 000000000..78cc8f50d --- /dev/null +++ b/embed/xulrunner/embed/FilePicker.cpp @@ -0,0 +1,492 @@ +/* + * Copyright © 2001 Philip Langdale + * Copyright © 2003, 2004 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#include "mozilla-config.h" +#include "config.h" + +#include <glib/gconvert.h> +#include <glib/gi18n.h> +#include <gtk/gtkfilefilter.h> +#include <gtk/gtkmessagedialog.h> +#include <gtk/gtkstock.h> + +#include <nsStringAPI.h> + +#include <nsCOMPtr.h> +#include <nsIDOMWindow.h> +#include <nsIFileURL.h> +#include <nsILocalFile.h> +#include <nsIPromptService.h> +#include <nsIServiceManager.h> +#include <nsIURI.h> +#include <nsNetCID.h> + +#include "ephy-debug.h" +#include "ephy-gui.h" +#include "ephy-prefs.h" + +#include "AutoJSContextStack.h" +#include "AutoWindowModalState.h" +#include "EphyUtils.h" + +#include "FilePicker.h" + +NS_IMPL_ISUPPORTS1(GFilePicker, nsIFilePicker) + +GFilePicker::GFilePicker() +: mDialog(nsnull) +, mMode(nsIFilePicker::modeOpen) +{ + LOG ("GFilePicker ctor (%p)", this); +} + +GFilePicker::~GFilePicker() +{ + LOG ("GFilePicker dtor (%p)", this); + + if (mDialog) + { + g_object_remove_weak_pointer (G_OBJECT (mDialog), (gpointer *) &mDialog); + gtk_widget_destroy (GTK_WIDGET (mDialog)); + } +} + +/* void init (in nsIDOMWindow parent, in AString title, in short mode); */ +#ifdef MOZ_NSIFILEPICKER_NSASTRING_ +NS_IMETHODIMP GFilePicker::Init(nsIDOMWindow *parent, const nsAString& title, PRInt16 mode) +#else +NS_IMETHODIMP GFilePicker::Init(nsIDOMWindowInternal *parent, const PRUnichar *title, PRInt16 mode) +#endif +{ + LOG ("GFilePicker::Init"); + + mParent = do_QueryInterface (parent); + + GtkWidget *gtkparent = EphyUtils::FindGtkParent (parent); +#if defined(MOZ_NSIFILEPICKER_NSASTRING_) + NS_ENSURE_TRUE (gtkparent, NS_ERROR_FAILURE); +#endif + + nsCString cTitle; +#ifdef MOZ_NSIFILEPICKER_NSASTRING_ + NS_UTF16ToCString (title, NS_CSTRING_ENCODING_UTF8, cTitle); +#else + NS_UTF16ToCString (nsString(title), NS_CSTRING_ENCODING_UTF8, cTitle); +#endif + + mMode = mode; + + GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN; + switch (mode) + { + case nsIFilePicker::modeGetFolder: + action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER; + break; + case nsIFilePicker::modeOpenMultiple: + case nsIFilePicker::modeOpen: + action = GTK_FILE_CHOOSER_ACTION_OPEN; + break; + case nsIFilePicker::modeSave: + action = GTK_FILE_CHOOSER_ACTION_SAVE; + break; + default: + g_assert_not_reached (); + break; + } + + mDialog = ephy_file_chooser_new (cTitle.get(), gtkparent, action, + CONF_STATE_UPLOAD_DIR, + EPHY_FILE_FILTER_NONE); + + if (parent) + { + gtk_window_group_add_window (ephy_gui_ensure_window_group (GTK_WINDOW (gtkparent)), + GTK_WINDOW (mDialog)); + } + + if (mode == nsIFilePicker::modeOpenMultiple) + { + gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (mDialog), TRUE); + } + if (mMode == nsIFilePicker::modeSave) + { + gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (mDialog), TRUE); + } + + g_object_add_weak_pointer (G_OBJECT (mDialog), (gpointer *) &mDialog); + + return NS_OK; +} + +/* void appendFilters (in long filterMask); */ +NS_IMETHODIMP GFilePicker::AppendFilters(PRInt32 filterMask) +{ + NS_ENSURE_TRUE (mDialog, NS_ERROR_FAILURE); + + LOG ("GFilePicker::AppendFilters mask=%d", filterMask); + + // http://lxr.mozilla.org/seamonkey/source/xpfe/components/filepicker/res/locale/en-US/filepicker.properties + // http://lxr.mozilla.org/seamonkey/source/xpfe/components/filepicker/src/nsFilePicker.js line 131 ff + + if (filterMask & nsIFilePicker::filterAll) + { + ephy_file_chooser_add_pattern_filter (mDialog, _("All files"), + "*", (char*) NULL); + } + if (filterMask & nsIFilePicker::filterHTML) + { + ephy_file_chooser_add_mime_filter (mDialog, _("Web pages"), + "text/html", + "application/xhtml+xml", + "text/xml", + (char *) NULL); + } + if (filterMask & nsIFilePicker::filterText) + { + ephy_file_chooser_add_pattern_filter (mDialog, _("Text files"), + "*.txt", "*.text", NULL); + } + if (filterMask & nsIFilePicker::filterImages) + { + ephy_file_chooser_add_mime_filter (mDialog, _("Images"), + "image/png", + "image/jpeg", + "image/gif", + (char *) NULL); + } + if (filterMask & nsIFilePicker::filterXML) + { + ephy_file_chooser_add_pattern_filter (mDialog, _("XML files"), + "*.xml", (char *) NULL); + } + if (filterMask & nsIFilePicker::filterXUL) + { + ephy_file_chooser_add_pattern_filter (mDialog, _("XUL files"), + "*.xul", (char *) NULL); + } + + return NS_OK; +} + +/* void appendFilter (in AString title, in AString filter); */ +#ifdef MOZ_NSIFILEPICKER_NSASTRING_ +NS_IMETHODIMP GFilePicker::AppendFilter(const nsAString& title, const nsAString& filter) +#else +NS_IMETHODIMP GFilePicker::AppendFilter(const PRUnichar *title, const PRUnichar *filter) +#endif +{ + NS_ENSURE_TRUE (mDialog, NS_ERROR_FAILURE); + + LOG ("GFilePicker::AppendFilter"); + +#ifdef MOZ_NSIFILEPICKER_NSASTRING_ + if (!filter.Length()) return NS_ERROR_FAILURE; +#else + if (!filter) return NS_ERROR_FAILURE; +#endif + + nsCString pattern; +#ifdef MOZ_NSIFILEPICKER_NSASTRING_ + NS_UTF16ToCString (filter, NS_CSTRING_ENCODING_UTF8, pattern); +#else + NS_UTF16ToCString (nsString(filter), NS_CSTRING_ENCODING_UTF8, pattern); +#endif + + char **patterns; + patterns = g_strsplit (pattern.get(), ";", -1); + if (!patterns) return NS_ERROR_FAILURE; + + GtkFileFilter *filth; + filth = gtk_file_filter_new (); + + for (int i = 0; patterns[i] != NULL; i++) + { + gtk_file_filter_add_pattern (filth, g_strstrip (patterns[i])); + } + + nsCString cTitle; +#ifdef MOZ_NSIFILEPICKER_NSASTRING_ + NS_UTF16ToCString (title, NS_CSTRING_ENCODING_UTF8, cTitle); +#else + NS_UTF16ToCString (nsString(title), NS_CSTRING_ENCODING_UTF8, cTitle); +#endif + + gtk_file_filter_set_name (filth, cTitle.get()); + + gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (mDialog), filth); + + g_strfreev (patterns); + + return NS_OK; +} + +/* attribute AString defaultString; */ +#ifdef MOZ_NSIFILEPICKER_NSASTRING_ +NS_IMETHODIMP GFilePicker::GetDefaultString(nsAString& aDefaultString) +#else +NS_IMETHODIMP GFilePicker::GetDefaultString(PRUnichar **aDefaultString) +#endif +{ + NS_ENSURE_TRUE (mDialog, NS_ERROR_FAILURE); + + LOG ("GFilePicker::GetDefaultString"); + +#ifdef MOZ_NSIFILEPICKER_NSASTRING_ + aDefaultString = mDefaultString; +#else + *aDefaultString = NS_StringCloneData (mDefaultString); +#endif + + return NS_OK; +} + +#ifdef MOZ_NSIFILEPICKER_NSASTRING_ +NS_IMETHODIMP GFilePicker::SetDefaultString(const nsAString& aDefaultString) +#else +NS_IMETHODIMP GFilePicker::SetDefaultString(const PRUnichar *aDefaultString) +#endif +{ + NS_ENSURE_TRUE (mDialog, NS_ERROR_FAILURE); + + mDefaultString.Assign (aDefaultString); + + if (mMode == nsIFilePicker::modeSave) + { + nsCString defaultString; + NS_UTF16ToCString (mDefaultString, NS_CSTRING_ENCODING_UTF8, + defaultString); + + LOG ("GFilePicker::SetDefaultString %s", defaultString.get()); + + if (!defaultString.Length()) return NS_ERROR_FAILURE; + + /* set_current_name takes UTF-8, not a filename */ + gtk_file_chooser_set_current_name + (GTK_FILE_CHOOSER (mDialog), defaultString.get()); + } + + return NS_OK; +} + +/* attribute AString defaultExtension; */ +#ifdef MOZ_NSIFILEPICKER_NSASTRING_ +NS_IMETHODIMP GFilePicker::GetDefaultExtension(nsAString& aDefaultExtension) +#else +NS_IMETHODIMP GFilePicker::GetDefaultExtension(PRUnichar **aDefaultExtension) +#endif +{ + LOG ("GFilePicker::GetDefaultExtension"); + + return NS_ERROR_NOT_IMPLEMENTED; +} + +#ifdef MOZ_NSIFILEPICKER_NSASTRING_ +NS_IMETHODIMP GFilePicker::SetDefaultExtension(const nsAString& aDefaultExtension) +#else +NS_IMETHODIMP GFilePicker::SetDefaultExtension(const PRUnichar *aDefaultExtension) +#endif +{ + LOG ("GFilePicker::SetDefaultExtension"); + + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* attribute long filterIndex; */ +NS_IMETHODIMP GFilePicker::GetFilterIndex(PRInt32 *aFilterIndex) +{ + LOG ("GFilePicker::GetFilterIndex"); + + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP GFilePicker::SetFilterIndex(PRInt32 aFilterIndex) +{ + LOG ("GFilePicker::SetFilterIndex index=%d", aFilterIndex); + + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* attribute nsILocalFile displayDirectory; */ +NS_IMETHODIMP GFilePicker::GetDisplayDirectory(nsILocalFile **aDisplayDirectory) +{ + NS_ENSURE_TRUE (mDialog, NS_ERROR_FAILURE); + + LOG ("GFilePicker::GetDisplayDirectory"); + + char *dir = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (mDialog)); + + if (dir != NULL) + { + nsCOMPtr<nsILocalFile> file = do_CreateInstance (NS_LOCAL_FILE_CONTRACTID); + file->InitWithNativePath (nsCString (dir)); + NS_IF_ADDREF (*aDisplayDirectory = file); + + g_free (dir); + } + + return NS_OK; +} + +NS_IMETHODIMP GFilePicker::SetDisplayDirectory(nsILocalFile *aDisplayDirectory) +{ + NS_ENSURE_TRUE (mDialog, NS_ERROR_FAILURE); + + nsCString dir; + aDisplayDirectory->GetNativePath (dir); + + LOG ("GFilePicker::SetDisplayDirectory to %s", dir.get()); + + if (mDefaultString.Length() && mMode != nsIFilePicker::modeSave) + { + nsCString defaultString; + NS_UTF16ToCString (mDefaultString, NS_CSTRING_ENCODING_NATIVE_FILESYSTEM, + defaultString); + + char *filename = g_build_filename (dir.get(), defaultString.get(), (char *) NULL); + LOG ("Setting filename to %s", filename); + gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (mDialog), filename); + g_free (filename); + } + else + { + gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (mDialog), + dir.get()); + } + + return NS_OK; +} + +/* readonly attribute nsILocalFile file; */ +NS_IMETHODIMP GFilePicker::GetFile(nsILocalFile **aFile) +{ + NS_ENSURE_TRUE (mDialog, NS_ERROR_FAILURE); + + char *filename; + + LOG ("GFilePicker::GetFile"); + + filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (mDialog)); + + if (filename != NULL) + { + nsCOMPtr<nsILocalFile> file = do_CreateInstance (NS_LOCAL_FILE_CONTRACTID); + file->InitWithNativePath (nsCString (filename)); + NS_IF_ADDREF (*aFile = file); + + g_free (filename); + } + + return NS_OK; +} + +/* readonly attribute nsIFileURL fileURL; */ +NS_IMETHODIMP GFilePicker::GetFileURL(nsIFileURL **aFileURL) +{ + NS_ENSURE_TRUE (mDialog, NS_ERROR_FAILURE); + + LOG ("GFilePicker::GetFileURL"); + + nsCOMPtr<nsILocalFile> file; + GetFile (getter_AddRefs(file)); + NS_ENSURE_TRUE (file, NS_ERROR_FAILURE); + + nsCOMPtr<nsIFileURL> fileURL = do_CreateInstance (NS_STANDARDURL_CONTRACTID); + fileURL->SetFile(file); + NS_IF_ADDREF(*aFileURL = fileURL); + + return NS_OK; +} + +/* readonly attribute nsISimpleEnumerator files; */ +NS_IMETHODIMP GFilePicker::GetFiles(nsISimpleEnumerator * *aFiles) +{ + // Not sure if we need to implement it at all, it's used nowhere + // in mozilla, but I guess a javascript might call it? + + LOG ("GFilePicker::GetFiles"); + + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* short show (); */ +NS_IMETHODIMP GFilePicker::Show(PRInt16 *_retval) +{ + nsresult rv; + AutoJSContextStack stack; + rv = stack.Init (); + if (NS_FAILED (rv)) return rv; + + AutoWindowModalState (mParent); + mParent = nsnull; + + LOG ("GFilePicker::Show"); + + gtk_window_set_modal (GTK_WINDOW (mDialog), TRUE); + gtk_window_set_destroy_with_parent (GTK_WINDOW (mDialog), FALSE); + + /* If there's just the "ALL" filter, it's no use showing the filters! */ + GSList *filters = gtk_file_chooser_list_filters (GTK_FILE_CHOOSER (mDialog)); + if (g_slist_length (filters) == 1) + { + GtkFileFilter *filter = GTK_FILE_FILTER (filters->data); + const char *name = gtk_file_filter_get_name (filter); + + if (!name || strcmp (name, _("All files")) == 0) + { + gtk_file_chooser_remove_filter (GTK_FILE_CHOOSER (mDialog), + filter); + } + } + g_slist_free (filters); + + gtk_widget_show (GTK_WIDGET (mDialog)); + + int response; + char *filename = NULL; + + do + { + response = gtk_dialog_run (GTK_DIALOG (mDialog)); + + g_free (filename); + filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (mDialog)); + + LOG ("GFilePicker::Show response=%d, filename=%s", response, filename); + } + while (response == GTK_RESPONSE_ACCEPT && + mMode == nsIFilePicker::modeSave && + !ephy_gui_check_location_writable (GTK_WIDGET (mDialog), filename)); + + gtk_widget_hide (GTK_WIDGET (mDialog)); + + if (response == GTK_RESPONSE_ACCEPT && filename != NULL) + { + *_retval = nsIFilePicker::returnOK; + } + else + { + *_retval = nsIFilePicker::returnCancel; + } + + g_free (filename); + + return NS_OK; +} diff --git a/embed/xulrunner/embed/FilePicker.h b/embed/xulrunner/embed/FilePicker.h new file mode 100644 index 000000000..fa63c56b1 --- /dev/null +++ b/embed/xulrunner/embed/FilePicker.h @@ -0,0 +1,62 @@ +/* + * Copyright © 2001 Philip Langdale + * Copyright © 2003 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#ifndef EPHY_FILEPICKER_H +#define EPHY_FILEPICKER_H + +#include <nsIFilePicker.h> + +class nsIDOMWindow; + +#include "ephy-file-chooser.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 "Epiphany File Picker Implementation" + +class nsIFactory; + +extern nsresult NS_NewFilePickerFactory(nsIFactory** aFactory); + +class GFilePicker : public nsIFilePicker +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIFILEPICKER + + GFilePicker(); + virtual ~GFilePicker(); + +private: + EphyFileChooser *mDialog; + PRInt16 mMode; + nsString mDefaultString; + nsCOMPtr<nsIDOMWindow> mParent; +}; + +#endif diff --git a/embed/xulrunner/embed/GeckoCookiePromptService.cpp b/embed/xulrunner/embed/GeckoCookiePromptService.cpp new file mode 100644 index 000000000..fa33e8bfb --- /dev/null +++ b/embed/xulrunner/embed/GeckoCookiePromptService.cpp @@ -0,0 +1,159 @@ +/* + * Copyright © 2003 Tommi Komulainen <tommi.komulainen@iki.fi> + * Copyright © 2004, 2007 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public 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 "mozilla-config.h" +#include "config.h" + +#include <glib/gi18n.h> + +#include <gtk/gtkbox.h> +#include <gtk/gtkcheckbutton.h> +#include <gtk/gtkdialog.h> +#include <gtk/gtkmessagedialog.h> +#include <gtk/gtkstock.h> +#include <gtk/gtkwindow.h> + +#include <nsStringAPI.h> + +#include "ephy-debug.h" +#include "ephy-gui.h" + +#include "AutoJSContextStack.h" +#include "AutoWindowModalState.h" +#include "EphyUtils.h" + +#include "GeckoCookiePromptService.h" + +NS_IMPL_ISUPPORTS1 (GeckoCookiePromptService, nsICookiePromptService) + +GeckoCookiePromptService::GeckoCookiePromptService() +{ + LOG ("GeckoCookiePromptService ctor [%p]", this); +} + +GeckoCookiePromptService::~GeckoCookiePromptService() +{ + LOG ("GeckoCookiePromptService dtor [%p]", this); +} + +/* boolean cookieDialog (in nsIDOMWindow parent, in nsICookie cookie, in ACString hostname, in long cookiesFromHost, in boolean changingCookie, inout boolean checkValue); */ +NS_IMETHODIMP +GeckoCookiePromptService::CookieDialog (nsIDOMWindow *aParent, + nsICookie *aCookie, + const nsACString &aHostname, + PRInt32 aCookiesFromHost, + PRBool aChangingCookie, + PRBool *_checkValue, + PRBool *_retval) +{ + NS_ENSURE_ARG (aParent); + NS_ENSURE_ARG (aCookie); + NS_ENSURE_ARG_POINTER (_checkValue); + NS_ENSURE_ARG_POINTER (_retval); + + // TODO short-circuit and accept session cookies as per preference + // TODO until mozilla starts supporting it natively? + + GtkWidget *parent = EphyUtils::FindGtkParent (aParent); + NS_ENSURE_TRUE(parent, NS_ERROR_INVALID_POINTER); + + nsresult rv; + AutoJSContextStack stack; + rv = stack.Init (); + if (NS_FAILED (rv)) { + return rv; + } + + AutoWindowModalState modalState (aParent); + + nsCString host(aHostname); + + GtkWidget *dialog = gtk_message_dialog_new + (GTK_WINDOW (parent), + GTK_DIALOG_MODAL /* FIXME mozilla sucks! */, + GTK_MESSAGE_QUESTION, + GTK_BUTTONS_NONE, + _("Accept cookie from %s?"), + host.get()); + GtkWindow *window = GTK_WINDOW (dialog); + GtkDialog *gdialog = GTK_DIALOG (dialog); + GtkMessageDialog *message_dialog = GTK_MESSAGE_DIALOG (dialog); + + gtk_window_set_icon_name (window, "web-browser"); + gtk_window_set_title (window, _("Accept Cookie?")); + + if (aChangingCookie) { + gtk_message_dialog_format_secondary_text + (message_dialog, + _("The site wants to modify an existing cookie.")); + } else if (aCookiesFromHost == 0) { + gtk_message_dialog_format_secondary_text + (message_dialog, + _("The site wants to set a cookie.")); + } else if (aCookiesFromHost == 1) { + gtk_message_dialog_format_secondary_text + (message_dialog, + _("The site wants to set a second cookie.")); + } else { + char *num_text = g_strdup_printf + (ngettext ("You already have %d cookie from this site.", + "You already have %d cookies from this site.", + aCookiesFromHost), + aCookiesFromHost); + + gtk_message_dialog_format_secondary_text + (message_dialog, + "The site %s wants to set another cookie. %s", + host.get(), num_text); + g_free (num_text); + } + + GtkWidget *checkbutton; + checkbutton = gtk_check_button_new_with_mnemonic + (_("Apply this _decision to all cookies from this site")); + gtk_widget_show (checkbutton); + gtk_box_pack_start (GTK_BOX (ephy_gui_message_dialog_get_content_box (dialog)), + checkbutton, FALSE, FALSE, 0); + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbutton), *_checkValue); + + gtk_dialog_add_button (gdialog, + _("_Reject"), GTK_RESPONSE_REJECT); + gtk_dialog_add_button (gdialog, + _("_Accept"), GTK_RESPONSE_ACCEPT); + gtk_dialog_set_default_response (gdialog, GTK_RESPONSE_ACCEPT); + + int response = gtk_dialog_run (gdialog); + + if (response == GTK_RESPONSE_ACCEPT || response == GTK_RESPONSE_REJECT) { + *_retval = (response == GTK_RESPONSE_ACCEPT); + *_checkValue = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (checkbutton)); + } else { + /* if the dialog was closed, but no button was pressed, + * consider it as 'Reject' but ignore the checkbutton + */ + *_retval = PR_FALSE; + *_checkValue = PR_FALSE; + } + + gtk_widget_destroy (dialog); + + return NS_OK; +} diff --git a/embed/xulrunner/embed/GeckoCookiePromptService.h b/embed/xulrunner/embed/GeckoCookiePromptService.h new file mode 100644 index 000000000..7092a2982 --- /dev/null +++ b/embed/xulrunner/embed/GeckoCookiePromptService.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2003 Tommi Komulainen <tommi.komulainen@iki.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public 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 COOKIEPROMPTSERVICE_H +#define COOKIEPROMPTSERVICE_H + +#include <nsICookiePromptService.h> + +/* 50766a18-0b34-41d9-8f6c-4612200e6556 */ +#define EPHY_COOKIEPROMPTSERVICE_CID \ + { 0x50766a18, 0x0b34, 0x41d9, { 0x8f, 0x6c, 0x46, 0x12, 0x20, 0x0e, 0x65, 0x56 } } + +#define EPHY_COOKIEPROMPTSERVICE_CLASSNAME "Epiphany Cookie Prompt Service" +#define EPHY_COOKIEPROMPTSERVICE_CONTRACTID "@mozilla.org/embedcomp/cookieprompt-service;1" + +class GeckoCookiePromptService : public nsICookiePromptService { + public: + NS_DECL_ISUPPORTS + NS_DECL_NSICOOKIEPROMPTSERVICE + + GeckoCookiePromptService(); + + private: + ~GeckoCookiePromptService(); +}; + +#endif /* COOKIEPROMPTSERVICE_H */ diff --git a/embed/xulrunner/embed/GeckoFormSigningDialog.cpp b/embed/xulrunner/embed/GeckoFormSigningDialog.cpp new file mode 100644 index 000000000..309b3c11e --- /dev/null +++ b/embed/xulrunner/embed/GeckoFormSigningDialog.cpp @@ -0,0 +1,158 @@ +/* + * Copyright © 2006 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#include "mozilla-config.h" +#include "config.h" + +#include <glib.h> +#include <glib/gi18n.h> +#include <gtk/gtk.h> +#include <glade/glade-xml.h> + +#include <nsStringAPI.h> + +#include <nsCOMPtr.h> +#include <nsIDOMWindow.h> +#include <nsIInterfaceRequestor.h> +#include <nsIInterfaceRequestorUtils.h> + +#include "eel-gconf-extensions.h" +#include "ephy-debug.h" +#include "ephy-embed-shell.h" +#include "ephy-file-helpers.h" +#include "ephy-prefs.h" + +#include "AutoJSContextStack.h" +#include "AutoWindowModalState.h" +#include "EphyUtils.h" + +#include "GeckoFormSigningDialog.h" + +#define LITERAL(s) reinterpret_cast<const nsAString::char_type*>(NS_L(s)) + +NS_IMPL_ISUPPORTS1 (GeckoFormSigningDialog, + nsIFormSigningDialog) + +GeckoFormSigningDialog::GeckoFormSigningDialog() +{ + LOG ("GeckoFormSigningDialog ctor [%p]", this); +} + +GeckoFormSigningDialog::~GeckoFormSigningDialog() +{ + LOG ("GeckoFormSigningDialog dtor [%p]", this); +} + +/* nsIFormSigningDialog implementation */ + +/* boolean confirmSignText (in nsIInterfaceRequestor ctxt, + in AString host, + in AString signText, + [array, size_is (count)] in wstring certNickList, + [array, size_is (count)] in wstring certDetailsList, + in PRUint32 count, + out PRInt32 selectedIndex, + out AString password); */ +NS_IMETHODIMP +GeckoFormSigningDialog::ConfirmSignText (nsIInterfaceRequestor *ctx, + const nsAString & host, + const nsAString & signText, + const PRUnichar **certNickList, + const PRUnichar **certDetailsList, + PRUint32 count, + PRInt32 *selectedIndex, + nsAString &_password, + PRBool *_cancelled) +{ + /* FIXME: limit |signText| to a sensitlbe length (maybe 100k)? */ + + nsresult rv; + AutoJSContextStack stack; + rv = stack.Init (); + if (NS_FAILED (rv)) return rv; + + nsCOMPtr<nsIDOMWindow> parent (do_GetInterface (ctx)); + if (!parent) { + parent = EphyJSUtils::GetDOMWindowFromCallContext (); + g_print ("Fallback window %p\n", (void*)parent.get()); + } + GtkWidget *gparent = EphyUtils::FindGtkParent (parent); + + AutoWindowModalState modalState (parent); + + GladeXML *gxml = glade_xml_new (ephy_file ("form-signing-dialog.glade"), + "form_signing_dialog", NULL); + g_return_val_if_fail (gxml, NS_ERROR_FAILURE); + + GtkWidget *dialog = glade_xml_get_widget (gxml, "form_signing_dialog"); + gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (gparent)); + + GtkLabel *primary_label = GTK_LABEL (glade_xml_get_widget (gxml, "primary_label")); + char *primary = g_strdup_printf (_("The web site “%s” requests that you sign the following text:"), + NS_ConvertUTF16toUTF8 (host).get ()); + gtk_label_set_text (primary_label, primary); + g_free (primary); + + GtkTextView *textview = GTK_TEXT_VIEW (glade_xml_get_widget (gxml, "textview")); + NS_ConvertUTF16toUTF8 text (signText); + gtk_text_buffer_set_text (gtk_text_view_get_buffer (textview), + text.get (), text.Length ()); + + GtkTable *table = GTK_TABLE (glade_xml_get_widget (gxml, "table")); + GtkComboBox *combo = GTK_COMBO_BOX (gtk_combo_box_new_text ()); + for (PRUint32 i = 0; i < count; ++i) { + gtk_combo_box_append_text (combo, NS_ConvertUTF16toUTF8 (certNickList[i]).get ()); + } + + gtk_combo_box_set_active (combo, 0); + gtk_table_attach (table, GTK_WIDGET (combo), 1, 2, 0, 1, + GtkAttachOptions (0), GtkAttachOptions (0), 0, 0); + gtk_widget_show (GTK_WIDGET (combo)); + + /* FIXME: Add "View Certificate" button */ + + GtkEntry *password_entry = GTK_ENTRY (glade_xml_get_widget (gxml, "password_entry")); + + GtkWidget *button = gtk_dialog_add_button (GTK_DIALOG (dialog), + GTK_STOCK_CANCEL, + GTK_RESPONSE_CANCEL); + gtk_dialog_add_button (GTK_DIALOG (dialog), + _("_Sign text"), + GTK_RESPONSE_ACCEPT); + gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_REJECT); + gtk_widget_grab_focus (button); + + /* FIXME: make Sign insensitive for some time (proportional to text length, with maximum?) */ + + g_object_unref (gxml); + + int response = gtk_dialog_run (GTK_DIALOG (dialog)); + + *_cancelled = response != GTK_RESPONSE_ACCEPT; + + if (response == GTK_RESPONSE_ACCEPT) { + _password = NS_ConvertUTF8toUTF16 (gtk_entry_get_text (password_entry)); + *selectedIndex = gtk_combo_box_get_active (combo); + } + + gtk_widget_destroy (dialog); + + return NS_OK; +} diff --git a/embed/xulrunner/embed/GeckoFormSigningDialog.h b/embed/xulrunner/embed/GeckoFormSigningDialog.h new file mode 100644 index 000000000..a4438e9d1 --- /dev/null +++ b/embed/xulrunner/embed/GeckoFormSigningDialog.h @@ -0,0 +1,42 @@ +/* + * Copyright © 2006 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#ifndef GECKO_FORMSIGNINGDIALOGS_H +#define GECKO_FORMSIGNINGDIALOGS_H + +#include <nsIFormSigningDialog.h> + +/* 4e42a43e-fbc5-40cc-bcbb-8cbc4e2101eb */ +#define GECKO_FORMSIGNINGDIALOGS_CID \ +{ 0x4e42a43e, 0xfbc5, 0x40cc, { 0xbc, 0xbb, 0x8c, 0xbc, 0x4e, 0x21, 0x01, 0xeb } } + +#define GECKO_FORMSIGNINGDIALOGS_CLASSNAME "Gecko Form Signing Dialogs" + +class GeckoFormSigningDialog : public nsIFormSigningDialog +{ + public: + NS_DECL_ISUPPORTS + NS_DECL_NSIFORMSIGNINGDIALOG + + GeckoFormSigningDialog(); + ~GeckoFormSigningDialog(); +}; + +#endif /* GECKO_FORMSIGNINGDIALOGS_H */ diff --git a/embed/xulrunner/embed/GeckoPrintService.cpp b/embed/xulrunner/embed/GeckoPrintService.cpp new file mode 100644 index 000000000..8be8263b9 --- /dev/null +++ b/embed/xulrunner/embed/GeckoPrintService.cpp @@ -0,0 +1,756 @@ +/* + * Copyright © 2006, 2007 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#include "mozilla-config.h" +#include "config.h" + +#include <glib.h> +#include <glib/gi18n.h> +#include <gtk/gtkcheckbutton.h> +#include <gtk/gtkdialog.h> +#include <gtk/gtklabel.h> +#include <gtk/gtkmessagedialog.h> +#include <gtk/gtkprintunixdialog.h> +#include <gtk/gtkstock.h> +#include <gtk/gtkwindow.h> +#include <glade/glade-xml.h> + +#include <nsStringAPI.h> + +#include <nsCOMPtr.h> +#include <nsIDOMWindow.h> +#include <nsIDOMWindowInternal.h> + +#include "eel-gconf-extensions.h" +#include "ephy-debug.h" +#include "ephy-embed-shell.h" +#include "ephy-file-helpers.h" +#include "ephy-gui.h" +#include "ephy-prefs.h" +#include "ephy-stock-icons.h" + +#include "AutoJSContextStack.h" +#include "AutoWindowModalState.h" +#include "EphyUtils.h" +#include "GeckoPrintSession.h" + +#include "GeckoPrintService.h" + +/* Some printing keys */ + +#define CONF_PRINT_BG_COLORS "/apps/epiphany/dialogs/print_background_colors" +#define CONF_PRINT_BG_IMAGES "/apps/epiphany/dialogs/print_background_images" +#define CONF_PRINT_COLOR "/apps/epiphany/dialogs/print_color" +#define CONF_PRINT_DATE "/apps/epiphany/dialogs/print_date" +#define CONF_PRINT_PAGE_NUMBERS "/apps/epiphany/dialogs/print_page_numbers" +#define CONF_PRINT_PAGE_TITLE "/apps/epiphany/dialogs/print_page_title" +#define CONF_PRINT_PAGE_URL "/apps/epiphany/dialogs/print_page_url" + +#define LITERAL(s) reinterpret_cast<const nsAString::char_type*>(NS_L(s)) + +/* From nsIDeviceContext.h */ +#define NS_ERROR_GFX_PRINTER_BASE (1) /* adjustable :-) */ +#define NS_ERROR_GFX_PRINTER_ACCESS_DENIED \ + NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_GFX,NS_ERROR_GFX_PRINTER_BASE+5) +#define NS_ERROR_GFX_PRINTER_NAME_NOT_FOUND \ + NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_GFX,NS_ERROR_GFX_PRINTER_BASE+4) + +NS_IMPL_ISUPPORTS1 (GeckoPrintService, + nsIPrintingPromptService) + +GeckoPrintService::GeckoPrintService() +{ + LOG ("GeckoPrintService ctor [%p]", this); +} + +GeckoPrintService::~GeckoPrintService() +{ + LOG ("GeckoPrintService dtor [%p]", this); +} + +/* nsIPrintingPromptService implementation */ + +/* void showPrintDialog (in nsIDOMWindow parent, + in nsIWebBrowserPrint webBrowserPrint, + in nsIPrintSettings printSettings); */ +NS_IMETHODIMP +GeckoPrintService::ShowPrintDialog (nsIDOMWindow *aParent, + nsIWebBrowserPrint *aWebBrowserPrint, + nsIPrintSettings *aSettings) +{ + /* Locked down? */ + if (eel_gconf_get_boolean (CONF_LOCKDOWN_DISABLE_PRINTING)) { + return NS_ERROR_GFX_PRINTER_ACCESS_DENIED; + } + + GeckoPrintSession *session = GeckoPrintSession::FromSettings (aSettings); + NS_ENSURE_TRUE (session, NS_ERROR_INVALID_POINTER); + + /* Print settings changes disallowed, just translate the settings */ + if (eel_gconf_get_boolean (CONF_LOCKDOWN_DISABLE_PRINT_SETUP)) { + return PrintUnattended (aParent, aSettings); + } + + /* Not locked down, show the dialogue */ + + nsresult rv; +#if 0 + PRBool haveSelection = PR_FALSE; + rv = aSettings->GetPrintOptions(nsIPrintSettings::kEnableSelectionRB, &haveSelection); + NS_ENSURE_SUCCESS (rv, rv); +#endif + + PRInt16 frameUI = nsIPrintSettings::kFrameEnableAll; + rv = aSettings->GetHowToEnableFrameUI (&frameUI); + NS_ENSURE_SUCCESS (rv, rv); + + GtkWidget *parent = EphyUtils::FindGtkParent (aParent); + NS_ENSURE_TRUE(parent, NS_ERROR_INVALID_POINTER); + + AutoJSContextStack stack; + rv = stack.Init (); + if (NS_FAILED (rv)) { + return rv; + } + + AutoWindowModalState modalState (aParent); + + EphyEmbedShell *shell = ephy_embed_shell_get_default (); + + GladeXML *xml = glade_xml_new (ephy_file ("print.glade"), + "print_dialog_custom_tab", NULL); + if (!xml) { + return NS_ERROR_FAILURE; + } + + /* Build the custom tab */ + GtkWidget *custom_tab = glade_xml_get_widget (xml, "custom_tab_container"); + ephy_gui_connect_checkbutton_to_gconf (glade_xml_get_widget (xml, "print_bg_colors_checkbutton"), CONF_PRINT_BG_COLORS); + ephy_gui_connect_checkbutton_to_gconf (glade_xml_get_widget (xml, "print_bg_images_checkbutton"), CONF_PRINT_BG_IMAGES); + ephy_gui_connect_checkbutton_to_gconf (glade_xml_get_widget (xml, "print_date_checkbutton"), CONF_PRINT_DATE); + ephy_gui_connect_checkbutton_to_gconf (glade_xml_get_widget (xml, "print_page_numbers_checkbutton"), CONF_PRINT_PAGE_NUMBERS); + ephy_gui_connect_checkbutton_to_gconf (glade_xml_get_widget (xml, "print_page_title_checkbutton"), CONF_PRINT_PAGE_TITLE); + ephy_gui_connect_checkbutton_to_gconf (glade_xml_get_widget (xml, "print_page_url_checkbutton"), CONF_PRINT_PAGE_URL); + + GtkWidget *frame_box = glade_xml_get_widget (xml, "frame_box"); + GtkWidget *print_frames_normal = glade_xml_get_widget (xml, "print_frames_normal"); + GtkWidget *print_frames_selected = glade_xml_get_widget (xml, "print_frames_selected"); + GtkWidget *print_frames_separately = glade_xml_get_widget (xml, "print_frames_separately"); + + /* FIXME: store/load from pref */ + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (print_frames_normal), TRUE); + + if (frameUI == nsIPrintSettings::kFrameEnableAll) { + /* Allow all frame options */ + gtk_widget_set_sensitive (frame_box, TRUE); + } else if (frameUI == nsIPrintSettings::kFrameEnableAsIsAndEach) { + /* Allow all except "selected frame" */ + gtk_widget_set_sensitive (frame_box, TRUE); + gtk_widget_set_sensitive (print_frames_selected, FALSE); + /* Preselect this one, since the default above only prints _one page_ ! */ + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (print_frames_separately), TRUE); + } + + /* FIXME: this sucks! find some way to do all of this async! */ + GtkWidget *dialog = gtk_print_unix_dialog_new (NULL /* FIXME title */, + GTK_WINDOW (parent)); + GtkPrintUnixDialog *print_dialog = GTK_PRINT_UNIX_DIALOG (dialog); + + GtkPrintCapabilities capabilities = + GtkPrintCapabilities (GTK_PRINT_CAPABILITY_PAGE_SET | + GTK_PRINT_CAPABILITY_COPIES | + GTK_PRINT_CAPABILITY_COLLATE | + GTK_PRINT_CAPABILITY_REVERSE | + GTK_PRINT_CAPABILITY_SCALE | + GTK_PRINT_CAPABILITY_GENERATE_PS); +#if 0 //def HAVE_GECKO_1_9 + capabilities = GtkPrintCapabilities (capabilities | GTK_PRINT_CAPABILITY_GENERATE_PDF); +#endif + gtk_print_unix_dialog_set_manual_capabilities (print_dialog, capabilities); + + gtk_print_unix_dialog_set_page_setup (print_dialog, + ephy_embed_shell_get_page_setup (shell)); + gtk_print_unix_dialog_set_settings (print_dialog, + ephy_embed_shell_get_print_settings (shell)); + + /* Remove custom tab from its dummy window and put it in the print dialogue */ + g_object_ref_sink (custom_tab); + gtk_container_remove (GTK_CONTAINER (custom_tab->parent), custom_tab); + gtk_print_unix_dialog_add_custom_tab (print_dialog, custom_tab, + gtk_label_new (_("Options"))); /* FIXME better name! */ + g_object_unref (custom_tab); + g_object_unref (xml); + + gtk_window_set_icon_name (GTK_WINDOW (dialog), EPHY_STOCK_EPHY); + + int response = gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_hide (dialog); + + GtkPrinter *printer = gtk_print_unix_dialog_get_selected_printer (print_dialog); + + if (response != GTK_RESPONSE_OK || !printer) { + gtk_widget_destroy (dialog); + + return NS_ERROR_ABORT; + } + + PRInt16 printFrames = nsIPrintSettings::kNoFrames; + if (frameUI != nsIPrintSettings::kFrameEnableNone) { + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (print_frames_normal))) { + printFrames = nsIPrintSettings::kFramesAsIs; + } else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (print_frames_selected))) { + printFrames = nsIPrintSettings::kSelectedFrame; + } if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (print_frames_separately))) { + printFrames = nsIPrintSettings::kEachFrameSep; + } + } + + GtkPageSetup *pageSetup = gtk_print_unix_dialog_get_page_setup (print_dialog); /* no reference owned */ + ephy_embed_shell_set_page_setup (shell, pageSetup); + + GtkPrintSettings *settings = gtk_print_unix_dialog_get_settings (print_dialog); + ephy_embed_shell_set_print_settings (shell, settings); + + /* We copy the setup and settings so we can modify them to unset + * options handled by gecko. + */ + GtkPageSetup *pageSetupCopy = gtk_page_setup_copy (pageSetup); + pageSetup = pageSetupCopy; + + GtkPrintSettings *settingsCopy = gtk_print_settings_copy (settings); + g_object_unref (settings); + settings = settingsCopy; + + rv = session->SetSettings (aSettings, settings, pageSetup, printer); + + /* Now translate the settings to nsIPrintSettings */ + if (NS_SUCCEEDED (rv)) { + nsCString sourceFile; + session->GetSourceFile (sourceFile); + if (!sourceFile.IsEmpty ()) { + rv = TranslateSettings (settings, pageSetup, printer, sourceFile, printFrames, PR_TRUE, aSettings); + } else { + rv = NS_ERROR_FAILURE; + } + } + + gtk_widget_destroy (dialog); + + g_object_unref (settings); + g_object_unref (pageSetup); + + return rv; +} + +/* 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 +GeckoPrintService::ShowProgress (nsIDOMWindow *aParent, + nsIWebBrowserPrint *aWebBrowserPrint, + nsIPrintSettings *aPrintSettings, + nsIObserver *aOpenDialogObserver, + PRBool aIsForPrinting, + nsIWebProgressListener **_webProgressListener, + nsIPrintProgressParams **_printProgressParams, + PRBool *_notifyOnOpen) +{ + /* Print preview */ + if (!aIsForPrinting) { + return NS_OK; + } + + nsresult rv; + nsCOMPtr<nsIDOMWindowInternal> domWin (do_QueryInterface (aParent, &rv)); + NS_ENSURE_SUCCESS (rv, rv); + + nsCOMPtr<nsIPrintSession> session; + rv = aPrintSettings->GetPrintSession (getter_AddRefs (session)); + NS_ENSURE_TRUE (NS_SUCCEEDED (rv) && session, nsnull); + + nsCOMPtr<nsIPrintProgress> progress (do_QueryInterface (session, &rv)); + NS_ENSURE_SUCCESS (rv, rv); + + /* Our print session implements those interfaces */ + rv = CallQueryInterface (session, _webProgressListener); + rv |= CallQueryInterface (session, _printProgressParams); + NS_ENSURE_SUCCESS (rv, rv); + + /* Setting this to PR_FALSE will make gecko immediately start printing + * when we return from this function. + * If we set this to PR_TRUE, we need to call aOpenDialogObserver::Observe + * (topic, subject and data don't matter) when we're ready for printing. + */ + *_notifyOnOpen = PR_FALSE; + + return progress->OpenProgressDialog (domWin, nsnull, nsnull, aOpenDialogObserver, _notifyOnOpen); +} + +/* void showPageSetup (in nsIDOMWindow parent, + in nsIPrintSettings printSettings, + in nsIObserver aObs); */ +NS_IMETHODIMP GeckoPrintService::ShowPageSetup (nsIDOMWindow *aParent, + nsIPrintSettings *aPrintSettings, + nsIObserver *aObserver) +{ + /* This function is never called from gecko code */ +#if 0 + /* Locked down? */ + if (eel_gconf_get_boolean (CONF_LOCKDOWN_DISABLE_PRINTING) || + eel_gconf_get_boolean (CONF_LOCKDOWN_DISABLE_PRINT_SETUP)) { + return NS_ERROR_ABORT; + } + + GtkWidget *parent = EphyUtils::FindGtkParent (aParent); + NS_ENSURE_TRUE(parent, NS_ERROR_INVALID_POINTER); + + AutoJSContextStack stack; + nsresult rv = stack.Init (); + if (NS_FAILED (rv)) { + return rv; + } + + AutoWindowModalState modalState (aParent); + + EphyEmbedShell *shell = ephy_embed_shell_get_default (); + GtkPageSetup *new_setup = + gtk_print_run_page_setup_dialog (GTK_WINDOW (parent), + ephy_embed_shell_get_page_setup (shell), + ephy_embed_shell_get_print_settings (shell)); + if (new_setup) { + ephy_embed_shell_set_page_setup (shell, new_setup); + g_object_unref (new_setup); + } + + /* FIXME do we need to notify aObserver somehow? */ + return NS_OK; +#endif + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* void showPrinterProperties (in nsIDOMWindow parent, + in wstring printerName, + in nsIPrintSettings printSettings); */ +NS_IMETHODIMP +GeckoPrintService::ShowPrinterProperties (nsIDOMWindow *aParent, + const PRUnichar *aPrinterName, + nsIPrintSettings *aPrintSettings) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* Private methods */ + +#if 0 +typedef struct +{ + GMainLoop *mainLoop; + GtkPrinter *mPrinter; + guint timeout; + int response; + guint cancelled : 1; +} FindPrinterData; + +static void +FreeFindPrinterData (FindPrinterData *data) +{ + if (data->printer) { + g_object_unref (data->printer); + } +} + +static void +DialogResponseCallback (GtkWidget *aDialog, + int aResponse, + FindPrinterData *data) +{ + data->response = aResponse; + g_main_loop_quit (data->mainloop); +} + +static void +TimeoutCallback (FindPrinterData *data) +{ + data->cancelled = TRUE; + g_main_loop_quit (data->mainLoop); + data->mainLoop = NULL; + return FALSE; +} + +static gboolean +PrinterEnumerateCallback (GtkPrinter *aPrinter, + FindPrinterData *data) +{ + if (data->cancelled) + return TRUE; + + if ((data->printerName && + strcmp (data->printerName, gtk_printer_get_name (aPrinter)) == 0) || + (!data->printerName && + gtk_printer_is_default (aPrinter))) { + data->printer = g_object_ref (aPrinter); + return TRUE; + } + + return FALSE; +} +#endif + +nsresult +GeckoPrintService::PrintUnattended (nsIDOMWindow *aParent, + nsIPrintSettings *aPrintSettings) +{ + return NS_ERROR_NOT_IMPLEMENTED; +#if 0 + GtkWidget *parent = EphyUtils::FindGtkParent (aParent); + NS_ENSURE_TRUE(parent, NS_ERROR_INVALID_POINTER); + + PRBool isCalledFromScript = EphyJSUtils::IsCalledFromScript (); + + nsresult rv; + AutoJSContextStack stack; + rv = stack.Init (); + if (NS_FAILED (rv)) { + return rv; + } + + AutoWindowModalState modalState (aParent); + + EphyEmbedShell *shell = ephy_embed_shell_get_default (); + GtkPrintSettings *settings = ephy_embed_shell_get_print_settings (shell); + NS_ENSURE_TRUE (settings, NS_ERROR_FAILURE); + + const char *printer = gtk_print_settings_get (settings, GTK_PRINT_SETTINGS_PRINTER); +#if 0 + if (!printer || !printer[0]) { + return NS_ERROR_GFX_PRINTER_NAME_NOT_FOUND; + } +#endif + /* We need to find the printer, so we need to run a mainloop. + * If called from a script, give the user a way to cancel the print; + * otherwise we'll just show a generic progress message. + */ + GtkWidget *dialog; + if (isCalledFromScript) { + dialog = gtk_message_dialog_new (GTK_WINDOW (parent), + GtkDialogFlags (0), + GTK_MESSAGE_QUESTION, + GTK_BUTTONS_CANCEL, + "%s", _("Print this page?")); + gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_PRINT, + GTK_RESPONSE_ACCEPT); + } else { + dialog = gtk_message_dialog_new (GTK_WINDOW (parent), + GtkDialogFlags (0), + GTK_MESSAGE_QUESTION, + GTK_BUTTONS_CANCEL, + "%s", _("Preparing to print")); + } + gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CANCEL); + gtk_window_set_icon_name (GTK_WINDOW (dialog), EPHY_STOCK_EPHY); + gtk_window_set_modal (GTK_WINDOW (dialog), TRUE); + + FindPrinterData *data = g_new0 (PrinterData, 1); + data->dialog = dialog; + + g_signal_connect (dialog, "response", + G_CALLBACK (DialogResponseCallback), data); + + /* Don't run forever */ + data->timeoutId = g_timeout_add (PRINTER_ENUMERATE_TIMEOUT, + (GSourceFunc) EnumerateTimoutCallback, + data); + /* Enumerate printers until we find our printer */ + gtk_enumerate_printers ((GtkPrinterFunc) PrinterEnumerateCallback, + data, + (GDestroyNotify) EnumerateDestroyCallback, FALSE); + + /* Now run the mainloop */ + int response = gtk_dialog_run (GTK_DIALOG (dialog)); + Printer + gtk_widget_destroy (dialog); + + if (response != GTK_RESPONSE_ACCEPT) { + return NS_ERROR_ABORT; + } + + nsCString sourceFile; + session->GetSourceFile (sourceFile); + if (!sourceFile.IsEmpty ()) { + rv = TranslateSettings (settings, + ephy_embed_shell_get_page_setup (shell), + sourceFile, PR_TRUE, aSettings); + } else { + rv = NS_ERROR_FAILURE; + } + + return rv; + } +#endif /* if 0 */ +} + +/* Static methods */ + +/* static */ nsresult +GeckoPrintService::TranslateSettings (GtkPrintSettings *aGtkSettings, + GtkPageSetup *aPageSetup, + GtkPrinter *aPrinter, + const nsACString &aSourceFile, + PRInt16 aPrintFrames, + PRBool aIsForPrinting, + nsIPrintSettings *aSettings) +{ + NS_ENSURE_ARG (aPrinter); + NS_ENSURE_ARG (aGtkSettings); + NS_ENSURE_ARG (aPageSetup); + +#if 0 + /* Locked down? */ + if (gtk_print_settings_get_print_to_file (aGtkSettings) && + eel_gconf_get_boolean (CONF_LOCKDOWN_DISABLE_SAVE_TO_DISK)) { + return NS_ERROR_GFX_PRINTER_ACCESS_DENIED; + } +#endif + + GtkPrintCapabilities capabilities = gtk_printer_get_capabilities (aPrinter); + + /* Initialisation */ + aSettings->SetIsInitializedFromPrinter (PR_FALSE); /* FIXME: PR_TRUE? */ + aSettings->SetIsInitializedFromPrefs (PR_FALSE); /* FIXME: PR_TRUE? */ + aSettings->SetPrintSilent (PR_FALSE); + aSettings->SetShowPrintProgress (PR_TRUE); + + /* We always print PS to a file and then hand that off to gtk-print */ + aSettings->SetPrinterName (LITERAL ("PostScript/default")); + + if (aIsForPrinting) { + aSettings->SetPrintToFile (PR_TRUE); + + nsString sourceFile; + NS_CStringToUTF16 (aSourceFile, + NS_CSTRING_ENCODING_NATIVE_FILESYSTEM, + sourceFile); + + aSettings->SetToFileName (sourceFile.get ()); + } else { + /* Otherwise mozilla will create the file nevertheless and + * fail since we haven't set a name! + */ + aSettings->SetPrintToFile (PR_FALSE); + } + + /* This is the time between printing each page, in ms. + * It 'gives the user more time to press cancel' ! + * We don't want any of this nonsense, so set this to a low value, + * just enough to update the print dialogue. + */ + aSettings->SetPrintPageDelay (50); + + if (aIsForPrinting) { +#if 0 //def HAVE_GECKO_1_9 + NS_ENSURE_TRUE (aPrinter, NS_ERROR_FAILURE); + + const char *format = gtk_print_settings_get (aGtkSettings, GTK_PRINT_SETTINGS_OUTPUT_FILE_FORMAT); + if (!format) + format = "ps"; + + if (strcmp (format, "pdf") == 0 && + gtk_printer_accepts_pdf (aPrinter)) { + aSettings->SetOutputFormat (nsIPrintSettings::kOutputFormatPDF); + } else if (strcmp (format, "ps") == 0 && + gtk_printer_accepts_ps (aPrinter)) { + aSettings->SetOutputFormat (nsIPrintSettings::kOutputFormatPS); + } else { + g_warning ("Output format '%s' specified, but printer '%s' does not support it!", + format, gtk_printer_get_name (aPrinter)); + return NS_ERROR_FAILURE; + } +#endif + + int n_copies = gtk_print_settings_get_n_copies (aGtkSettings); + if (n_copies <= 0) + return NS_ERROR_FAILURE; + if (capabilities & GTK_PRINT_CAPABILITY_COPIES) { + aSettings->SetNumCopies (1); + } else { + /* We have to copy them ourself */ + aSettings->SetNumCopies (n_copies); + gtk_print_settings_set_n_copies (aGtkSettings, 1); + } + + gboolean reverse = gtk_print_settings_get_reverse (aGtkSettings); + if (capabilities & GTK_PRINT_CAPABILITY_REVERSE) { + aSettings->SetPrintReversed (PR_FALSE); + } else { + aSettings->SetPrintReversed (reverse); + gtk_print_settings_set_reverse (aGtkSettings, FALSE); + } + + GtkPageSet pageSet = gtk_print_settings_get_page_set (aGtkSettings); + aSettings->SetPrintOptions (nsIPrintSettings::kPrintEvenPages, + pageSet != GTK_PAGE_SET_ODD); + aSettings->SetPrintOptions (nsIPrintSettings::kPrintEvenPages, + pageSet != GTK_PAGE_SET_EVEN); + + GtkPrintPages printPages = gtk_print_settings_get_print_pages (aGtkSettings); + switch (printPages) { + case GTK_PRINT_PAGES_RANGES: { + int numRanges = 0; + GtkPageRange *pageRanges = gtk_print_settings_get_page_ranges (aGtkSettings, &numRanges); + if (numRanges > 0) { + /* FIXME: We can only support one range, ignore more ranges or raise error? */ + aSettings->SetPrintRange (nsIPrintSettings::kRangeSpecifiedPageRange); + /* Gecko page numbers start at 1, while gtk page numbers start at 0 */ + aSettings->SetStartPageRange (pageRanges[0].start + 1); + aSettings->SetEndPageRange (pageRanges[0].end + 1); + + g_free (pageRanges); + break; + } + /* Fall-through to PAGES_ALL */ + } + case GTK_PRINT_PAGES_CURRENT: + /* not supported, fall through */ + case GTK_PRINT_PAGES_ALL: + aSettings->SetPrintRange (nsIPrintSettings::kRangeAllPages); + break; + /* FIXME: we need some custom ranges here, "Selection" and "Focused Frame" */ + } + } else { + aSettings->SetPrintOptions (nsIPrintSettings::kPrintEvenPages, PR_TRUE); + aSettings->SetPrintOptions (nsIPrintSettings::kPrintEvenPages, PR_TRUE); + aSettings->SetPrintReversed (PR_FALSE); + aSettings->SetPrintRange (nsIPrintSettings::kRangeAllPages); + } + + /* And clear those in the settings, so the printer doesn't try to apply them too */ + gtk_print_settings_set_print_pages (aGtkSettings, GTK_PRINT_PAGES_ALL); + gtk_print_settings_set_page_ranges (aGtkSettings, NULL, 0); + gtk_print_settings_set_page_set (aGtkSettings, GTK_PAGE_SET_ALL); + + switch (gtk_print_settings_get_orientation (aGtkSettings)) { + case GTK_PAGE_ORIENTATION_PORTRAIT: + case GTK_PAGE_ORIENTATION_REVERSE_PORTRAIT: /* not supported */ + aSettings->SetOrientation (nsIPrintSettings::kPortraitOrientation); + break; + case GTK_PAGE_ORIENTATION_LANDSCAPE: + case GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE: /* not supported */ + aSettings->SetOrientation (nsIPrintSettings::kLandscapeOrientation); + break; + } + + aSettings->SetPrintInColor (gtk_print_settings_get_use_color (aGtkSettings)); + + aSettings->SetPaperSizeUnit(nsIPrintSettings::kPaperSizeMillimeters); + aSettings->SetPaperSize (nsIPrintSettings::kPaperSizeDefined); + + GtkPaperSize *paperSize = gtk_page_setup_get_paper_size (aPageSetup); + if (!paperSize) { + return NS_ERROR_FAILURE; + } + + aSettings->SetPaperSizeType (nsIPrintSettings::kPaperSizeDefined); + aSettings->SetPaperWidth (gtk_paper_size_get_width (paperSize, GTK_UNIT_MM)); + aSettings->SetPaperHeight (gtk_paper_size_get_height (paperSize, GTK_UNIT_MM)); + +#ifdef HAVE_GECKO_1_9 + aSettings->SetPaperName (NS_ConvertUTF8toUTF16 (gtk_paper_size_get_name (paperSize)).get ()); +#else +{ + /* Mozilla bug https://bugzilla.mozilla.org/show_bug.cgi?id=307404 + * means that we cannot actually use any paper sizes except mozilla's + * builtin list, and we must refer to them *by name*! + */ + static const struct { + const char gtkPaperName[13]; + const char mozPaperName[10]; + } paperTable [] = { + { GTK_PAPER_NAME_A5, "A5" }, + { GTK_PAPER_NAME_A4, "A4" }, + { GTK_PAPER_NAME_A3, "A3" }, + { GTK_PAPER_NAME_LETTER, "Letter" }, + { GTK_PAPER_NAME_LEGAL, "Legal" }, + { GTK_PAPER_NAME_EXECUTIVE, "Executive" }, + }; + + const char *paperName = gtk_paper_size_get_name (paperSize); + + PRUint32 i; + for (i = 0; i < G_N_ELEMENTS (paperTable); i++) { + if (g_ascii_strcasecmp (paperTable[i].gtkPaperName, paperName) == 0) { + paperName = paperTable[i].mozPaperName; + break; + } + } + if (i == G_N_ELEMENTS (paperTable)) { + /* Not in table, fall back to A4 */ + g_warning ("Unknown paper name '%s', falling back to A4", gtk_paper_size_get_name (paperSize)); + paperName = paperTable[1].mozPaperName; + } + + aSettings->SetPaperName (NS_ConvertUTF8toUTF16 (paperName).get ()); +} +#endif /* !HAVE_GECKO_1_9 */ + + /* Sucky mozilla wants margins in inch! */ + aSettings->SetMarginTop (gtk_page_setup_get_top_margin (aPageSetup, GTK_UNIT_INCH)); + aSettings->SetMarginBottom (gtk_page_setup_get_bottom_margin (aPageSetup, GTK_UNIT_INCH)); + aSettings->SetMarginLeft (gtk_page_setup_get_left_margin (aPageSetup, GTK_UNIT_INCH)); + aSettings->SetMarginRight (gtk_page_setup_get_right_margin (aPageSetup, GTK_UNIT_INCH)); + + aSettings->SetHeaderStrLeft (eel_gconf_get_boolean (CONF_PRINT_PAGE_TITLE) ? LITERAL ("&T") : LITERAL ("")); + aSettings->SetHeaderStrCenter (LITERAL ("")); + aSettings->SetHeaderStrRight (eel_gconf_get_boolean (CONF_PRINT_PAGE_URL) ? LITERAL ("&U") : LITERAL ("")); + aSettings->SetFooterStrLeft (eel_gconf_get_boolean (CONF_PRINT_PAGE_NUMBERS) ? LITERAL ("&PT") : LITERAL ("")); + aSettings->SetFooterStrCenter (LITERAL ("")); + aSettings->SetFooterStrRight (eel_gconf_get_boolean (CONF_PRINT_DATE) ? LITERAL ("&D") : LITERAL ("")); + + aSettings->SetPrintFrameType (aPrintFrames); + aSettings->SetPrintFrameTypeUsage (nsIPrintSettings::kUseSettingWhenPossible); + + /* FIXME: only if GTK_PRINT_CAPABILITY_SCALE is not set? */ + aSettings->SetScaling (gtk_print_settings_get_scale (aGtkSettings) / 100.0); + gtk_print_settings_set_scale (aGtkSettings, 1.0); + + aSettings->SetShrinkToFit (PR_FALSE); /* FIXME setting */ + + aSettings->SetPrintBGColors (eel_gconf_get_boolean (CONF_PRINT_BG_COLORS) != FALSE); + aSettings->SetPrintBGImages (eel_gconf_get_boolean (CONF_PRINT_BG_IMAGES) != FALSE); + + /* aSettings->SetPlexName (LITERAL ("default")); */ + /* aSettings->SetColorspace (LITERAL ("default")); */ + /* aSettings->SetResolutionName (LITERAL ("default")); */ + /* aSettings->SetDownloadFonts (PR_TRUE); */ + + /* Unset those setting that we can handle, so they don't get applied + * again for the print job. + */ + /* gtk_print_settings_set_collate (aGtkSettings, FALSE); not yet */ + /* FIXME: Unset the orientation for the print job? */ + /* gtk_print_settings_set_orientation (aGtkSettings, GTK_PAGE_ORIENTATION_PORTRAIT); */ + /* FIXME: unset output format -> "ps" ? */ + + return NS_OK; +} diff --git a/embed/xulrunner/embed/GeckoPrintService.h b/embed/xulrunner/embed/GeckoPrintService.h new file mode 100644 index 000000000..c2e21cf3e --- /dev/null +++ b/embed/xulrunner/embed/GeckoPrintService.h @@ -0,0 +1,54 @@ +/* + * Copyright © 2006 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#ifndef GECKO_PRINT_SERVICE_H +#define GECKO_PRINT_SERVICE_H + +#include <gtk/gtkpagesetup.h> +#include <gtk/gtkprintsettings.h> +#include <gtk/gtkprinter.h> + +#include <nsIPrintingPromptService.h> + +class nsIPrintSettings; + +/* 6a71ff30-7f4d-4d91-b71a-d5c9764b34be */ +#define GECKO_PRINT_SERVICE_IID \ +{ 0x6a71ff30, 0x7f4d, 0x4d91, \ + { 0xb7, 0x1a, 0xd5, 0xc9, 0x76, 0x4b, 0x34, 0xbe } } + +#define GECKO_PRINT_SERVICE_CLASSNAME "Gecko Print Service" + +class GeckoPrintService : public nsIPrintingPromptService +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIPRINTINGPROMPTSERVICE + + GeckoPrintService(); + virtual ~GeckoPrintService(); + + static nsresult TranslateSettings (GtkPrintSettings*, GtkPageSetup *, GtkPrinter *, const nsACString&, PRInt16, PRBool, nsIPrintSettings*); + +private: + nsresult PrintUnattended (nsIDOMWindow *, nsIPrintSettings *); +}; + +#endif /* GECKO_PRINT_SERVICE_H */ diff --git a/embed/xulrunner/embed/GeckoPrintSession.cpp b/embed/xulrunner/embed/GeckoPrintSession.cpp new file mode 100644 index 000000000..ddf968283 --- /dev/null +++ b/embed/xulrunner/embed/GeckoPrintSession.cpp @@ -0,0 +1,629 @@ +/* + * Copyright © 2006 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#include "mozilla-config.h" +#include "config.h" + +#include <unistd.h> + +#include <glib/gi18n.h> +#include <gtk/gtk.h> + +#include <nsStringAPI.h> + +#include <nsIDOMWindow.h> +#include <nsIDOMWindowInternal.h> +#include <nsIPrintSettings.h> + +#include "ephy-debug.h" +#include "ephy-embed-shell.h" +#include "ephy-file-helpers.h" + +#include "EphyUtils.h" + +#include "GeckoPrintSession.h" + +#define MAX_STRING_LENGTH 512 + +GeckoPrintSession::GeckoPrintSession () +: mSettings(NULL) +, mPageSetup(NULL) +, mPrinter(NULL) +, mJob(NULL) +, mProgressDialog(NULL) +, mTitleLabel(NULL) +, mProgressBar(NULL) +, mStartPrintIdleID(0) +, mSourceFileIsTemp(PR_FALSE) +, mDone(PR_FALSE) +, mCancelled(PR_FALSE) +{ + LOG ("GeckoPrintSession ctor [%p]", (void*) this); + + /* FIXME: connect to "prepare-close" ? */ + g_object_ref (ephy_embed_shell_get_default ()); +} + +GeckoPrintSession::~GeckoPrintSession () +{ + LOG ("GeckoPrintSession dtor [%p]", (void*) this); + + NS_ASSERTION (mStartPrintIdleID == 0, "Impossible"); + + if (!mDone && !mCancelled) { + Cancel (); + } + DestroyJob (); + + if (mSettings) { + g_object_unref (mSettings); + } + if (mPageSetup) { + g_object_unref (mPageSetup); + } + if (mPrinter) { + g_object_unref (mPrinter); + } + if (mProgressDialog) { + gtk_widget_destroy (mProgressDialog); + } + if (mSourceFileIsTemp) { + unlink (mSourceFile.get ()); + } + + g_object_unref (ephy_embed_shell_get_default ()); +} + +void +GeckoPrintSession::GetSourceFile (nsACString &aSource) +{ + aSource.Assign (mSourceFile); +} + +nsresult +GeckoPrintSession::SetSettings (nsIPrintSettings *aPrintSettings, + GtkPrintSettings *aSettings, + GtkPageSetup *aPageSetup, + GtkPrinter *aPrinter) +{ + NS_ASSERTION (!mPrintSettings && !mSettings && !mPageSetup && !mPrinter, "Already have settings!"); + + NS_ENSURE_ARG (aPrintSettings); + NS_ENSURE_ARG (aSettings); + + mPrintSettings = aPrintSettings; + mSettings = (GtkPrintSettings *) g_object_ref (aSettings); + + NS_ENSURE_ARG (aPageSetup); + NS_ENSURE_ARG (aPrinter); + + mPageSetup = (GtkPageSetup *) g_object_ref (aPageSetup); + mPrinter = (GtkPrinter *) g_object_ref (aPrinter); + +#if 0 + /* Compute the source file name */ + if (gtk_print_settings_get_print_to_file (mSettings)) { + /* FIXME: support gnome-VFS uris here! */ + const char *fileURI = gtk_print_settings_get (aSettings, "export-uri"); + NS_ENSURE_TRUE (fileURI, NS_ERROR_FAILURE); + + char *fileName = g_filename_from_uri (fileURI, NULL, NULL); + NS_ENSURE_TRUE (fileURI, NS_ERROR_FAILURE); + + mSourceFile.Assign (fileName); + g_free (fileName); + } else +#endif + { + char *base, *tmpName; + + /* FIXME: use pure glib here (g_mkstemp)! */ + base = g_build_filename (ephy_file_tmp_dir (), "print-XXXXXX", (const char *) NULL); + tmpName = ephy_file_tmp_filename (base, "ps"); + g_free (base); + + NS_ENSURE_TRUE (tmpName, NS_ERROR_FAILURE); + mSourceFile.Assign (tmpName); + g_free (tmpName); + + mSourceFileIsTemp = PR_TRUE; + } + + return NS_OK; +} + +/* static methods */ + +/* static */ GeckoPrintSession * +GeckoPrintSession::FromSettings (nsIPrintSettings *aSettings) +{ + nsresult rv; + nsCOMPtr<nsIPrintSession> session; + rv = aSettings->GetPrintSession (getter_AddRefs (session)); + NS_ENSURE_TRUE (NS_SUCCEEDED (rv) && session, nsnull); + + /* this is ok since the caller holds a ref to the settings which hold a ref to the session */ + nsIPrintSession *sessionPtr = session.get(); + return static_cast<GeckoPrintSession*>(sessionPtr); +} + +/* static functions */ + +static void +ReleaseSession (GeckoPrintSession *aSession) +{ + NS_RELEASE (aSession); +} + +static gboolean +ProgressDeleteCallback (GtkDialog *aDialog) +{ + gtk_dialog_response (aDialog, GTK_RESPONSE_DELETE_EVENT); + return TRUE; +} + +static void +ProgressResponseCallback (GtkDialog *aDialog, + int aResponse, + GeckoPrintSession *aSession) +{ + aSession->Cancel (); +} + +static gboolean +StartPrintIdleCallback (GeckoPrintSession *aSession) +{ + aSession->StartPrinting (); + + return FALSE; +} + +static void +JobStatusChangedCallback (GtkPrintJob *aJob, + GeckoPrintSession *aSession) +{ + aSession->JobStatusChanged (); +} + +static void +JobCompletedCallback (GtkPrintJob *aJob, + GeckoPrintSession *aSession, + GError *aError) +{ + aSession->JobDone (); + + if (aError) { + aSession->JobError (aError->message); + } +} + +/* Private methods */ + +void +GeckoPrintSession::SetProgress (PRInt32 aCurrent, + PRInt32 aMaximum) +{ + NS_ENSURE_TRUE (mProgressDialog, ); + + if (mCancelled) return; + + /* Mozilla is weird */ + if (aCurrent > aMaximum || (aCurrent == 100 && aMaximum == 100)) return; + + double fraction = 0.0; + if (aMaximum > 0 && aCurrent >= 0) { + char *text = g_strdup_printf (_("Page %d of %d"), aCurrent, aMaximum); + gtk_progress_bar_set_text (GTK_PROGRESS_BAR (mProgressBar), text); + g_free (text); + + fraction = (double) aCurrent / (double) aMaximum; + } + + gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (mProgressBar), CLAMP (fraction, 0.0, 1.0)); +} + +void +GeckoPrintSession::SetProgressText (const char *aText) +{ + NS_ENSURE_TRUE (mProgressDialog, ); + + gtk_progress_bar_set_text (GTK_PROGRESS_BAR (mProgressBar), aText); +} + +void +GeckoPrintSession::Cancel () +{ + SetProcessCanceledByUser (PR_TRUE); + + if (mProgressDialog) { + gtk_dialog_set_response_sensitive (GTK_DIALOG (mProgressDialog), + GTK_RESPONSE_CANCEL, FALSE); + + SetProgress (0, 0); + SetProgressText (_("Cancelling print")); /* FIXME text! */ + } + + if (mJob) { + /* FIXME: There's no way to cancel mJob! Bug #339323 */ + } +} + +void +GeckoPrintSession::StartPrinting () +{ + mStartPrintIdleID = 0; + + GError *error = NULL; + +#if 0 + /* FIXME: this could also be a print job to a file which was + * printed to a temp file and now needs to be uploaded to its + * final location with gnome-vfs. + */ + if (gtk_print_settings_get_print_to_file (mSettings)) return; +#endif + + NS_ENSURE_TRUE (mSettings && mPageSetup && mPrinter, ); + + mJob = gtk_print_job_new (mTitle.get (), + mPrinter, + mSettings, + mPageSetup); + if (!gtk_print_job_set_source_file (mJob, mSourceFile.get (), &error)) { + /* FIXME: error dialogue! */ + g_warning ("Couldn't set print job source: %s", error->message); + g_error_free (error); + + g_object_unref (mJob); + mJob = NULL; + + return; + } + + g_signal_connect (mJob, "status-changed", + G_CALLBACK (JobStatusChangedCallback), this); + + /* Keep us alive until the job is done! */ + NS_ADDREF_THIS (); + gtk_print_job_send (mJob, + (GtkPrintJobCompleteFunc) JobCompletedCallback, + this, + (GDestroyNotify) ReleaseSession); +} + +void +GeckoPrintSession::JobStatusChanged () +{ + NS_ENSURE_TRUE (mProgressDialog, ); + + LOG ("print session %p status changed %d\n", this, gtk_print_job_get_status (mJob)); + + /* FIXME: are any other status codes relevant info for the user? */ + if (gtk_print_job_get_status (mJob) == GTK_PRINT_STATUS_SENDING_DATA) { + gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (mProgressBar), 0.75); + /* FIXME text! */ + SetProgressText (_("Spooling...")); + } +} + +void +GeckoPrintSession::JobError (const char *aErrorMessage) +{ + LOG ("print job error: %s", aErrorMessage); + + /* FIXME better text */ + GtkWidget *dialog = gtk_message_dialog_new (NULL, + GtkDialogFlags (0), + GTK_MESSAGE_ERROR, + GTK_BUTTONS_OK, + _("Print error")); + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), + "%s", aErrorMessage); + g_signal_connect (dialog, "response", + G_CALLBACK (gtk_widget_destroy), NULL); + + gtk_widget_show (dialog); +} + +void +GeckoPrintSession::JobDone () +{ + NS_ENSURE_TRUE (mProgressDialog, ); + + mDone = PR_TRUE; + + gtk_widget_hide (mProgressDialog); + + DestroyJob (); +} + +void +GeckoPrintSession::DestroyJob () +{ + if (!mJob) return; + + g_signal_handlers_disconnect_by_func (mJob, (void*) JobStatusChangedCallback, this); + g_object_unref (mJob); + mJob = NULL; +} + +void +GeckoPrintSession::LaunchJobOnIdle () +{ + NS_ASSERTION (!mStartPrintIdleID, "Already started printing!"); + + /* Don't send the job to the printer if the user cancelled the print */ + if (mCancelled) return; + + /* Keep us alive until the idle handler runs! */ + NS_ADDREF_THIS (); + mStartPrintIdleID = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, + (GSourceFunc) StartPrintIdleCallback, + this, + (GDestroyNotify) ReleaseSession); +} + +/* XPCOM interfaces */ + +NS_IMPL_THREADSAFE_ISUPPORTS5 (GeckoPrintSession, + nsIPrintSession, + nsIWebProgressListener, + nsIPrintProgress, + nsIPrintProgressParams, + nsISupportsWeakReference) + +/* nsIPrintSession implementation */ + +/* nsIWebProgressListener implementation */ + +/* void onStateChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in unsigned long aStateFlags, in nsresult aStatus); */ +NS_IMETHODIMP +GeckoPrintSession::OnStateChange (nsIWebProgress *aWebProgress, + nsIRequest *aRequest, + PRUint32 aStateFlags, + nsresult aStatus) +{ + if (NS_SUCCEEDED (aStatus) && + aStateFlags & nsIWebProgressListener::STATE_IS_DOCUMENT) { + if (aStateFlags & nsIWebProgressListener::STATE_START) { + /* Printing starts now */ + SetProgress (0, 0); + } else if ((aStateFlags & nsIWebProgressListener::STATE_STOP)) { + /* Printing done, upload to printer */ + LaunchJobOnIdle (); + } + } + + 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 +GeckoPrintSession::OnProgressChange (nsIWebProgress *aWebProgress, + nsIRequest *aRequest, + PRInt32 aCurSelfProgress, + PRInt32 aMaxSelfProgress, + PRInt32 aCurTotalProgress, + PRInt32 aMaxTotalProgress) +{ + SetProgress (aCurTotalProgress, aMaxTotalProgress); + + return NS_OK; +} + +/* void onLocationChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsIURI aLocation); */ +NS_IMETHODIMP +GeckoPrintSession::OnLocationChange (nsIWebProgress *aWebProgress, + nsIRequest *aRequest, + nsIURI *aLocation) +{ + NS_ASSERTION (0, "OnLocationChange reached!"); + return NS_OK; +} + +/* void onStatusChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsresult aStatus, in wstring aMessage); */ +NS_IMETHODIMP +GeckoPrintSession::OnStatusChange (nsIWebProgress *aWebProgress, + nsIRequest *aRequest, + nsresult aStatus, + const PRUnichar *aMessage) +{ + NS_ASSERTION (0, "OnStatusChange reached!"); + return NS_OK; +} + +/* void onSecurityChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in unsigned long aState); */ +NS_IMETHODIMP +GeckoPrintSession::OnSecurityChange (nsIWebProgress *aWebProgress, + nsIRequest *aRequest, + PRUint32 aState) +{ + NS_ASSERTION (0, "OnSecurityChange reached!"); + return NS_OK; +} + +/* nsIPrintProgress implementation */ + +/* void openProgressDialog (in nsIDOMWindowInternal parent, in string dialogURL, in nsISupports parameters, in nsIObserver openDialogObserver, out boolean notifyOnOpen); */ +NS_IMETHODIMP +GeckoPrintSession::OpenProgressDialog (nsIDOMWindowInternal *aParent, + const char *aDialogURL, + nsISupports *aParameters, + nsIObserver *aOpenDialogObserver, + PRBool *_notifyOnOpen) +{ + NS_ENSURE_STATE (!mProgressDialog); + + nsCOMPtr<nsIDOMWindow> domWindow (do_QueryInterface (aParent)); + GtkWidget *parent = EphyUtils::FindGtkParent (domWindow); + + GtkWidget *vbox, *hbox, *image; + + mProgressDialog = gtk_dialog_new (); + GtkDialog *dialog = GTK_DIALOG (mProgressDialog); + + gtk_dialog_add_button (dialog, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); + + g_signal_connect (dialog, "delete-event", + G_CALLBACK (ProgressDeleteCallback), NULL); + g_signal_connect (dialog, "response", + G_CALLBACK (ProgressResponseCallback), this); + + /* FIXME do we need transient? initially on top should suffice */ + gtk_window_set_transient_for (GTK_WINDOW (dialog), + GTK_WINDOW (parent)); + + gtk_dialog_set_has_separator (dialog, FALSE); + gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE); + gtk_container_set_border_width (GTK_CONTAINER (dialog), 5); + gtk_box_set_spacing (GTK_BOX (dialog->vbox), 14); /* 2 * 5 + 14 = 24 */ + gtk_box_set_spacing (GTK_BOX (dialog->action_area), 5); + + hbox = gtk_hbox_new (FALSE, 12); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); + gtk_container_add (GTK_CONTAINER (dialog->vbox), hbox); + + image = gtk_image_new_from_stock (GTK_STOCK_PRINT, GTK_ICON_SIZE_DIALOG); + gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0.0); + gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0); + + vbox = gtk_vbox_new (FALSE, 12); + gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); + + mTitleLabel = gtk_label_new (NULL); + gtk_label_set_line_wrap (GTK_LABEL (mTitleLabel), TRUE); + gtk_misc_set_alignment (GTK_MISC (mTitleLabel), 0.0, 0.0); + gtk_box_pack_start (GTK_BOX (vbox), mTitleLabel, FALSE, FALSE, 0); + + mProgressBar = gtk_progress_bar_new (); + gtk_box_pack_start (GTK_BOX (vbox), mProgressBar, FALSE, FALSE, 0); + + gtk_widget_show_all (hbox); + gtk_window_present (GTK_WINDOW (dialog)); + + *_notifyOnOpen = PR_FALSE; + + return NS_OK; +} + +/* void closeProgressDialog (in boolean forceClose); */ +NS_IMETHODIMP +GeckoPrintSession::CloseProgressDialog (PRBool forceClose) +{ + return NS_OK; +} + +/* void registerListener (in nsIWebProgressListener listener); */ +NS_IMETHODIMP +GeckoPrintSession::RegisterListener (nsIWebProgressListener *listener) +{ + return NS_OK; +} + +/* void unregisterListener (in nsIWebProgressListener listener); */ +NS_IMETHODIMP +GeckoPrintSession::UnregisterListener (nsIWebProgressListener *listener) +{ + return NS_OK; +} + +/* void doneIniting (); */ +NS_IMETHODIMP +GeckoPrintSession::DoneIniting() +{ + return NS_OK; +} + +/* nsIPrompt getPrompter (); */ +NS_IMETHODIMP +GeckoPrintSession::GetPrompter (nsIPrompt **_retval) +{ + g_return_val_if_reached (NS_ERROR_NOT_IMPLEMENTED); + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* attribute boolean processCanceledByUser; */ +NS_IMETHODIMP +GeckoPrintSession::GetProcessCanceledByUser (PRBool *aProcessCanceledByUser) +{ + *aProcessCanceledByUser = mCancelled; + return NS_OK; +} + +NS_IMETHODIMP +GeckoPrintSession::SetProcessCanceledByUser (PRBool aProcessCanceledByUser) +{ + mCancelled = aProcessCanceledByUser; + if (mPrintSettings) { + mPrintSettings->SetIsCancelled (aProcessCanceledByUser); + } + + return NS_OK; +} + +/* nsIPrintProgressParams implementation */ + +/* attribute wstring docTitle; */ +NS_IMETHODIMP +GeckoPrintSession::GetDocTitle (PRUnichar * *aDocTitle) +{ + g_return_val_if_reached (NS_ERROR_NOT_IMPLEMENTED); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +GeckoPrintSession::SetDocTitle (const PRUnichar * aDocTitle) +{ + NS_ENSURE_STATE (mProgressDialog); + + char *converted = EphyUtils::ConvertUTF16toUTF8 (aDocTitle, MAX_STRING_LENGTH); + if (converted) { + mTitle.Assign (converted); + + char *title = g_strdup_printf (_("Printing “%s”"), converted); + gtk_window_set_title (GTK_WINDOW (mProgressDialog), title); + gtk_label_set_text (GTK_LABEL (mTitleLabel), title); + g_free (converted); + g_free (title); + } + return NS_OK; +} + +/* attribute wstring docURL; */ +NS_IMETHODIMP +GeckoPrintSession::GetDocURL (PRUnichar * *aDocURL) +{ + g_return_val_if_reached (NS_ERROR_NOT_IMPLEMENTED); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +GeckoPrintSession::SetDocURL (const PRUnichar * aDocURL) +{ +#if 0 + NS_ENSURE_STATE (mJob); + + char *converted = EphyUtils::ConvertUTF16toUTF8 (aDocTitle, MAX_STRING_LENGTH); + if (converted) { + g_free (converted); + } +#endif + return NS_OK; +} diff --git a/embed/xulrunner/embed/GeckoPrintSession.h b/embed/xulrunner/embed/GeckoPrintSession.h new file mode 100644 index 000000000..027f01e23 --- /dev/null +++ b/embed/xulrunner/embed/GeckoPrintSession.h @@ -0,0 +1,94 @@ +/* + * Copyright © 2006 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#ifndef GECKO_PRINT_SESSION_H +#define GECKO_PRINT_SESSION_H + +#include <nsCOMPtr.h> +#include <nsIPrintSession.h> +#include <nsIWebProgressListener.h> +#include <nsIPrintProgress.h> +#include <nsIPrintProgressParams.h> +#include <nsWeakReference.h> + +#include <gtk/gtkwidget.h> +#include <gtk/gtkprintjob.h> +#include <gtk/gtkprinter.h> +#include <gtk/gtkprintjob.h> + +class nsIPrintSettings; +class nsIDOMWindow; + +/* 0940c973-97e7-476f-a612-4ed9473a0b36 */ +#define GECKO_PRINT_SESSION_IID \ +{ 0x0940c973, 0x97e7, 0x476f, \ + { 0xa6, 0x12, 0x4e, 0xd9, 0x47, 0x3a, 0x0b, 0x36 } } + +#define GECKO_PRINT_SESSION_CLASSNAME "Gecko Print Session" + +class GeckoPrintSession : public nsIPrintSession, + public nsIPrintProgress, + public nsIPrintProgressParams, + public nsSupportsWeakReference +{ + public: + GeckoPrintSession(); + virtual ~GeckoPrintSession(); + + NS_DECL_ISUPPORTS + NS_DECL_NSIPRINTSESSION + NS_DECL_NSIWEBPROGRESSLISTENER + NS_DECL_NSIPRINTPROGRESS + NS_DECL_NSIPRINTPROGRESSPARAMS + + nsresult SetSettings (nsIPrintSettings *, GtkPrintSettings*, GtkPageSetup*, GtkPrinter*); + void GetSourceFile (nsACString&); + + static GeckoPrintSession *FromSettings (nsIPrintSettings *); + + void Cancel (); + void StartPrinting (); + void JobStatusChanged (); + void JobDone (); + void JobError (const char *); + + private: + nsCOMPtr<nsIPrintSettings> mPrintSettings; + GtkPrintSettings *mSettings; + GtkPageSetup *mPageSetup; + GtkPrinter *mPrinter; + GtkPrintJob *mJob; + GtkWidget *mProgressDialog; + GtkWidget *mTitleLabel; + GtkWidget *mProgressBar; + nsCString mSourceFile; + nsCString mTitle; + guint mStartPrintIdleID; + PRPackedBool mSourceFileIsTemp; + PRPackedBool mDone; + PRPackedBool mCancelled; + + void SetProgress (PRInt32, PRInt32); + void SetProgressText (const char *); + void LaunchJobOnIdle (); + void DestroyJob (); +}; + +#endif /* GECKO_PRINT_SESSION_H */ diff --git a/embed/xulrunner/embed/GeckoSpellCheckEngine.cpp b/embed/xulrunner/embed/GeckoSpellCheckEngine.cpp new file mode 100644 index 000000000..59ab5df2d --- /dev/null +++ b/embed/xulrunner/embed/GeckoSpellCheckEngine.cpp @@ -0,0 +1,205 @@ +/* + * Copyright © 2006 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#include "mozilla-config.h" +#include "config.h" + +//#include <bonobo.h> +#include <stdio.h> +#include <stdlib.h> + +#include <nsStringAPI.h> + +#include <mozIPersonalDictionary.h> +#include <nsMemory.h> + +#include "ephy-debug.h" + +#include "GeckoSpellCheckEngine.h" + +#ifndef HAVE_GECKO_1_9 +#define ToNewUnicode NS_StringCloneData +#endif + +GeckoSpellCheckEngine::GeckoSpellCheckEngine () +{ + LOG ("GeckoSpellCheckEngine ctor [%p]", (void*) this); + mSpeller = ephy_spell_check_get_default (); +} + +GeckoSpellCheckEngine::~GeckoSpellCheckEngine () +{ + LOG ("GeckoSpellCheckEngine dtor [%p]", (void*) this); + g_object_unref (mSpeller); +} + +NS_IMPL_ISUPPORTS1 (GeckoSpellCheckEngine, + mozISpellCheckingEngine) + +/* nsISpellCheckEngine implementation */ + +/* attribute wstring dictionary; */ +NS_IMETHODIMP GeckoSpellCheckEngine::GetDictionary (PRUnichar * *aDictionary) +{ + /* Gets the identifier of the current dictionary */ + char *code = ephy_spell_check_get_language (mSpeller); + if (!code) { + return NS_ERROR_FAILURE; + } + + *aDictionary = ToNewUnicode (NS_ConvertUTF8toUTF16 (code)); + g_free (code); + + return NS_OK; +} + +NS_IMETHODIMP GeckoSpellCheckEngine::SetDictionary (const PRUnichar * aDictionary) +{ + return NS_OK; +} + +/* readonly attribute wstring language; */ +NS_IMETHODIMP GeckoSpellCheckEngine::GetLanguage (PRUnichar * *aLanguage) +{ + /* Gets the identifier of the current dictionary */ + char *code = ephy_spell_check_get_language (mSpeller); + if (!code) { + return NS_ERROR_FAILURE; + } + + *aLanguage = ToNewUnicode (NS_ConvertUTF8toUTF16 (code)); + g_free (code); + + return NS_OK; +} + +/* readonly attribute boolean providesPersonalDictionary; */ +NS_IMETHODIMP GeckoSpellCheckEngine::GetProvidesPersonalDictionary (PRBool *aProvidesPersonalDictionary) +{ + *aProvidesPersonalDictionary = PR_FALSE; + return NS_OK; +} + +/* readonly attribute boolean providesWordUtils; */ +NS_IMETHODIMP GeckoSpellCheckEngine::GetProvidesWordUtils (PRBool *aProvidesWordUtils) +{ + *aProvidesWordUtils = PR_FALSE; + return NS_OK; +} + +/* readonly attribute wstring name; */ +NS_IMETHODIMP GeckoSpellCheckEngine::GetName (PRUnichar * *aName) +{ + /* It's fine to leave this unimplemented */ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* readonly attribute wstring copyright; */ +NS_IMETHODIMP GeckoSpellCheckEngine::GetCopyright (PRUnichar * *aCopyright) +{ + /* It's fine to leave this unimplemented */ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* attribute mozIPersonalDictionary personalDictionary; */ +NS_IMETHODIMP GeckoSpellCheckEngine::GetPersonalDictionary (mozIPersonalDictionary * *aPersonalDictionary) +{ + NS_IF_ADDREF (*aPersonalDictionary = mPersonalDictionary); + return NS_OK; +} + +NS_IMETHODIMP GeckoSpellCheckEngine::SetPersonalDictionary (mozIPersonalDictionary * aPersonalDictionary) +{ + mPersonalDictionary = aPersonalDictionary; + return NS_OK; +} + +/* void getDictionaryList ([array, size_is (count)] out wstring dictionaries, out PRUint32 count); */ +NS_IMETHODIMP +GeckoSpellCheckEngine::GetDictionaryList (PRUnichar ***_dictionaries, + PRUint32 *_count) +{ + *_count = 1; + *_dictionaries = (PRUnichar **)nsMemory::Alloc(sizeof(PRUnichar *)); // only one entry + *_dictionaries[0] = ToNewUnicode (NS_LITERAL_STRING ("en")); + return NS_OK; +} + +/* boolean check (in wstring word); */ +NS_IMETHODIMP GeckoSpellCheckEngine::Check (const PRUnichar *word, + PRBool *_retval) +{ + NS_ENSURE_STATE (mSpeller); + NS_ENSURE_ARG (word); + + NS_ConvertUTF16toUTF8 converted (word); + + gboolean correct = FALSE; + if (!ephy_spell_check_check_word (mSpeller, + converted.get (), + converted.Length (), + &correct)) + return NS_ERROR_FAILURE; + + *_retval = correct != FALSE; + + return NS_OK; +} + +/* void suggest (in wstring word, [array, size_is (count)] out wstring suggestions, out PRUint32 count); */ +NS_IMETHODIMP GeckoSpellCheckEngine::Suggest (const PRUnichar *word, + PRUnichar ***_suggestions, + PRUint32 *_count) +{ +#if 0 + NS_ENSURE_STATE (mSpeller); + NS_ENSURE_ARG (word); + + NS_ConvertUTF16toUTF8 converted (word); + + gsize count; + char **suggestions = ephy_spell_check_get_suggestions (mSpeller, + converted.get (), + converted.Length (), + &count); + + *_count = count; + *_suggestions = nsnull; + + PRUnichar **array = nsnull; + if (count > 0) { + NS_ASSERTION (suggestions, "Count > 0 but suggestions are NULL?"); + array = (PRUnichar **) nsMemory::Alloc (count * sizeof (PRUnichar *)); + if (array) { + *_suggestions = array; + + for (gsize i = 0; i < count; ++i) { + NS_ConvertUTF8toUTF16 sugg (suggestions[i]); + array[i] = ToNewUnicode (sugg); + } + } + + ephy_spell_check_free_suggestions (mSpeller, suggestions); + } + + return array ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +#endif + return NS_ERROR_NOT_IMPLEMENTED; +} diff --git a/embed/xulrunner/embed/GeckoSpellCheckEngine.h b/embed/xulrunner/embed/GeckoSpellCheckEngine.h new file mode 100644 index 000000000..b70f6c970 --- /dev/null +++ b/embed/xulrunner/embed/GeckoSpellCheckEngine.h @@ -0,0 +1,52 @@ +/* + * Copyright © 2006 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#ifndef GECKO_SPELL_CHECK_ENGINE_H +#define GECKO_SPELL_CHECK_ENGINE_H + +#include <nsCOMPtr.h> +#include <mozISpellCheckingEngine.h> + +#include "ephy-spell-check.h" + +class mozIPersonalDictionary; + +/* 26948b8b-d136-4a78-a9c5-3a145812b649 */ +#define GECKO_SPELL_CHECK_ENGINE_IID \ +{ 0x26948b8b, 0xd136, 0x4a78, { 0xa9, 0xc5, 0x3a, 0x14, 0x58, 0x12, 0xb6, 0x49 } } + +#define GECKO_SPELL_CHECK_ENGINE_CONTRACTID "@mozilla.org/spellchecker/myspell;1" +#define GECKO_SPELL_CHECK_ENGINE_CLASSNAME "Gecko Print Settings" + +class GeckoSpellCheckEngine : public mozISpellCheckingEngine +{ + public: + GeckoSpellCheckEngine(); + virtual ~GeckoSpellCheckEngine(); + + NS_DECL_ISUPPORTS + NS_DECL_MOZISPELLCHECKINGENGINE + + private: + nsCOMPtr<mozIPersonalDictionary> mPersonalDictionary; + EphySpellCheck *mSpeller; +}; + +#endif /* GECKO_SPELL_CHECK_ENGINE_H */ diff --git a/embed/xulrunner/embed/GlobalHistory.cpp b/embed/xulrunner/embed/GlobalHistory.cpp new file mode 100644 index 000000000..efcda79f9 --- /dev/null +++ b/embed/xulrunner/embed/GlobalHistory.cpp @@ -0,0 +1,225 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright © 2001, 2004 Philip Langdale + * Copyright © 2004 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#include "mozilla-config.h" +#include "config.h" + +#include <nsStringAPI.h> + +#include <nsIURI.h> + +#include "ephy-embed-shell.h" + +#include "GlobalHistory.h" + + +#define MAX_TITLE_LENGTH 2048 +#define MAX_URL_LENGTH 16384 + +#ifdef HAVE_NSIGLOBALHISTORY3_H +NS_IMPL_ISUPPORTS2 (MozGlobalHistory, nsIGlobalHistory2, nsIGlobalHistory3) +#else +NS_IMPL_ISUPPORTS1 (MozGlobalHistory, nsIGlobalHistory2) +#endif /* HAVE_NSIGLOBALHISTORY3_H */ + +MozGlobalHistory::MozGlobalHistory () +{ + mGlobalHistory = EPHY_HISTORY (ephy_embed_shell_get_global_history (embed_shell)); + + mHistoryListener = new EphyHistoryListener (); + mHistoryListener->Init (mGlobalHistory); +} + +MozGlobalHistory::~MozGlobalHistory () +{ +} + +/* void addURI (in nsIURI aURI, in boolean aRedirect, in boolean aToplevel, in nsIURI aReferrer); */ +NS_IMETHODIMP MozGlobalHistory::AddURI(nsIURI *aURI, + PRBool aRedirect, + PRBool aToplevel, + nsIURI *aReferrer) +{ + nsresult rv; + + NS_ENSURE_ARG (aURI); + + // filter out unwanted URIs such as chrome: etc + // The model is really if we don't know differently then add which basically + // means we are suppose to try all the things we know not to allow in and + // then if we don't bail go on and allow it in. But here lets compare + // against the most common case we know to allow in and go on and say yes + // to it. + + PRBool isHTTP = PR_FALSE, isHTTPS = PR_FALSE; + rv = aURI->SchemeIs("http", &isHTTP); + rv |= aURI->SchemeIs("https", &isHTTPS); + NS_ENSURE_SUCCESS (rv, NS_ERROR_FAILURE); + + if (!isHTTP && !isHTTPS) + { + static const char *schemes[] = { "javascript", + "data", + "about", + "chrome", + "resource", + "view-source" }; + + for (PRUint32 i = 0; i < G_N_ELEMENTS (schemes); ++i) + { + PRBool result = PR_FALSE; + if (NS_SUCCEEDED (aURI->SchemeIs (schemes[i], &result)) && result) + { + return NS_OK; + } + } + } + + nsCString spec; + rv = aURI->GetSpec(spec); + NS_ENSURE_TRUE (NS_SUCCEEDED(rv) && spec.Length(), rv); + + if (spec.Length () > MAX_URL_LENGTH) return NS_OK; + + ephy_history_add_page (mGlobalHistory, spec.get(), aRedirect, aToplevel); + + return NS_OK; +} + +/* boolean isVisited (in nsIURI aURI); */ +NS_IMETHODIMP MozGlobalHistory::IsVisited(nsIURI *aURI, + PRBool *_retval) +{ + NS_ENSURE_ARG (aURI); + + *_retval = PR_FALSE; + + nsCString spec; + aURI->GetSpec(spec); + + if (spec.Length () > MAX_URL_LENGTH) return NS_OK; + + *_retval = ephy_history_is_page_visited (mGlobalHistory, spec.get()); + + return NS_OK; +} + +/* void setPageTitle (in nsIURI aURI, in AString aTitle); */ +NS_IMETHODIMP MozGlobalHistory::SetPageTitle(nsIURI *aURI, + const nsAString & aTitle) +{ + NS_ENSURE_ARG (aURI); + + nsCString spec; + aURI->GetSpec(spec); + + if (spec.Length () > MAX_URL_LENGTH) return NS_OK; + + nsString uTitle (aTitle); + + /* This depends on the assumption that + * typeof(PRUnichar) == typeof (gunichar2) == uint16, + * which should be pretty safe. + */ + glong n_read = 0, n_written = 0; + char *converted = g_utf16_to_utf8 ((gunichar2*) uTitle.get(), MAX_TITLE_LENGTH, + &n_read, &n_written, NULL); + /* FIXME loop from the end while !g_unichar_isspace (char)? */ + if (converted == NULL) return NS_OK; + + ephy_history_set_page_title (mGlobalHistory, spec.get(), converted); + + g_free (converted); + + return NS_OK; +} + +#ifdef HAVE_NSIGLOBALHISTORY3_H + +#ifdef HAVE_GECKO_1_9 + +/* unsigned long getURIGeckoFlags(in nsIURI aURI); */ +NS_IMETHODIMP +MozGlobalHistory::GetURIGeckoFlags(nsIURI *aURI, + PRUint32* aFlags) +{ + *aFlags = 0; + + nsCString spec; + aURI->GetSpec(spec); + + if (spec.Length () > MAX_URL_LENGTH) return NS_OK; + + EphyNode *page = ephy_history_get_page (mGlobalHistory, spec.get()); + + GValue value = { 0, }; + if (page != NULL && + ephy_node_get_property (page, EPHY_NODE_PAGE_PROP_GECKO_FLAGS, &value)) + { + *aFlags = (PRUint32) (gulong) g_value_get_long (&value); + g_value_unset (&value); + + return NS_OK; + } + + return NS_ERROR_FAILURE; +} + +/* void setURIGeckoFlags(in nsIURI aURI, in unsigned long aFlags); */ +NS_IMETHODIMP +MozGlobalHistory::SetURIGeckoFlags(nsIURI *aURI, + PRUint32 aFlags) +{ + nsCString spec; + aURI->GetSpec(spec); + + if (spec.Length () > MAX_URL_LENGTH) return NS_OK; + + EphyNode *page = ephy_history_get_page (mGlobalHistory, spec.get()); + if (page != NULL) + { + ephy_node_set_property_long (page, + EPHY_NODE_PAGE_PROP_GECKO_FLAGS, + aFlags); + return NS_OK; + } + + return NS_ERROR_FAILURE; +} + +#endif /* HAVE_GECKO_1_9 */ + +/* void addDocumentRedirect (in nsIChannel + aOldChannel, + in nsIChannel aNewChannel, + in PRInt32 aFlags, + in boolean aTopLevel); */ +NS_IMETHODIMP +MozGlobalHistory::AddDocumentRedirect(nsIChannel *aOldChannel, + nsIChannel *aNewChannel, + PRInt32 aFlags, + PRBool aTopLevel) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +#endif /* HAVE_NSIGLOBALHISTORY3_H */ diff --git a/embed/xulrunner/embed/GlobalHistory.h b/embed/xulrunner/embed/GlobalHistory.h new file mode 100644 index 000000000..8397874a0 --- /dev/null +++ b/embed/xulrunner/embed/GlobalHistory.h @@ -0,0 +1,68 @@ +/* + * Copyright © 2001, 2004 Philip Langdale + * Copyright © 2004 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#ifndef EPHY_GLOBAL_HISTORY_H +#define EPHY_GLOBAL_HISTORY_H + +#ifdef HAVE_NSIGLOBALHISTORY3_H +#include <nsIGlobalHistory3.h> +#else +#include <nsIGlobalHistory2.h> +#endif /* HAVE_NSIGLOBALHISTORY3_H */ + +#include <nsAutoPtr.h> +#include <nsCOMPtr.h> + +#include "ephy-history.h" + +#include "EphyHistoryListener.h" + +#define EPHY_GLOBALHISTORY_CLASSNAME "Epiphany Global History Implementation" + +#define EPHY_GLOBALHISTORY_CID \ +{ 0xbe0c42c1, \ + 0x39d4, \ + 0x4271, \ + { 0xb7, 0x9e, 0xf7, 0xaa, 0x49, 0xeb, 0x6a, 0x15} \ +} + +#ifdef HAVE_NSIGLOBALHISTORY3_H +class MozGlobalHistory: public nsIGlobalHistory3 +#else +class MozGlobalHistory: public nsIGlobalHistory2 +#endif /* HAVE_NSIGLOBALHISTORY3_H */ +{ + public: + MozGlobalHistory (); + virtual ~MozGlobalHistory(); + + NS_DECL_ISUPPORTS + NS_DECL_NSIGLOBALHISTORY2 +#ifdef HAVE_NSIGLOBALHISTORY3_H + NS_DECL_NSIGLOBALHISTORY3 +#endif /* HAVE_NSIGLOBALHISTORY3_H */ + + private: + EphyHistory *mGlobalHistory; + nsRefPtr<EphyHistoryListener> mHistoryListener; +}; + +#endif /* EPHY_GLOBAL_HISTORY_H */ diff --git a/embed/xulrunner/embed/GtkNSSClientAuthDialogs.cpp b/embed/xulrunner/embed/GtkNSSClientAuthDialogs.cpp new file mode 100644 index 000000000..410827166 --- /dev/null +++ b/embed/xulrunner/embed/GtkNSSClientAuthDialogs.cpp @@ -0,0 +1,284 @@ +/* + * GtkNSSClientAuthDialogs.cpp + * + * Copyright © 2003 Crispin Flowerday <gnome@flowerday.cx> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#include "mozilla-config.h" +#include "config.h" + +#include <glib/gi18n.h> +#include <gtk/gtkcelllayout.h> +#include <gtk/gtkcellrenderer.h> +#include <gtk/gtkcellrenderertext.h> +#include <gtk/gtkcombobox.h> +#include <gtk/gtkdialog.h> +#include <gtk/gtkexpander.h> +#include <gtk/gtkhbox.h> +#include <gtk/gtkimage.h> +#include <gtk/gtklabel.h> +#include <gtk/gtkliststore.h> +#include <gtk/gtkmenuitem.h> +#include <gtk/gtkoptionmenu.h> +#include <gtk/gtkprogressbar.h> +#include <gtk/gtkscrolledwindow.h> +#include <gtk/gtkstock.h> +#include <gtk/gtktextbuffer.h> +#include <gtk/gtktextview.h> +#include <gtk/gtktogglebutton.h> +#include <gtk/gtktreemodel.h> +#include <gtk/gtkvbox.h> + +#include <nsStringAPI.h> + +#include <nsIDOMWindow.h> +#include <nsIInterfaceRequestor.h> +#include <nsIInterfaceRequestorUtils.h> +#include <nsIServiceManager.h> + +#include "ephy-debug.h" +#include "ephy-gui.h" +#include "ephy-state.h" +#include "ephy-stock-icons.h" + +#include "AutoJSContextStack.h" +#include "AutoWindowModalState.h" +#include "EphyUtils.h" + +#include "GtkNSSClientAuthDialogs.h" + +GtkNSSClientAuthDialogs::GtkNSSClientAuthDialogs() +{ + LOG ("GtkNSSClientAuthDialogs ctor (%p)", this); +} + + +GtkNSSClientAuthDialogs::~GtkNSSClientAuthDialogs() +{ + LOG ("GtkNSSClientAuthDialogs dtor (%p)", this); +} + +NS_IMPL_THREADSAFE_ISUPPORTS1 (GtkNSSClientAuthDialogs, + nsIClientAuthDialogs) + +/** + * Indent a widget according the HIG + * + * @returns: The new indented widget + */ +static GtkWidget* +higgy_indent_widget (GtkWidget *widget) +{ + GtkWidget *hbox; + GtkWidget *label; + + hbox = gtk_hbox_new (FALSE, 6); + + label = gtk_label_new (""); + gtk_box_pack_start (GTK_BOX(hbox), label, FALSE, TRUE, 6); + gtk_widget_show (label); + + gtk_box_pack_start (GTK_BOX(hbox), widget, TRUE, TRUE, 0); + + return hbox; +} + +static void +combo_changed_cb (GtkComboBox *combo, GtkTextView *textview) +{ + GtkTreeModel *model; + GtkTreeIter iter; + GtkTextBuffer *buffer; + int index; + + model = gtk_combo_box_get_model (combo); + index = gtk_combo_box_get_active (combo); + buffer = gtk_text_view_get_buffer (textview); + + if (gtk_tree_model_iter_nth_child (model, &iter, NULL, index)) + { + char *text; + + gtk_tree_model_get (model, &iter, 1, &text, -1); + + gtk_text_buffer_set_text (buffer, text, -1); + + g_free (text); + } + else + { + gtk_text_buffer_set_text (buffer, "", -1); + } +} + +NS_IMETHODIMP +GtkNSSClientAuthDialogs::ChooseCertificate (nsIInterfaceRequestor *ctx, + const PRUnichar *cn, + const PRUnichar *organization, + const PRUnichar *issuer, + const PRUnichar **certNickList, + const PRUnichar **certDetailsList, + PRUint32 count, PRInt32 *selectedIndex, + PRBool *canceled) +{ + GtkWidget *dialog, *label, *vbox, *textview; + GtkWidget *details, *expander, *hbox, *image; + GtkWidget *combo; + GtkListStore *store; + GtkTreeIter iter; + GtkCellRenderer *renderer; + char *msg, *markup_text; + PRUint32 i; + + nsresult rv; + AutoJSContextStack stack; + rv = stack.Init (); + if (NS_FAILED (rv)) return rv; + + nsCOMPtr<nsIDOMWindow> parent (do_GetInterface (ctx)); + GtkWindow *gparent = GTK_WINDOW (EphyUtils::FindGtkParent (parent)); + + AutoWindowModalState modalState (parent); + + dialog = gtk_dialog_new_with_buttons ("", + GTK_WINDOW (gparent), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_STOCK_CANCEL, + GTK_RESPONSE_CANCEL, + _("_Select Certificate"), + GTK_RESPONSE_OK, + (char *) NULL); + + if (gparent) + { + gtk_window_group_add_window (ephy_gui_ensure_window_group (gparent), + GTK_WINDOW (dialog)); + } + + gtk_window_set_icon_name (GTK_WINDOW (dialog), EPHY_STOCK_EPHY); + + gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE); + gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE); + gtk_container_set_border_width (GTK_CONTAINER (dialog), 5); + gtk_box_set_spacing (GTK_BOX(GTK_DIALOG (dialog)->vbox), 14); /* 24 = 2 * 5 + 14 */ + gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK); + + hbox = gtk_hbox_new (FALSE, 12); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox, FALSE, FALSE, 0); + gtk_widget_show (hbox); + + 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_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0); + gtk_widget_show (image); + + vbox = gtk_vbox_new (FALSE, 12); + gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); + gtk_widget_show (vbox); + + label = gtk_label_new (NULL); + gtk_label_set_use_markup (GTK_LABEL (label), TRUE); + gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); + gtk_label_set_selectable (GTK_LABEL (label), TRUE); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.0); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); + + msg = g_markup_printf_escaped (_("Choose a certificate to present as identification to “%s”."), + NS_ConvertUTF16toUTF8 (cn).get()); + markup_text = g_strdup_printf ("<span weight=\"bold\" size=\"larger\">%s</span>\n\n%s", + _("Select a certificate to identify yourself."), + msg); + gtk_label_set_markup (GTK_LABEL (label), markup_text); + g_free (msg); + g_free (markup_text); + + /* Create and populate the combo */ + store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING); + for (i = 0; i < count; i++) + { + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, + 0, NS_ConvertUTF16toUTF8 (certNickList[i]).get(), + 1, NS_ConvertUTF16toUTF8 (certDetailsList[i]).get(), + -1); + } + + combo = gtk_combo_box_new_with_model (GTK_TREE_MODEL (store)); + g_object_unref (store); + + renderer = gtk_cell_renderer_text_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, TRUE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), renderer, + "text", 0, + (char *) NULL); + + gtk_widget_show (combo); + gtk_box_pack_start (GTK_BOX (vbox), combo, FALSE, TRUE, 0); + + expander = gtk_expander_new_with_mnemonic (_("Certificate _Details")); + ephy_state_add_expander (GTK_WIDGET (expander), "client-auth-dialog-expander", FALSE); + + gtk_widget_show (expander); + gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), expander, FALSE, FALSE, 0); + + /* Create the text box */ + textview = gtk_text_view_new (); + gtk_text_view_set_editable (GTK_TEXT_VIEW (textview), FALSE); + gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (textview), FALSE); + gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (textview), GTK_WRAP_WORD); + gtk_widget_set_size_request (GTK_WIDGET (textview), -1, 100); + gtk_widget_show (textview); + + details = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (details), GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (details), GTK_SHADOW_IN); + gtk_container_add (GTK_CONTAINER (details), textview); + gtk_widget_show (details); + + details = higgy_indent_widget (details); + gtk_container_set_border_width (GTK_CONTAINER (details), 5); + gtk_widget_show (details); + + gtk_container_add (GTK_CONTAINER (expander), details); + + g_signal_connect (G_OBJECT (combo), "changed", + G_CALLBACK (combo_changed_cb), + textview); + + gtk_combo_box_set_active (GTK_COMBO_BOX (combo), 0); + + /* run the dialog */ + int res = gtk_dialog_run (GTK_DIALOG (dialog)); + if (res == GTK_RESPONSE_OK) + { + *canceled = PR_FALSE; + *selectedIndex = gtk_combo_box_get_active (GTK_COMBO_BOX (combo)); + } + else + { + *canceled = PR_TRUE; + } + + gtk_widget_destroy (dialog); + return NS_OK; +} diff --git a/embed/xulrunner/embed/GtkNSSClientAuthDialogs.h b/embed/xulrunner/embed/GtkNSSClientAuthDialogs.h new file mode 100644 index 000000000..0aa582700 --- /dev/null +++ b/embed/xulrunner/embed/GtkNSSClientAuthDialogs.h @@ -0,0 +1,45 @@ +/* + * Copyright © 2003 Crispin Flowerday <gnome@flowerday.cx> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * + * $Id$ + */ + +#ifndef GTKNSSCLIENTAUTHDIALOGS_H +#define GTKNSSCLIENTAUTHDIALOGS_H 1 + +#include <nsIClientAuthDialogs.h> + +// 55b3837e-dbde-4c24-9247-f328e3012485 +#define GTK_NSSCLIENTAUTHDIALOGS_CID \ + {0x55b3837e, 0xdbde, 0x4c24, {0x92, 0x47, 0xf3, 0x28, 0xe3, 0x01, 0x24, 0x85}} + +#define GTK_NSSCLIENTAUTHDIALOGS_CLASSNAME "Gtk NSS Client Auth Dialogs" + +class GtkNSSClientAuthDialogs +: public nsIClientAuthDialogs +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSICLIENTAUTHDIALOGS + + GtkNSSClientAuthDialogs(); + virtual ~GtkNSSClientAuthDialogs(); +}; + + +#endif /* GTKNSSCLIENTAUTHDIALOGS_H */ diff --git a/embed/xulrunner/embed/GtkNSSDialogs.cpp b/embed/xulrunner/embed/GtkNSSDialogs.cpp new file mode 100644 index 000000000..25b99d141 --- /dev/null +++ b/embed/xulrunner/embed/GtkNSSDialogs.cpp @@ -0,0 +1,1694 @@ +/* + * Copyright © 2003 Crispin Flowerday <gnome@flowerday.cx> + * Copyright © 2006 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +/* + * This file provides Gtk implementations of the mozilla Certificate dialogs + * such as the ones displayed when connecting to a site with a self-signed + * or expired certificate. + */ + +#include "mozilla-config.h" +#include "config.h" + +#include <time.h> + +#include <glib/gi18n.h> +#include <gtk/gtkalignment.h> +#include <gtk/gtkbutton.h> +#include <gtk/gtkcellrenderertext.h> +#include <gtk/gtkcheckbutton.h> +#include <gtk/gtkdialog.h> +#include <gtk/gtkeditable.h> +#include <gtk/gtkentry.h> +#include <gtk/gtkhbox.h> +#include <gtk/gtkimage.h> +#include <gtk/gtklabel.h> +#include <gtk/gtkmessagedialog.h> +#include <gtk/gtkprogressbar.h> +#include <gtk/gtksizegroup.h> +#include <gtk/gtkstock.h> +#include <gtk/gtktable.h> +#include <gtk/gtktextbuffer.h> +#include <gtk/gtktextview.h> +#include <gtk/gtktogglebutton.h> +#include <gtk/gtktreeselection.h> +#include <gtk/gtktreestore.h> +#include <gtk/gtktreeview.h> +#include <gtk/gtkvbox.h> +#include <gtk/gtkcombobox.h> +#include <gconf/gconf-client.h> +#include <glade/glade-xml.h> + +#include <nsStringAPI.h> + +#include <nsCOMPtr.h> +#include <nsIArray.h> +#include <nsIASN1Object.h> +#include <nsIASN1Sequence.h> +#include <nsICRLInfo.h> +#include <nsIDOMWindow.h> +#include <nsIInterfaceRequestor.h> +#include <nsIInterfaceRequestorUtils.h> +#include <nsIPKCS11ModuleDB.h> +#include <nsIPKCS11Slot.h> +#include <nsIPK11Token.h> +#include <nsIPK11TokenDB.h> +#include <nsIServiceManager.h> +#include <nsISimpleEnumerator.h> +#include <nsIX509CertDB.h> +#include <nsIX509Cert.h> +#include <nsIX509CertValidity.h> +#include <nsMemory.h> +#include <nsServiceManagerUtils.h> + +#ifdef HAVE_NSIMUTABLEARRAY_H +#include <nsIMutableArray.h> +#endif + +#include "ephy-file-helpers.h" +#include "ephy-gui.h" +#include "ephy-password-dialog.h" +#include "ephy-stock-icons.h" + +#include "AutoJSContextStack.h" +#include "AutoWindowModalState.h" +#include "EphyUtils.h" + +#include "GtkNSSDialogs.h" + +NS_DEFINE_CID (kX509CertCID, NS_IX509CERT_IID); +NS_DEFINE_CID (kASN1ObjectCID, NS_IASN1OBJECT_IID); + +enum +{ + NSSDIALOG_RESPONSE_VIEW_CERT = 10 +}; + +GtkNSSDialogs::GtkNSSDialogs () +{ +} + +GtkNSSDialogs::~GtkNSSDialogs () +{ +} + +NS_IMPL_THREADSAFE_ISUPPORTS5 (GtkNSSDialogs, + nsICertificateDialogs, + nsIBadCertListener, + nsITokenPasswordDialogs, + nsITokenDialogs, + nsIDOMCryptoDialogs) + +/* There's also nsICertPickDialogs which is implemented in mozilla + * but has no callers. So we don't implement it. + * Same for nsIUserCertPicker which is only used in mailnews. + */ + +/** + * Call the mozilla service to display a certificate + */ +static void +view_certificate (nsIInterfaceRequestor *ctx, nsIX509Cert *cert) +{ + nsresult rv; + nsCOMPtr<nsICertificateDialogs> certDialogs = + do_GetService (NS_CERTIFICATEDIALOGS_CONTRACTID, &rv); + NS_ENSURE_SUCCESS (rv, ); + + certDialogs->ViewCert (ctx, cert); +} + +/** + * Indent a widget according the HIG + * + * @returns: The new indented widget + */ +static GtkWidget* +higgy_indent_widget (GtkWidget *widget) +{ + GtkWidget *hbox; + GtkWidget *label; + + hbox = gtk_hbox_new (FALSE, 6); + + label = gtk_label_new (NULL); + gtk_box_pack_start (GTK_BOX(hbox), label, FALSE, TRUE, 6); + gtk_widget_show (label); + + gtk_box_pack_start (GTK_BOX(hbox), widget, TRUE, TRUE, 0); + + return hbox; +} + +/** + * Setup up a dialog with the correct HIG'gy spacings, adding the content_widget + */ +static void +higgy_setup_dialog (GtkDialog *dialog, const gchar *stock_icon, + GtkWidget **content_label, + GtkWidget **content_vbox) +{ + GtkWidget *hbox, *label, *image, *vbox; + + g_return_if_fail (GTK_IS_DIALOG (dialog)); + g_return_if_fail (content_label); + + gtk_dialog_set_has_separator (dialog, FALSE); + gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE); + gtk_container_set_border_width (GTK_CONTAINER (dialog), 5); + + hbox = gtk_hbox_new (FALSE, 12); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); + gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), hbox); + + image = gtk_image_new_from_stock (stock_icon, GTK_ICON_SIZE_DIALOG); + gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0.0); + gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0); + + vbox = gtk_vbox_new (FALSE, 12); + gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); + + label = gtk_label_new (NULL); + gtk_label_set_use_markup (GTK_LABEL (label), TRUE); + gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); + gtk_label_set_selectable (GTK_LABEL (label), TRUE); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.0); + + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); + + gtk_widget_show (image); + gtk_widget_show (vbox); + gtk_widget_show (hbox); + gtk_widget_show (label); + + /* Set up the spacing for the dialog internal widgets */ + gtk_box_set_spacing (GTK_BOX(dialog->vbox), 14); /* 24 = 2 * 5 + 14 */ + + *content_label = label; + if (content_vbox) + { + *content_vbox = vbox; + } +} + + +/** + * Display a dialog box, showing 'View Certificate', 'Cancel', + * and 'Accept' buttons. Optionally a checkbox can be shown, + * or the text can be NULL to avoid it being displayed + * + * @returns: GTK_RESPONSE_ACCEPT if the user clicked Accept + */ +static gint +display_cert_warning_box (nsIInterfaceRequestor *ctx, + nsIX509Cert *cert, + const char *markup_text, + const char *checkbox_text, + gboolean *checkbox_value, + const char *affirmative_text) +{ + GtkWidget *dialog, *label, *checkbox, *vbox, *button; + int res; + + g_return_val_if_fail (markup_text, GTK_RESPONSE_CANCEL); + g_return_val_if_fail (!checkbox_text || checkbox_value, GTK_RESPONSE_CANCEL); + + nsresult rv; + AutoJSContextStack stack; + rv = stack.Init (); + if (NS_FAILED (rv)) return rv; + + /* NOTE: Due to a mozilla bug [https://bugzilla.mozilla.org/show_bug.cgi?id=306288], + * we will always end up without a parent! + */ + nsCOMPtr<nsIDOMWindow> parent (do_GetInterface (ctx)); + GtkWindow *gparent = GTK_WINDOW (EphyUtils::FindGtkParent (parent)); + + AutoWindowModalState modalState (parent); + + dialog = gtk_dialog_new_with_buttons ("", gparent, + GTK_DIALOG_DESTROY_WITH_PARENT, + (char *) NULL); + if (gparent) + { + gtk_window_group_add_window (ephy_gui_ensure_window_group (gparent), + GTK_WINDOW (dialog)); + } + + gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE); + gtk_window_set_icon_name (GTK_WINDOW (dialog), EPHY_STOCK_EPHY); + + higgy_setup_dialog (GTK_DIALOG (dialog), + GTK_STOCK_DIALOG_WARNING, &label, &vbox); + + /* Add the buttons */ + gtk_dialog_add_button (GTK_DIALOG (dialog), _("_View Certificate"), + NSSDIALOG_RESPONSE_VIEW_CERT); + + gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_CANCEL, + GTK_RESPONSE_CANCEL); + + if (affirmative_text == NULL) + { + affirmative_text = _("_Accept"); + } + + button = gtk_dialog_add_button (GTK_DIALOG (dialog), + affirmative_text, + GTK_RESPONSE_ACCEPT); + gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT); + + if (checkbox_text) + { + checkbox = gtk_check_button_new_with_mnemonic (checkbox_text); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbox), + *checkbox_value); + + gtk_box_pack_start (GTK_BOX (vbox), checkbox, TRUE, TRUE, 0); + } + else + { + checkbox = 0; + } + + /* We don't want focus on the checkbox */ + gtk_widget_grab_focus (button); + + gtk_label_set_markup (GTK_LABEL (label), markup_text); + gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT); + gtk_widget_show_all (dialog); + + while (1) + { + res = gtk_dialog_run (GTK_DIALOG (dialog)); + if (res == NSSDIALOG_RESPONSE_VIEW_CERT) + { + view_certificate (ctx, cert); + continue; + } + + break; + } + + if (res == GTK_RESPONSE_ACCEPT && checkbox) + { + *checkbox_value = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (checkbox)); + } + + gtk_widget_destroy (dialog); + return res; +} + + +/* Helper functions */ + +nsresult +GtkNSSDialogs::GetTokenAndSlotFromName (const PRUnichar *aName, + nsIPK11Token **aToken, + nsIPKCS11Slot **aSlot) +{ + nsresult rv = NS_ERROR_FAILURE; + *aToken = nsnull; + *aSlot = nsnull; + + nsCOMPtr<nsIPK11TokenDB> tokenDB = do_GetService("@mozilla.org/security/pk11tokendb;1"); + nsCOMPtr<nsIPKCS11ModuleDB> pkcs11DB = do_GetService("@mozilla.org/security/pkcs11moduledb;1"); + if (!tokenDB || !pkcs11DB) return rv; + + rv = tokenDB->FindTokenByName (aName, aToken); + NS_ENSURE_TRUE (NS_SUCCEEDED (rv) && *aToken, rv); + + pkcs11DB->FindSlotByName (aName, aSlot); + + NS_ENSURE_TRUE (*aSlot, NS_ERROR_FAILURE); + +#ifdef GNOME_ENABLE_DEBUG + /* Dump some info about this token */ + nsIPK11Token *token = *aToken; + PRUnichar *tName, *tLabel, *tManID, *tHWVersion, *tFWVersion, *tSN; + PRInt32 minPwdLen; + PRBool needsInit, isHW, needsLogin, isFriendly; + + token->GetTokenName(&tName); + token->GetTokenLabel(&tLabel); + token->GetTokenManID(&tManID); + token->GetTokenHWVersion(&tHWVersion); + token->GetTokenFWVersion(&tFWVersion); + token->GetTokenSerialNumber(&tSN); + token->GetMinimumPasswordLength(&minPwdLen); + token->GetNeedsUserInit(&needsInit); + token->IsHardwareToken(&isHW); + token->NeedsLogin(&needsLogin); + token->IsFriendly(&isFriendly); + + g_print ("Token '%s' has \nName: %s\nLabel: %s\nManID: %s\nHWversion: %s\nFWVersion: %s\nSN: %s\n" + "MinPwdLen: %d\nNeedsUserInit: %d\nIsHWToken: %d\nNeedsLogin: %d\nIsFriendly: %d\n\n", + NS_ConvertUTF16toUTF8(aName).get(), + + NS_ConvertUTF16toUTF8(tName).get(), + NS_ConvertUTF16toUTF8(tLabel).get(), + NS_ConvertUTF16toUTF8(tManID).get(), + NS_ConvertUTF16toUTF8(tHWVersion).get(), + NS_ConvertUTF16toUTF8(tFWVersion).get(), + NS_ConvertUTF16toUTF8(tSN).get(), + minPwdLen, + needsInit, + isHW, + needsLogin, + isFriendly); + + nsIPKCS11Slot *slot = *aSlot; + PRUnichar*slDesc; + slot->GetDesc(&slDesc); + g_print ("Slot description: %s\n", NS_ConvertUTF16toUTF8 (slDesc).get()); +#endif + + return NS_OK; +} + +/* nsICertificateDialogs */ + +NS_IMETHODIMP +GtkNSSDialogs::ConfirmMismatchDomain (nsIInterfaceRequestor *ctx, + const nsACString &targetURL, + nsIX509Cert *cert, PRBool *_retval) +{ + char *first, *second, *msg; + int res; + + nsString commonName; + cert->GetCommonName (commonName); + + NS_ConvertUTF16toUTF8 cCommonName (commonName); + + nsCString cTargetUrl (targetURL); + + first = g_markup_printf_escaped (_("The site “%s” returned security information for " + "“%s”. It is possible that someone is intercepting " + "your communication to obtain your confidential " + "information."), + cTargetUrl.get(), cCommonName.get()); + + second = g_markup_printf_escaped (_("You should only accept the security information if you " + "trust “%s” and “%s”."), + cTargetUrl.get(), cCommonName.get()); + + msg = g_strdup_printf ("<span weight=\"bold\" size=\"larger\">%s</span>\n\n%s\n\n%s", + _("Accept incorrect security information?"), + first, second); + + res = display_cert_warning_box (ctx, cert, msg, NULL, NULL, NULL); + + g_free (second); + g_free (first); + g_free (msg); + + *_retval = (res == GTK_RESPONSE_ACCEPT); + return NS_OK; +} + + +NS_IMETHODIMP +GtkNSSDialogs::ConfirmUnknownIssuer (nsIInterfaceRequestor *ctx, + nsIX509Cert *cert, PRInt16 *outAddType, + PRBool *_retval) +{ + gboolean accept_perm = FALSE; + char *secondary, *tertiary, *msg; + int res; + + nsString commonName; + cert->GetCommonName (commonName); + + NS_ConvertUTF16toUTF8 cCommonName (commonName); + + secondary = g_markup_printf_escaped + (_("It was not possible to automatically trust “%s”. " + "It is possible that someone is intercepting your " + "communication to obtain your confidential information."), + cCommonName.get()); + + tertiary = g_markup_printf_escaped + (_("You should only connect to the site if you are certain " + "you are connected to “%s”."), + cCommonName.get()); + + msg = g_strdup_printf ("<span weight=\"bold\" size=\"larger\">%s</span>\n\n%s\n\n%s", + _("Connect to untrusted site?"), + secondary, tertiary); + + res = display_cert_warning_box (ctx, cert, msg, + _("_Trust this security information from now on"), + &accept_perm, _("Co_nnect")); + g_free (tertiary); + g_free (secondary); + g_free (msg); + + if (res != GTK_RESPONSE_ACCEPT) + { + *_retval = PR_FALSE; + *outAddType = UNINIT_ADD_FLAG; + } + else + { + if (accept_perm) + { + *_retval = PR_TRUE; + *outAddType = ADD_TRUSTED_PERMANENTLY; + } + else + { + *_retval = PR_TRUE; + *outAddType = ADD_TRUSTED_FOR_SESSION; + } + } + + return NS_OK; +} + + +/* boolean confirmCertExpired (in nsIInterfaceRequestor socketInfo, + in nsIX509Cert cert); */ +NS_IMETHODIMP +GtkNSSDialogs::ConfirmCertExpired (nsIInterfaceRequestor *ctx, + nsIX509Cert *cert, PRBool *_retval) +{ + nsresult rv; + PRTime now = PR_Now(); + PRTime notAfter, notBefore, timeToUse; + PRInt64 normalizedTime; + time_t t; + struct tm tm; + char formattedDate[128]; + char *fdate; + const char *primary, *text; + char *secondary, *msg; + + *_retval = PR_FALSE; + + nsCOMPtr<nsIX509CertValidity> validity; + rv = cert->GetValidity (getter_AddRefs(validity)); + if (NS_FAILED(rv)) return rv; + + rv = validity->GetNotAfter (¬After); + if (NS_FAILED(rv)) return rv; + + rv = validity->GetNotBefore (¬Before); + if (NS_FAILED(rv)) return rv; + + if (LL_CMP(now, >, notAfter)) + { + primary = _("Accept expired security information?"); + /* Translators: first %s is a hostname, second %s is a time/date */ + text = _("The security information for “%s” " + "expired on %s."); + timeToUse = notAfter; + } + else + { + primary = _("Accept not yet valid security information?"); + /* Translators: first %s is a hostname, second %s is a time/date */ + text = _("The security information for “%s” isn't valid until %s."); + timeToUse = notBefore; + } + + nsString commonName; + cert->GetCommonName (commonName); + + NS_ConvertUTF16toUTF8 cCommonName (commonName); + + LL_DIV (normalizedTime, timeToUse, PR_USEC_PER_SEC); + LL_L2UI (t, normalizedTime); + /* To translators: this a time format that is used while displaying the + * expiry or start date of an SSL certificate, for the format see + * strftime(3) */ + strftime (formattedDate, sizeof(formattedDate), _("%a %d %b %Y"), + localtime_r (&t, &tm)); + /* FIXME! this isn't actually correct, LC_CTIME codeset could be different than locale codeset! */ + fdate = g_locale_to_utf8 (formattedDate, -1, NULL, NULL, NULL); + + secondary = g_markup_printf_escaped (text, cCommonName.get(), fdate); + + msg = g_strdup_printf ("<span weight=\"bold\" size=\"larger\">%s</span>\n\n%s\n\n%s", + primary, secondary, + _("You should ensure that your computer's time is correct.")); + + int res = display_cert_warning_box (ctx, cert, msg, NULL, NULL, NULL); + + g_free (fdate); + g_free (msg); + g_free (secondary); + + *_retval = (res == GTK_RESPONSE_ACCEPT); + + return NS_OK; +} + +/* void notifyCrlNextupdate (in nsIInterfaceRequestor socketInfo, + in AUTF8String targetURL, + in nsIX509Cert cert); */ +NS_IMETHODIMP +GtkNSSDialogs::NotifyCrlNextupdate (nsIInterfaceRequestor *ctx, + const nsACString & targetURL, + nsIX509Cert *cert) +{ + nsCOMPtr<nsIDOMWindow> parent = do_GetInterface (ctx); + GtkWidget *gparent = EphyUtils::FindGtkParent (parent); + + nsCString cTargetUrl (targetURL); + + nsString commonName; + cert->GetCommonName (commonName); + + GtkWidget *dialog = gtk_message_dialog_new + (GTK_WINDOW (gparent), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_OK, + _("Cannot establish connection to “%s”"), + cTargetUrl.get ()); + + gtk_message_dialog_format_secondary_text + (GTK_MESSAGE_DIALOG (dialog), + _("The certificate revocation list (CRL) from “%s” " + "needs to be updated.\n\n" + "Please ask your system administrator for assistance."), + NS_ConvertUTF16toUTF8 (commonName).get ()); + gtk_window_set_icon_name (GTK_WINDOW (dialog), EPHY_STOCK_EPHY); + + g_signal_connect (dialog, "response", + (GCallback) gtk_widget_destroy, NULL); + + gtk_widget_show_all (dialog); + return NS_OK; +} + +NS_IMETHODIMP +GtkNSSDialogs::ConfirmDownloadCACert(nsIInterfaceRequestor *ctx, + nsIX509Cert *cert, + PRUint32 *_trust, + PRBool *_retval) +{ + GtkWidget *dialog, *label; + char *msg, *primary; + + nsresult rv; + AutoJSContextStack stack; + rv = stack.Init (); + if (NS_FAILED (rv)) return rv; + + nsCOMPtr<nsIDOMWindow> parent (do_GetInterface (ctx)); + GtkWindow *gparent = GTK_WINDOW (EphyUtils::FindGtkParent (parent)); + + AutoWindowModalState modalState (parent); + + dialog = gtk_dialog_new_with_buttons (_("Trust new Certificate Authority?"), gparent, + GTK_DIALOG_DESTROY_WITH_PARENT, + _("_View Certificate"), + NSSDIALOG_RESPONSE_VIEW_CERT, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + _("_Trust CA"), GTK_RESPONSE_ACCEPT, + (char *) NULL); + + if (gparent) + { + gtk_window_group_add_window (ephy_gui_ensure_window_group (gparent), + GTK_WINDOW (dialog)); + } + + gtk_window_set_icon_name (GTK_WINDOW (dialog), EPHY_STOCK_EPHY); + + higgy_setup_dialog (GTK_DIALOG (dialog), GTK_STOCK_DIALOG_WARNING, + &label, NULL); + gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT); + + nsString commonName; + cert->GetCommonName (commonName); + + NS_ConvertUTF16toUTF8 cCommonName (commonName); + + primary = g_markup_printf_escaped (_("Trust new Certificate Authority “%s” to identify web sites?"), + cCommonName.get()); + + msg = g_strdup_printf ("<span weight=\"bold\" size=\"larger\">%s</span>\n\n%s", + primary, + _("Before trusting a Certificate Authority (CA) you should " + "verify the certificate is authentic.")); + gtk_label_set_markup (GTK_LABEL (label), msg); + g_free (primary); + g_free (msg); + + gtk_widget_show_all (dialog); + int ret; + + while (1) + { + ret = gtk_dialog_run (GTK_DIALOG (dialog)); + if (ret == NSSDIALOG_RESPONSE_VIEW_CERT) + { + view_certificate (ctx, cert); + continue; + } + + break; + } + + if (ret != GTK_RESPONSE_ACCEPT) + { + *_retval = PR_FALSE; + } + else + { + if (ret == GTK_RESPONSE_ACCEPT) + { + *_trust |= nsIX509CertDB::TRUSTED_SSL; + } + else + { + *_trust = nsIX509CertDB::UNTRUSTED; + } + + *_retval = PR_TRUE; + } + gtk_widget_destroy (dialog); + + return NS_OK; +} + + +NS_IMETHODIMP +GtkNSSDialogs::NotifyCACertExists (nsIInterfaceRequestor *ctx) +{ + GtkWidget *dialog, *label; + char * msg; + + nsCOMPtr<nsIDOMWindow> parent = do_GetInterface (ctx); + GtkWindow *gparent = GTK_WINDOW (EphyUtils::FindGtkParent (parent)); + + dialog = gtk_dialog_new_with_buttons ("", gparent, + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_STOCK_OK, + GTK_RESPONSE_OK, + (char *) NULL); + + if (gparent) + { + gtk_window_group_add_window (ephy_gui_ensure_window_group (gparent), + GTK_WINDOW (dialog)); + } + + gtk_window_set_icon_name (GTK_WINDOW (dialog), EPHY_STOCK_EPHY); + + higgy_setup_dialog (GTK_DIALOG (dialog), GTK_STOCK_DIALOG_ERROR, + &label, NULL); + + msg = g_strdup_printf ("<span weight=\"bold\" size=\"larger\">%s</span>\n\n%s", + _("Certificate already exists."), + _("The certificate has already been imported.")); + gtk_label_set_markup (GTK_LABEL (label), msg); + g_free (msg); + + g_signal_connect (G_OBJECT (dialog), + "response", + (GCallback)gtk_widget_destroy, NULL); + + gtk_widget_show_all (dialog); + return NS_OK; +} + +/* FIXME: This interface sucks! There is way to know the name of the certificate! */ +NS_IMETHODIMP +GtkNSSDialogs::SetPKCS12FilePassword(nsIInterfaceRequestor *ctx, + nsAString &_password, + PRBool *_retval) +{ + GtkWidget *dialog; + char *msg; + + nsresult rv; + AutoJSContextStack stack; + rv = stack.Init (); + if (NS_FAILED (rv)) return rv; + + nsCOMPtr<nsIDOMWindow> parent (do_GetInterface (ctx)); + GtkWidget *gparent = EphyUtils::FindGtkParent (parent); + + AutoWindowModalState modalState (parent); + + dialog = ephy_password_dialog_new (gparent, + _("Select Password"), + EphyPasswordDialogFlags(EPHY_PASSWORD_DIALOG_FLAGS_SHOW_NEW_PASSWORD | + EPHY_PASSWORD_DIALOG_FLAGS_SHOW_QUALITY_METER)); + gtk_window_set_modal (GTK_WINDOW (dialog), TRUE); + gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE); + + /* FIXME: set accept button text to (_("_Back Up Certificate") ? + * That's not actually correct, since this function is also called from other places! + */ + + msg = g_markup_printf_escaped (_("Select a password to protect this certificate")); + gtk_message_dialog_set_markup (GTK_MESSAGE_DIALOG (dialog), msg); + g_free (msg); + + int response = gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_hide (dialog); + + if (response == GTK_RESPONSE_ACCEPT) + { + const char *text = ephy_password_dialog_get_new_password (EPHY_PASSWORD_DIALOG (dialog)); + g_return_val_if_fail (text != NULL, NS_ERROR_FAILURE); + NS_CStringToUTF16 (nsDependentCString (text), + NS_CSTRING_ENCODING_UTF8, _password); + } + + *_retval = response == GTK_RESPONSE_ACCEPT; + + gtk_widget_destroy (dialog); + + return NS_OK; +} + +NS_IMETHODIMP +GtkNSSDialogs::GetPKCS12FilePassword(nsIInterfaceRequestor *ctx, + nsAString &_password, + PRBool *_retval) +{ + g_print ("GtkNSSDialogs::GetPKCS12FilePassword\n"); + + nsresult rv; + AutoJSContextStack stack; + rv = stack.Init (); + if (NS_FAILED (rv)) return rv; + + nsCOMPtr<nsIDOMWindow> parent (do_GetInterface (ctx)); + GtkWidget *gparent = EphyUtils::FindGtkParent (parent); + + AutoWindowModalState modalState (parent); + + GtkWidget *dialog = ephy_password_dialog_new + (gparent, + "", + EphyPasswordDialogFlags (EPHY_PASSWORD_DIALOG_FLAGS_SHOW_PASSWORD)); + EphyPasswordDialog *password_dialog = EPHY_PASSWORD_DIALOG (dialog); + /* FIXME: set accept button text to _("I_mport Certificate") ? */ + + gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE); + + /* FIXME: mozilla sucks, no way to get the name of the certificate / cert file! */ + char *msg = g_markup_printf_escaped (_("Enter the password for this certificate")); + gtk_message_dialog_set_markup (GTK_MESSAGE_DIALOG (dialog), msg); + g_free (msg); + + int response = gtk_dialog_run (GTK_DIALOG (dialog)); + + if (response == GTK_RESPONSE_ACCEPT) + { + const char *pwd = ephy_password_dialog_get_password (password_dialog); + NS_CStringToUTF16 (nsDependentCString (pwd), + NS_CSTRING_ENCODING_UTF8, _password); + } + + *_retval = response == GTK_RESPONSE_ACCEPT; + + gtk_widget_destroy (dialog); + + return NS_OK; +} + + +static void +set_table_row (GtkWidget *table, + int& row, + const char *title, + const char *text) +{ + GtkWidget *header, *label; + char *bold; + + if (text == NULL || text[0] == 0) return; + + bold = g_markup_printf_escaped ("<b>%s</b>", title); + header = gtk_label_new (bold); + g_free (bold); + + gtk_label_set_use_markup (GTK_LABEL (header), TRUE); + gtk_misc_set_alignment (GTK_MISC (header), 0, 0); + gtk_widget_show (header); + gtk_table_attach (GTK_TABLE (table), header, 0, 1, row, row+1, + GTK_FILL, GTK_FILL, 0, 0); + + label = gtk_label_new (text); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0); + gtk_label_set_selectable (GTK_LABEL (label), TRUE); + gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END); + gtk_label_set_max_width_chars (GTK_LABEL (label), 48); + gtk_widget_show (label); + gtk_table_attach_defaults (GTK_TABLE (table), label, 1, 2, row, row+1); + + row++; +} + +NS_IMETHODIMP +GtkNSSDialogs::CrlImportStatusDialog(nsIInterfaceRequestor *ctx, nsICRLInfo *crl) +{ + + GtkWidget *dialog, *label, *table, *vbox; + nsresult rv; + char *msg; + + nsCOMPtr<nsIDOMWindow> parent = do_GetInterface (ctx); + GtkWidget *gparent = EphyUtils::FindGtkParent (parent); + + dialog = gtk_dialog_new_with_buttons ("", + GTK_WINDOW (gparent), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_STOCK_OK, GTK_RESPONSE_OK, + (char *) NULL); + + gtk_window_set_icon_name (GTK_WINDOW (dialog), EPHY_STOCK_EPHY); + gtk_window_set_title (GTK_WINDOW (dialog), _("Certificate Revocation List Imported")); + + /* Needed because gparent == NULL always because of mozilla sucks */ + gtk_window_set_skip_pager_hint (GTK_WINDOW (dialog), TRUE); + gtk_window_set_skip_taskbar_hint (GTK_WINDOW (dialog), TRUE); + + higgy_setup_dialog (GTK_DIALOG (dialog), GTK_STOCK_DIALOG_INFO, + &label, &vbox); + + msg = g_strdup_printf ("<span weight=\"bold\" size=\"larger\">%s</span>", + _("Certificate Revocation List (CRL) successfully imported")); + gtk_label_set_markup (GTK_LABEL (label), msg); + g_free (msg); + + table = gtk_table_new (2, 3, FALSE); + gtk_table_set_row_spacings (GTK_TABLE (table), 6); + gtk_table_set_col_spacings (GTK_TABLE (table), 12); + + nsString org, orgUnit, nextUpdate; + rv = crl->GetOrganization (org); + if (NS_FAILED(rv)) return rv; + + rv = crl->GetOrganizationalUnit (orgUnit); + if (NS_FAILED(rv)) return rv; + + rv = crl->GetNextUpdateLocale (nextUpdate); + if (NS_FAILED(rv)) return rv; + + int row = 0; + set_table_row (table, row, _("Organization:"), NS_ConvertUTF16toUTF8 (org).get ()); + + set_table_row (table, row, _("Unit:"), NS_ConvertUTF16toUTF8 (orgUnit).get ()); + + set_table_row (table, row, _("Next Update:"), NS_ConvertUTF16toUTF8 (nextUpdate).get ()); + + gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0); + + gtk_widget_show_all (dialog); + g_signal_connect (G_OBJECT (dialog), + "response", + (GCallback)gtk_widget_destroy, NULL); + + gtk_widget_show_all (dialog); + return NS_OK; +} + +/** + * Help function to fill in the labels on the General tab + */ +static void +set_label_cert_attribute (GladeXML* gxml, const char* label_id, nsAString &value) +{ + GtkWidget *label; + label = glade_xml_get_widget (gxml, label_id); + + g_return_if_fail (GTK_IS_LABEL (label)); + + if (!value.Length()) { + gtk_label_set_use_markup (GTK_LABEL (label), TRUE); + char *msg = g_strdup_printf ("<i><%s></i>", + _("Not part of certificate")); + gtk_label_set_markup (GTK_LABEL (label), msg); + g_free (msg); + } + else + { + gtk_label_set_use_markup (GTK_LABEL (label), FALSE); + gtk_label_set_text (GTK_LABEL (label), NS_ConvertUTF16toUTF8 (value).get()); + } +} + + +/** + * Do that actual filling in of the certificate tree + */ +static gboolean +fill_cert_chain_tree (GtkTreeView *treeview, nsIArray *certChain) +{ + nsresult rv; + GtkTreeModel * model = gtk_tree_view_get_model (treeview); + + GtkTreeIter parent; + PRUint32 numCerts; + rv = certChain->GetLength (&numCerts); + if (NS_FAILED(rv) || numCerts < 1) return FALSE; + + for (int i = (int)numCerts-1 ; i >= 0; i--) + { + nsCOMPtr<nsIX509Cert> nsCert; + rv = certChain->QueryElementAt (i, kX509CertCID, + getter_AddRefs(nsCert)); + if (NS_FAILED(rv)) return FALSE; + + GtkTreeIter iter; + gtk_tree_store_append (GTK_TREE_STORE (model), &iter, + (i == (int)numCerts-1) ? NULL : &parent); + + nsString value; + rv = nsCert->GetCommonName (value); + if (NS_FAILED(rv)) return FALSE; + + NS_ConvertUTF16toUTF8 cValue (value); + + nsIX509Cert *nsCertP = nsCert; + if (value.Length()) + { + gtk_tree_store_set (GTK_TREE_STORE(model), &iter, + 0, cValue.get(), + 1, nsCertP, + -1); + } + else + { + char * title; + rv = nsCert->GetWindowTitle (&title); + if (NS_FAILED(rv)) return FALSE; + + gtk_tree_store_set (GTK_TREE_STORE(model), + &iter, 0, title, 1, nsCertP, -1); + nsMemory::Free (title); + } + parent = iter; + } + gtk_tree_view_expand_all (GTK_TREE_VIEW (treeview)); + + /* And select the last entry, and scroll the view so it's visible */ + GtkTreeSelection *select = gtk_tree_view_get_selection (treeview); + GtkTreePath *path = gtk_tree_model_get_path (model, &parent); + gtk_tree_selection_select_path (select, path); + gtk_tree_view_scroll_to_cell (treeview, path, NULL, TRUE, 0.5, 0.0); + gtk_tree_path_free (path); + + return TRUE; +} + +/** + * Add an ASN object to the treeview, recursing if the object was a + * sequence + */ +static void +add_asn1_object_to_tree(GtkTreeModel *model, nsIASN1Object *object, GtkTreeIter *parent) +{ + nsString dispNameU; + object->GetDisplayName(dispNameU); + + GtkTreeIter iter; + gtk_tree_store_append (GTK_TREE_STORE (model), &iter, parent); + + gtk_tree_store_set (GTK_TREE_STORE(model), &iter, + 0, NS_ConvertUTF16toUTF8 (dispNameU).get(), + 1, object, + -1); + + nsCOMPtr<nsIASN1Sequence> sequence(do_QueryInterface(object)); + if (!sequence) return; + + nsCOMPtr<nsIMutableArray> asn1Objects; + sequence->GetASN1Objects(getter_AddRefs(asn1Objects)); + + PRUint32 numObjects; + asn1Objects->GetLength(&numObjects); + if (!asn1Objects) return; + + for (PRUint32 i = 0; i < numObjects ; i++) + { + nsCOMPtr<nsIASN1Object> currObject; + asn1Objects->QueryElementAt (i, kASN1ObjectCID, + getter_AddRefs (currObject)); + add_asn1_object_to_tree (model, currObject, &iter); + } +} + + +/** + * Update the "Certificate Fields" treeview when a different cert + * is selected in the hierarchy text view + */ +static void +cert_chain_tree_view_selection_changed_cb (GtkTreeSelection *selection, + GtkWidget* tree_view) +{ + GtkTreeIter iter; + nsIX509Cert *nsCert; + nsresult rv; + GtkTreeModel * model; + + if (gtk_tree_selection_get_selected (selection, &model, &iter)) + { + gtk_tree_model_get (model, &iter, 1, &nsCert, -1); + + nsCOMPtr<nsIASN1Object> object; + rv = nsCert->GetASN1Structure (getter_AddRefs(object)); + if (NS_FAILED(rv)) return; + + model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view)); + gtk_tree_store_clear (GTK_TREE_STORE (model)); + add_asn1_object_to_tree (model, object, NULL); + + gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view)); + } +} + +/** + * When the "Certificate Field" treeview is changed, update the + * text_view to display the value of the currently selected field + */ +static void +field_tree_view_selection_changed_cb (GtkTreeSelection *selection, + GtkWidget* text_view) +{ + GtkTreeIter iter; + GtkTreeModel *model; + GtkTextBuffer * text_buffer = + gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view)); + + if (gtk_tree_selection_get_selected (selection, &model, &iter)) + { + nsIASN1Object *object; + + gtk_tree_model_get (model, &iter, 1, &object, -1); + + nsString dispValU; + object->GetDisplayValue(dispValU); + + gtk_text_buffer_set_text (text_buffer, NS_ConvertUTF16toUTF8 (dispValU).get(), -1); + } + else + { + gtk_text_buffer_set_text (text_buffer, "", 0); + } +} + +/** + * Setup the various treeviews, the textview, and fill the treeviews + */ +static gboolean +setup_view_cert_tree (GtkWidget *dialog, GladeXML*gxml, nsIArray *certChain) +{ + GtkCellRenderer *renderer; + GtkWidget *chain_tree_view, *field_tree_view, *text_view; + PangoFontDescription *monospace_font_desc; + GConfClient *conf_client; + char *monospace_font; + + chain_tree_view = glade_xml_get_widget (gxml, "treeview_cert_chain"); + field_tree_view = glade_xml_get_widget (gxml, "treeview_cert_info"); + text_view = glade_xml_get_widget (gxml, "textview_field_value"); + + /* Setup the certificate chain view */ + GtkTreeStore *store = gtk_tree_store_new (2, + G_TYPE_STRING, + G_TYPE_POINTER); + gtk_tree_view_set_model (GTK_TREE_VIEW (chain_tree_view), GTK_TREE_MODEL (store)); + g_object_unref (store); + + + renderer = gtk_cell_renderer_text_new (); + gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (chain_tree_view), + 0, "Certificate", + renderer, + "text", 0, + (char *) NULL); + + GtkTreeSelection *select = gtk_tree_view_get_selection (GTK_TREE_VIEW (chain_tree_view)); + gtk_tree_selection_set_mode (select, GTK_SELECTION_SINGLE); + + g_signal_connect (G_OBJECT (select), "changed", + G_CALLBACK (cert_chain_tree_view_selection_changed_cb), + field_tree_view); + + /* Setup the certificate field view */ + store = gtk_tree_store_new (2, + G_TYPE_STRING, + G_TYPE_POINTER); + gtk_tree_view_set_model (GTK_TREE_VIEW (field_tree_view), GTK_TREE_MODEL (store)); + g_object_unref (store); + + + gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (field_tree_view), + 0, "Certificate Field", + renderer, + "text", 0, + (char *) NULL); + + select = gtk_tree_view_get_selection (GTK_TREE_VIEW (field_tree_view)); + gtk_tree_selection_set_mode (select, GTK_SELECTION_SINGLE); + + g_signal_connect (G_OBJECT (select), "changed", + G_CALLBACK (field_tree_view_selection_changed_cb), + text_view); + + /* Get the text_view displaying a propertional font + * + * Pick up the monospace font from desktop preferences */ + conf_client = gconf_client_get_default (); + monospace_font = gconf_client_get_string (conf_client, + "/desktop/gnome/interface/monospace_font_name", NULL); + if (monospace_font) + { + monospace_font_desc = pango_font_description_from_string (monospace_font); + gtk_widget_modify_font (text_view, monospace_font_desc); + pango_font_description_free (monospace_font_desc); + } + g_object_unref (conf_client); + + /* And fill the certificate chain tree */ + return fill_cert_chain_tree (GTK_TREE_VIEW (chain_tree_view), certChain); +} + +/* void viewCert (in nsIX509Cert cert); */ +NS_IMETHODIMP +GtkNSSDialogs::ViewCert(nsIInterfaceRequestor *ctx, + nsIX509Cert *cert) +{ + GtkWidget *dialog, *widget; + GladeXML *gxml; + nsString value; + PRUint32 verifystate, count; + PRUnichar ** usage; + GtkSizeGroup * sizegroup; + + nsresult rv; + AutoJSContextStack stack; + rv = stack.Init (); + if (NS_FAILED (rv)) return rv; + + gxml = glade_xml_new (ephy_file ("certificate-dialogs.glade"), + "viewcert_dialog", NULL); + g_return_val_if_fail (gxml != NULL, NS_ERROR_FAILURE); + + dialog = glade_xml_get_widget (gxml, "viewcert_dialog"); + g_return_val_if_fail (dialog != NULL, NS_ERROR_FAILURE); + + nsCOMPtr<nsIDOMWindow> parent (do_GetInterface (ctx)); + GtkWindow *gparent = GTK_WINDOW (EphyUtils::FindGtkParent (parent)); + + AutoWindowModalState modalState (parent); + + if (gparent) + { + gtk_window_set_transient_for (GTK_WINDOW(dialog), GTK_WINDOW(gparent)); + gtk_window_group_add_window (ephy_gui_ensure_window_group (GTK_WINDOW (gparent)), + GTK_WINDOW (dialog)); + gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE); + } + + gtk_window_set_icon_name (GTK_WINDOW (dialog), EPHY_STOCK_EPHY); + + gtk_window_set_title (GTK_WINDOW (dialog), _("Certificate Properties")); + gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CLOSE); + + /* Set up the GtkSizeGroup so that the columns line up */ + sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); + widget = glade_xml_get_widget (gxml, "label_size1"); + gtk_size_group_add_widget (sizegroup, widget); + widget = glade_xml_get_widget (gxml, "label_size2"); + gtk_size_group_add_widget (sizegroup, widget); + widget = glade_xml_get_widget (gxml, "label_size3"); + gtk_size_group_add_widget (sizegroup, widget); + widget = glade_xml_get_widget (gxml, "label_size4"); + gtk_size_group_add_widget (sizegroup, widget); + g_object_unref (sizegroup); + + rv = cert->GetUsagesArray (FALSE, &verifystate, &count, &usage); + if (NS_FAILED(rv)) return rv; + + const char * text; + switch (verifystate) + { + case nsIX509Cert::VERIFIED_OK: + text = _("This certificate has been verified for the following uses:"); + break; + case nsIX509Cert::CERT_REVOKED: + text = _("Could not verify this certificate because it has been revoked."); + break; + case nsIX509Cert::CERT_EXPIRED: + text = _("Could not verify this certificate because it has expired."); + break; + case nsIX509Cert::CERT_NOT_TRUSTED: + text = _("Could not verify this certificate because it is not trusted."); + break; + case nsIX509Cert::ISSUER_NOT_TRUSTED: + text = _("Could not verify this certificate because the issuer is not trusted."); + break; + case nsIX509Cert::ISSUER_UNKNOWN: + text = _("Could not verify this certificate because the issuer is unknown."); + break; + case nsIX509Cert::INVALID_CA: + text = _("Could not verify this certificate because the CA certificate is invalid."); + break; + case nsIX509Cert::NOT_VERIFIED_UNKNOWN: + case nsIX509Cert::USAGE_NOT_ALLOWED: + default: + text = _("Could not verify this certificate for unknown reasons."); + } + + char *vmsg = g_strdup_printf ("<b>%s</b>", text); + widget = glade_xml_get_widget (gxml, "label_verify_text"); + g_return_val_if_fail (GTK_IS_LABEL (widget), NS_ERROR_FAILURE); + gtk_label_set_markup (GTK_LABEL (widget), vmsg); + g_free (vmsg); + + if (count > 0) + { + GtkWidget *vbox = gtk_vbox_new (FALSE, 3); + GtkWidget *indent; + for (PRUint32 i = 0 ; i < count ; i++) + { + GtkWidget *label = gtk_label_new (NS_ConvertUTF16toUTF8 (usage[i]).get()); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); + nsMemory::Free (usage[i]); + } + nsMemory::Free (usage); + indent = higgy_indent_widget (vbox); + widget = glade_xml_get_widget (gxml, "vbox_validity"); + g_return_val_if_fail (GTK_IS_BOX (widget), NS_ERROR_FAILURE); + + gtk_box_pack_start (GTK_BOX (widget), indent, FALSE, FALSE, 0); + } + + cert->GetCommonName (value); + set_label_cert_attribute (gxml, "label_cn", value); + + cert->GetOrganization (value); + set_label_cert_attribute (gxml, "label_o", value); + + cert->GetOrganizationalUnit (value); + set_label_cert_attribute (gxml, "label_ou", value); + + cert->GetSerialNumber (value); + set_label_cert_attribute (gxml, "label_serial", value); + + rv = cert->GetIssuerCommonName (value); + if (NS_FAILED(rv)) return rv; + set_label_cert_attribute (gxml, "label_issuer_cn", value); + + cert->GetIssuerOrganization (value); + set_label_cert_attribute (gxml, "label_issuer_o", value); + + cert->GetIssuerOrganizationUnit (value); + set_label_cert_attribute (gxml, "label_issuer_ou", value); + + nsCOMPtr<nsIX509CertValidity> validity; + rv = cert->GetValidity (getter_AddRefs(validity)); + if (NS_FAILED(rv)) return rv; + + rv = validity->GetNotAfterLocalDay (value); + if (NS_FAILED(rv)) return rv; + set_label_cert_attribute (gxml, "label_notafter", value); + + rv = validity->GetNotBeforeLocalDay (value); + if (NS_FAILED(rv)) return rv; + set_label_cert_attribute (gxml, "label_notbefore", value); + + cert->GetSha1Fingerprint (value); + set_label_cert_attribute (gxml, "label_sha_print", value); + + cert->GetMd5Fingerprint (value); + set_label_cert_attribute (gxml, "label_md5_print", value); + + /* Hold a reference to each certificate in the chain while the + * dialog is displayed, this holds the reference for the ASN + * objects as well */ + + nsCOMPtr<nsIArray> certChain; + rv = cert->GetChain (getter_AddRefs(certChain)); + if (NS_FAILED(rv)) return rv; + + gboolean ret = setup_view_cert_tree (dialog, gxml, certChain); + if (ret == FALSE) return NS_ERROR_FAILURE; + + g_object_unref (gxml); + + gtk_widget_show_all (dialog); + + int res; + while (1) + { + res = gtk_dialog_run (GTK_DIALOG (dialog)); + if (res == GTK_RESPONSE_HELP) + { + ephy_gui_help (GTK_WINDOW (dialog), "epiphany", "using-certificate-viewer"); + continue; + } + break; + } + + gtk_widget_destroy (dialog); + return NS_OK; +} + +/* nsITokenPasswordDialogs */ + +/* NOTE: This interface totally sucks, see https://bugzilla.mozilla.org/show_bug.cgi?id=306993 */ + +/* void setPassword (in nsIInterfaceRequestor ctx, in wstring tokenName, out boolean canceled); */ +NS_IMETHODIMP +GtkNSSDialogs::SetPassword(nsIInterfaceRequestor *aCtx, + const PRUnichar *aTokenName, + PRBool *aCancelled) +{ + NS_ENSURE_ARG_POINTER(aCancelled); + + nsresult rv; + nsCOMPtr<nsIPK11Token> token; + nsCOMPtr<nsIPKCS11Slot> slot; + rv = GetTokenAndSlotFromName (aTokenName, getter_AddRefs (token), + getter_AddRefs (slot)); + NS_ENSURE_SUCCESS (rv, rv); + NS_ENSURE_TRUE (token && slot, NS_ERROR_FAILURE); + + AutoJSContextStack stack; + rv = stack.Init (); + if (NS_FAILED (rv)) return rv; + + PRUint32 status = nsIPKCS11Slot::SLOT_UNINITIALIZED; + slot->GetStatus (&status); + + nsCOMPtr<nsIDOMWindow> parent (do_GetInterface (aCtx)); + GtkWidget *gparent = EphyUtils::FindGtkParent (parent); + + AutoWindowModalState modalState (parent); + + EphyPasswordDialogFlags flags = + EphyPasswordDialogFlags (EPHY_PASSWORD_DIALOG_FLAGS_SHOW_NEW_PASSWORD | + EPHY_PASSWORD_DIALOG_FLAGS_SHOW_QUALITY_METER); + if (status != nsIPKCS11Slot::SLOT_UNINITIALIZED) + flags = EphyPasswordDialogFlags (flags | EPHY_PASSWORD_DIALOG_FLAGS_SHOW_PASSWORD); + + GtkWidget *dialog = ephy_password_dialog_new + (gparent, + _("Change Token Password"), + flags); + EphyPasswordDialog *password_dialog = EPHY_PASSWORD_DIALOG (dialog); + + char *message; + if (status == nsIPKCS11Slot::SLOT_UNINITIALIZED) { + message = g_markup_printf_escaped (_("Choose a password for the “%s” token"), + NS_ConvertUTF16toUTF8 (aTokenName).get ()); + } else { + message = g_markup_printf_escaped (_("Change the password for the “%s” token"), + NS_ConvertUTF16toUTF8 (aTokenName).get ()); + } + + gtk_message_dialog_set_markup (GTK_MESSAGE_DIALOG (dialog), + message); + g_free (message); + + int response; + nsString oldPassword; + PRBool pwdOk, needsLogin; + do { + response = gtk_dialog_run (GTK_DIALOG (dialog)); + + if (status != nsIPKCS11Slot::SLOT_UNINITIALIZED) + { + const char *pwd = ephy_password_dialog_get_password (password_dialog); + oldPassword = NS_ConvertUTF8toUTF16 (pwd); + } + } while (response == GTK_RESPONSE_OK && + status != nsIPKCS11Slot::SLOT_UNINITIALIZED && + NS_SUCCEEDED (token->NeedsLogin (&needsLogin)) && needsLogin && + NS_SUCCEEDED (token->CheckPassword (oldPassword.get (), &pwdOk) && + !pwdOk)); + + if (response == GTK_RESPONSE_ACCEPT) + { + const char *pwd = ephy_password_dialog_get_new_password (password_dialog); + + NS_ConvertUTF8toUTF16 newPassword (pwd); + + if (status == nsIPKCS11Slot::SLOT_UNINITIALIZED) + { + rv = token->InitPassword (newPassword.get ()); + } + else + { + rv = token->ChangePassword (oldPassword.get (), + newPassword.get ()); + } + } + else + { + rv = NS_OK; + } + + gtk_widget_destroy (GTK_WIDGET (dialog)); + + *aCancelled = response != GTK_RESPONSE_ACCEPT; + + return rv; +} + +/* void getPassword (in nsIInterfaceRequestor ctx, in wstring tokenName, out wstring password, out boolean canceled); */ +NS_IMETHODIMP +GtkNSSDialogs::GetPassword(nsIInterfaceRequestor *aCtx, + const PRUnichar *aTokenName, + PRUnichar **aPassword, + PRBool *aCancelled) +{ + NS_ENSURE_ARG_POINTER(aCancelled); + + nsresult rv; + nsCOMPtr<nsIPK11Token> token; + nsCOMPtr<nsIPKCS11Slot> slot; + rv = GetTokenAndSlotFromName (aTokenName, getter_AddRefs (token), + getter_AddRefs (slot)); + NS_ENSURE_SUCCESS (rv, rv); + NS_ENSURE_TRUE (token && slot, NS_ERROR_FAILURE); + + AutoJSContextStack stack; + rv = stack.Init (); + if (NS_FAILED (rv)) return rv; + + nsCOMPtr<nsIDOMWindow> parent (do_GetInterface (aCtx)); + GtkWidget *gparent = EphyUtils::FindGtkParent (parent); + + AutoWindowModalState modalState (parent); + + EphyPasswordDialogFlags flags = + EphyPasswordDialogFlags (EPHY_PASSWORD_DIALOG_FLAGS_SHOW_PASSWORD); + + GtkWidget *dialog = ephy_password_dialog_new + (gparent, + _("Get Token Password"), /* FIXME */ + flags); + EphyPasswordDialog *password_dialog = EPHY_PASSWORD_DIALOG (dialog); + + /* Translators: A "token" is something that enables the user to authenticate himself or + * prove his credentials. This can be either a hardware device (e.g. a smart-card), or + * a data file (e.g. a cryptographic certificate). + */ + char *message = g_markup_printf_escaped (_("Please enter the password for the “%s” token"), + NS_ConvertUTF16toUTF8 (aTokenName).get ()); + gtk_message_dialog_set_markup (GTK_MESSAGE_DIALOG (dialog), + message); + g_free (message); + + int response = gtk_dialog_run (GTK_DIALOG (dialog)); + + if (response == GTK_RESPONSE_ACCEPT) + { + const char *pwd = ephy_password_dialog_get_password (password_dialog); + *aPassword = NS_StringCloneData (NS_ConvertUTF8toUTF16 (pwd)); + } + + gtk_widget_destroy (GTK_WIDGET (dialog)); + + *aCancelled = response != GTK_RESPONSE_ACCEPT; + + return NS_OK; +} + +/* nsITokenDialogs */ + +static void +SelectionChangedCallback (GtkComboBox *combo, + GtkDialog *dialog) +{ + int active = gtk_combo_box_get_active (combo); + gtk_dialog_set_response_sensitive (dialog, GTK_RESPONSE_ACCEPT, active >= 0); +} + +/* void ChooseToken (in nsIInterfaceRequestor ctx, + [array, size_is (count)] in wstring tokenNameList, + in unsigned long count, + out wstring tokenName, + out boolean canceled); */ +NS_IMETHODIMP +GtkNSSDialogs::ChooseToken (nsIInterfaceRequestor *aContext, + const PRUnichar **tokenNameList, + PRUint32 count, + PRUnichar **_tokenName, + PRBool *_cancelled) +{ + NS_ENSURE_ARG (tokenNameList); + NS_ENSURE_ARG (count); + + nsresult rv; + AutoJSContextStack stack; + rv = stack.Init (); + if (NS_FAILED (rv)) return rv; + + /* Didn't you know it? MOZILLA SUCKS! ChooseToken is always called with |aContext| == NULL! See + * http://bonsai.mozilla.org/cvsblame.cgi?file=mozilla/security/manager/ssl/src/nsKeygenHandler.cpp&rev=1.39&mark=346#346 + * Need to investigate if we it's always called directly from code called from JS, in which case we + * can use EphyJSUtils::GetDOMWindowFromCallContext. + */ + nsCOMPtr<nsIDOMWindow> parent (do_GetInterface (aContext)); + GtkWidget *gparent = EphyUtils::FindGtkParent (parent); + + AutoWindowModalState modalState (parent); + + GtkWidget *dialog = gtk_message_dialog_new + (GTK_WINDOW (gparent), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_OTHER, + GTK_BUTTONS_CANCEL, + _("Please select a token:")); + + gtk_window_set_icon_name (GTK_WINDOW (dialog), EPHY_STOCK_EPHY); + + GtkWidget *combo = gtk_combo_box_new_text (); + for (PRUint32 i = 0; i < count; ++i) { + gtk_combo_box_append_text (GTK_COMBO_BOX (combo), + NS_ConvertUTF16toUTF8 (tokenNameList[i]).get ()); + } + gtk_combo_box_set_active (GTK_COMBO_BOX (combo), -1); + g_signal_connect (combo, "changed", + G_CALLBACK (SelectionChangedCallback), dialog); + + /* FIXME: View Cert button? */ + + GtkWidget *vbox = GTK_MESSAGE_DIALOG (dialog)->label->parent; + gtk_box_pack_start (GTK_BOX (vbox), combo, FALSE, FALSE, 0); + + gtk_dialog_add_button (GTK_DIALOG (dialog), + _("_Select"), + GTK_RESPONSE_ACCEPT); + + gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_REJECT); + + int response = gtk_dialog_run (GTK_DIALOG (dialog)); + int selected = gtk_combo_box_get_active (GTK_COMBO_BOX (combo)); + + gtk_widget_destroy (dialog); + + *_cancelled = response != GTK_RESPONSE_ACCEPT; + + if (response == GTK_RESPONSE_ACCEPT) { + NS_ENSURE_TRUE (selected >= 0 && selected < (int) count, NS_ERROR_FAILURE); + *_tokenName = NS_StringCloneData (nsDependentString (tokenNameList[selected])); + } + + return NS_OK; +} + +/* nsIDOMCryptoDialogs */ + +/* Note: this interface sucks! See https://bugzilla.mozilla.org/show_bug.cgi?id=341914 */ + +/* boolean ConfirmKeyEscrow (in nsIX509Cert escrowAuthority); */ +NS_IMETHODIMP +GtkNSSDialogs::ConfirmKeyEscrow (nsIX509Cert *aEscrowAuthority, + PRBool *_retval) +{ + NS_ENSURE_ARG (aEscrowAuthority); + + nsresult rv; + AutoJSContextStack stack; + rv = stack.Init (); + if (NS_FAILED (rv)) return rv; + +#if 0 + nsCOMPtr<nsIDOMWindow> parent (do_GetInterface (aCtx)); +#endif + nsCOMPtr<nsIDOMWindow> parent (EphyJSUtils::GetDOMWindowFromCallContext ()); + GtkWidget *gparent = EphyUtils::FindGtkParent (parent); + + AutoWindowModalState modalState (parent); + + /* FIXME: is that guaranteed to be non-empty? */ + nsString commonName; + aEscrowAuthority->GetCommonName (commonName); + + GtkWidget *dialog = gtk_message_dialog_new + (GTK_WINDOW (gparent), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_WARNING /* QUESTION really but it's also a strong warnings... */, + GTK_BUTTONS_NONE, + _("Escrow the secret key?")); + + /* FIXME: If I understand the documentation of generateCRMFRequest + * correctly, key escrow is never used for signing keys (if it were, + * we'd have to warn that the cert authority can forge your signature + * too). + */ + gtk_message_dialog_format_secondary_text + (GTK_MESSAGE_DIALOG (dialog), + _("The certificate authority “%s” requests that you give it a copy " + "of the newly generated secret key.\n\n" + "This will enable the certificate authority read any " + "communications encrypted with this key " + "without your knowledge or consent.\n\n" + "It is strongly recommended not to allow it."), + NS_ConvertUTF16toUTF8 (commonName).get ()); + + gtk_window_set_icon_name (GTK_WINDOW (dialog), EPHY_STOCK_EPHY); + + GtkWidget *button = gtk_dialog_add_button (GTK_DIALOG (dialog), + _("_Reject"), + GTK_RESPONSE_REJECT); + gtk_dialog_add_button (GTK_DIALOG (dialog), + _("_Allow"), + GTK_RESPONSE_ACCEPT); + /* FIXME: View Cert button? */ + + gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_REJECT); + gtk_widget_grab_focus (button); + + int response = gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + + *_retval = response == GTK_RESPONSE_ACCEPT; + + return NS_OK; +} diff --git a/embed/xulrunner/embed/GtkNSSDialogs.h b/embed/xulrunner/embed/GtkNSSDialogs.h new file mode 100644 index 000000000..2edd1ffbe --- /dev/null +++ b/embed/xulrunner/embed/GtkNSSDialogs.h @@ -0,0 +1,61 @@ +/* + * Copyright © 2003 Crispin Flowerday <gnome@flowerday.cx> + * Copyright © 2006 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#ifndef GTKNSSDIALOGS_H +#define GTKNSSDIALOGS_H 1 + +#include <nsIBadCertListener.h> +#include <nsICertificateDialogs.h> +#include <nsITokenPasswordDialogs.h> +#include <nsITokenDialogs.h> +#include <nsIDOMCryptoDialogs.h> + +class nsIPK11Token; +class nsIPKCS11Slot; + +/* 7a50a10d-9425-4e12-84b1-5822edacd8ce */ +#define GTK_NSSDIALOGS_CID \ + {0x7a50a10d, 0x9425, 0x4e12, {0x84, 0xb1, 0x58, 0x22, 0xed, 0xac, 0xd8, 0xce}} + +#define GTK_NSSDIALOGS_CLASSNAME "Gtk NSS Dialogs" + +class GtkNSSDialogs : public nsIBadCertListener, + public nsICertificateDialogs, + public nsITokenPasswordDialogs, + public nsITokenDialogs, + public nsIDOMCryptoDialogs +{ + public: + NS_DECL_ISUPPORTS + NS_DECL_NSIBADCERTLISTENER + NS_DECL_NSICERTIFICATEDIALOGS + NS_DECL_NSITOKENPASSWORDDIALOGS + NS_DECL_NSITOKENDIALOGS + NS_DECL_NSIDOMCRYPTODIALOGS + + GtkNSSDialogs(); + virtual ~GtkNSSDialogs(); + + private: + nsresult GetTokenAndSlotFromName(const PRUnichar*, nsIPK11Token**, nsIPKCS11Slot**); +}; + +#endif /* GTKNSSDIALOGS_H */ diff --git a/embed/xulrunner/embed/GtkNSSKeyPairDialogs.cpp b/embed/xulrunner/embed/GtkNSSKeyPairDialogs.cpp new file mode 100644 index 000000000..3b9e405cc --- /dev/null +++ b/embed/xulrunner/embed/GtkNSSKeyPairDialogs.cpp @@ -0,0 +1,216 @@ +/* + * GtkNSSKeyPairDialogs.cpp + * + * Copyright © 2003 Crispin Flowerday <gnome@flowerday.cx> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +/* + * This file provides Gtk implementations of the mozilla Generating Key Pair + * dialogs. + */ + +#include "mozilla-config.h" +#include "config.h" + +#include <glib/gi18n.h> +#include <gtk/gtkdialog.h> +#include <gtk/gtkhbox.h> +#include <gtk/gtkimage.h> +#include <gtk/gtklabel.h> +#include <gtk/gtkmain.h> +#include <gtk/gtkprogressbar.h> +#include <gtk/gtkstock.h> +#include <gtk/gtkvbox.h> + +#include <nsIDOMWindow.h> +#include <nsIInterfaceRequestor.h> +#include <nsIInterfaceRequestorUtils.h> +#include <nsIKeygenThread.h> +#include <nsIObserver.h> +#include <nsIServiceManager.h> + +#include "ephy-debug.h" +#include "ephy-gui.h" +#include "ephy-stock-icons.h" + +#include "AutoJSContextStack.h" +#include "AutoWindowModalState.h" +#include "EphyUtils.h" + +#include "GtkNSSKeyPairDialogs.h" + +GtkNSSKeyPairDialogs::GtkNSSKeyPairDialogs () +{ + LOG ("GtkNSSKeyPairDialogs ctor (%p)", this); +} + +GtkNSSKeyPairDialogs::~GtkNSSKeyPairDialogs () +{ + LOG ("GtkNSSKeyPairDialogs dtor (%p)", this); +} + +NS_IMPL_THREADSAFE_ISUPPORTS1 (GtkNSSKeyPairDialogs, + nsIGeneratingKeypairInfoDialogs) + +class KeyPairObserver : public nsIObserver +{ +public: + NS_DECL_NSIOBSERVER + NS_DECL_ISUPPORTS + + KeyPairObserver() : close_called (FALSE) {}; + virtual ~KeyPairObserver() {}; + + gboolean close_called; +}; + +NS_IMPL_ISUPPORTS1 (KeyPairObserver, nsIObserver); + +NS_IMETHODIMP KeyPairObserver::Observe (nsISupports *aSubject, const char *aTopic, + const PRUnichar *aData) +{ + close_called = TRUE; + return NS_OK; +} + +/* ------------------------------------------------------------ */ +static void +begin_busy (GtkWidget *widget) +{ + static GdkCursor *cursor = NULL; + + if (cursor == NULL) cursor = gdk_cursor_new (GDK_WATCH); + + if (!GTK_WIDGET_REALIZED (widget)) gtk_widget_realize (GTK_WIDGET(widget)); + + gdk_window_set_cursor (GTK_WIDGET (widget)->window, cursor); + + /* Eek! FIXME: AutoJSContextStack! */ + while (gtk_events_pending ()) gtk_main_iteration (); +} + +static void +end_busy (GtkWidget *widget) +{ + gdk_window_set_cursor (GTK_WIDGET(widget)->window, NULL); +} + + +struct KeyPairInfo +{ + GtkWidget *progress; + GtkWidget *dialog; + KeyPairObserver *helper; +}; + + +static gboolean +generating_timeout_cb (KeyPairInfo *info) +{ + gtk_progress_bar_pulse (GTK_PROGRESS_BAR (info->progress)); + + if (info->helper->close_called) + { + gtk_dialog_response (GTK_DIALOG (info->dialog), GTK_RESPONSE_OK); + } + return TRUE; +} + + +/* void displayGeneratingKeypairInfo (in nsIInterfaceRequestor ctx, + in nsIKeygenThread runnable); */ +NS_IMETHODIMP +GtkNSSKeyPairDialogs::DisplayGeneratingKeypairInfo (nsIInterfaceRequestor *ctx, + nsIKeygenThread *runnable) +{ + GtkWidget *dialog, *progress, *label, *vbox; + gint timeout_id; + + nsresult rv; + AutoJSContextStack stack; + rv = stack.Init (); + if (NS_FAILED (rv)) return rv; + + nsCOMPtr<nsIDOMWindow> parent = do_GetInterface (ctx); + GtkWindow *gparent = GTK_WINDOW (EphyUtils::FindGtkParent (parent)); + + AutoWindowModalState modalState (parent); + + dialog = gtk_dialog_new_with_buttons ("", gparent, + GTK_DIALOG_DESTROY_WITH_PARENT, (char *) NULL); + + if (gparent) + { + gtk_window_group_add_window (ephy_gui_ensure_window_group (gparent), + GTK_WINDOW (dialog)); + } + + gtk_window_set_icon_name (GTK_WINDOW (dialog), EPHY_STOCK_EPHY); + + gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE); + gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE); + gtk_container_set_border_width (GTK_CONTAINER (dialog), 5); + + vbox = gtk_vbox_new (FALSE, 12); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), vbox, TRUE, TRUE, 0); + + label = gtk_label_new (NULL); + gtk_label_set_use_markup (GTK_LABEL (label), TRUE); + gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.0); + gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0); + + char *msg = g_strdup_printf ("<span weight=\"bold\" size=\"larger\">%s</span>\n\n%s", + _("Generating Private Key."), + _("Please wait while a new private key is " + "generated. This process could take a few minutes." )); + gtk_label_set_markup (GTK_LABEL(label), msg); + g_free (msg); + + progress = gtk_progress_bar_new (); + gtk_box_pack_start (GTK_BOX (vbox), progress, TRUE, TRUE, 0); + + /* Create a helper class that just waits for close events + * from the other thread */ + nsCOMPtr<KeyPairObserver> helper = new KeyPairObserver; + + KeyPairInfo callback_data = { progress, dialog, helper }; + timeout_id = g_timeout_add (100, (GSourceFunc)generating_timeout_cb, &callback_data); + + gtk_widget_show_all (dialog); + gtk_widget_hide (GTK_DIALOG (dialog)->action_area); + + begin_busy (dialog); + runnable->StartKeyGeneration (helper); + int res = gtk_dialog_run (GTK_DIALOG (dialog)); + if (res != GTK_RESPONSE_OK && helper->close_called == FALSE) + { + /* Ignore the already_closed flag, our nsIDOMWindowInterna::Close + * function just sets a flag, it doesn't close the window, so we + * dont have a race condition */ + PRBool already_closed = FALSE; + runnable->UserCanceled (&already_closed); + } + + g_source_remove (timeout_id); + end_busy (dialog); + gtk_widget_destroy (dialog); + return NS_OK; +} diff --git a/embed/xulrunner/embed/GtkNSSKeyPairDialogs.h b/embed/xulrunner/embed/GtkNSSKeyPairDialogs.h new file mode 100644 index 000000000..f4b92d9e1 --- /dev/null +++ b/embed/xulrunner/embed/GtkNSSKeyPairDialogs.h @@ -0,0 +1,45 @@ +/* + * Copyright © 2003 Crispin Flowerday <gnome@flowerday.cx> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * + * $Id$ + */ + +#ifndef GTKNSSKEYPAIRDIALOGS_H +#define GTKNSSKEYPAIRDIALOGS_H 1 + +#include <nsIGenKeypairInfoDlg.h> + +// 6a8b1aff-ae8b-4751-982e-4ce5ad544100 +#define GTK_NSSKEYPAIRDIALOGS_CID \ + {0x6a8b1aff, 0xae8b, 0x4751, {0x98, 0x2e, 0x4c, 0xe5, 0xad, 0x54, 0x41, 0x10}} + +#define GTK_NSSKEYPAIRDIALOGS_CLASSNAME "Gtk NSS Key Pair Dialogs" + +class GtkNSSKeyPairDialogs +: public nsIGeneratingKeypairInfoDialogs +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIGENERATINGKEYPAIRINFODIALOGS + + GtkNSSKeyPairDialogs(); + virtual ~GtkNSSKeyPairDialogs(); +}; + + +#endif /* GTKNSSKEYPAIRDIALOGS_H */ diff --git a/embed/xulrunner/embed/GtkNSSSecurityWarningDialogs.cpp b/embed/xulrunner/embed/GtkNSSSecurityWarningDialogs.cpp new file mode 100644 index 000000000..b50b3762a --- /dev/null +++ b/embed/xulrunner/embed/GtkNSSSecurityWarningDialogs.cpp @@ -0,0 +1,285 @@ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright © 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Terry Hayes <thayes@netscape.com> + * Javier Delgadillo <javi@netscape.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** + * + * Copyright © 2005 Christian Persch + * + * $Id$ + */ + +#include "mozilla-config.h" +#include "config.h" + +#include <glib/gi18n.h> +#include <gtk/gtkbox.h> +#include <gtk/gtkdialog.h> +#include <gtk/gtkhbox.h> +#include <gtk/gtklabel.h> +#include <gtk/gtkvbox.h> + +#include "ephy-stock-icons.h" + +#include <nsCOMPtr.h> +#include <nsIDOMWindow.h> +#include <nsIInterfaceRequestor.h> +#include <nsIInterfaceRequestorUtils.h> +#include <nsIPrefBranch.h> +#include <nsIPrefService.h> +#include <nsIServiceManager.h> +#include <nsServiceManagerUtils.h> + +#include "AutoJSContextStack.h" +#include "AutoWindowModalState.h" +#include "EphyUtils.h" + +#include "GtkNSSSecurityWarningDialogs.h" + +NS_IMPL_THREADSAFE_ISUPPORTS1 (GtkNSSSecurityWarningDialogs, nsISecurityWarningDialogs) + +#define ENTER_SITE_PREF "security.warn_entering_secure" +#define WEAK_SITE_PREF "security.warn_entering_weak" +#define MIXEDCONTENT_PREF "security.warn_viewing_mixed" +#define INSECURE_SUBMIT_PREF "security.warn_submit_insecure" + +GtkNSSSecurityWarningDialogs::GtkNSSSecurityWarningDialogs() +{ +} + +GtkNSSSecurityWarningDialogs::~GtkNSSSecurityWarningDialogs() +{ +} + +NS_IMETHODIMP +GtkNSSSecurityWarningDialogs::ConfirmEnteringSecure (nsIInterfaceRequestor *aContext, + PRBool *_retval) +{ + DoDialog (aContext, + ENTER_SITE_PREF, + GTK_MESSAGE_INFO, + GTK_BUTTONS_OK, + GTK_RESPONSE_OK, + _("Security Notice"), + _("This page is loaded over a secure connection"), + _("For secure pages, the address entry has a distinct " + "color and a locked padlock icon is displayed.\n\n" + "The padlock icon in the statusbar also indicates " + "whether a page is secure."), + nsnull, _retval); + + *_retval = PR_TRUE; + return NS_OK; +} + +NS_IMETHODIMP +GtkNSSSecurityWarningDialogs::ConfirmEnteringWeak (nsIInterfaceRequestor *aContext, + PRBool *_retval) +{ + DoDialog (aContext, + WEAK_SITE_PREF, + GTK_MESSAGE_WARNING, + GTK_BUTTONS_OK, + GTK_RESPONSE_OK, + _("Security Warning"), + _("This page is loaded over a low security connection"), + _("Any information you see or enter on this page could " + "easily be intercepted by a third party."), + nsnull, _retval); + + *_retval = PR_TRUE; + return NS_OK; +} + +NS_IMETHODIMP +GtkNSSSecurityWarningDialogs::ConfirmLeavingSecure (nsIInterfaceRequestor *aContext, + PRBool *_retval) +{ + /* don't prompt */ + *_retval = PR_TRUE; + return NS_OK; +} + +NS_IMETHODIMP +GtkNSSSecurityWarningDialogs::ConfirmMixedMode (nsIInterfaceRequestor *aContext, + PRBool *_retval) +{ + DoDialog (aContext, + MIXEDCONTENT_PREF, + GTK_MESSAGE_WARNING, + GTK_BUTTONS_OK, + GTK_RESPONSE_OK, + _("Security Warning"), + _("Some parts of this page are loaded over an insecure connection"), + _("Some information you see or enter will be sent over an insecure " + "connection, and could easily be intercepted by a third party."), + nsnull, _retval); + + *_retval = PR_TRUE; + return NS_OK; +} + +NS_IMETHODIMP +GtkNSSSecurityWarningDialogs::ConfirmPostToInsecure (nsIInterfaceRequestor *aContext, + PRBool* _retval) +{ + DoDialog (aContext, + INSECURE_SUBMIT_PREF, + GTK_MESSAGE_WARNING, + GTK_BUTTONS_CANCEL, + GTK_RESPONSE_ACCEPT, + _("Security Warning"), + _("Send this information over an insecure connection?"), + _("The information you have entered will be sent over an " + "insecure connection, and could easily be intercepted " + "by a third party."), + _("_Send"), + _retval); + + return NS_OK; +} + +NS_IMETHODIMP +GtkNSSSecurityWarningDialogs::ConfirmPostToInsecureFromSecure (nsIInterfaceRequestor *aContext, + PRBool* _retval) +{ + DoDialog (aContext, + nsnull, /* No preference for this one - it's too important */ + GTK_MESSAGE_WARNING, + GTK_BUTTONS_CANCEL, + GTK_RESPONSE_CANCEL, + _("Security Warning"), + _("Send this information over an insecure connection?"), + _("Although this page was loaded over a secure connection, " + "the information you have entered will be sent over an " + "insecure connection, and could easily be intercepted by " + "a third party."), + _("_Send"), + _retval); + + return NS_OK; +} + +void +GtkNSSSecurityWarningDialogs::DoDialog (nsIInterfaceRequestor *aContext, + const char *aPrefName, + GtkMessageType aType, + GtkButtonsType aButtons, + int aDefaultResponse, + const char *aTitle, + const char *aPrimary, + const char *aSecondary, + const char *aButtonText, + PRBool *_retval) +{ + *_retval = PR_FALSE; + + nsresult rv; + PRBool show = PR_TRUE; + nsCOMPtr<nsIPrefBranch> prefBranch + (do_GetService (NS_PREFSERVICE_CONTRACTID)); + if (prefBranch && aPrefName) + { + rv = prefBranch->GetBoolPref (aPrefName, &show); + if (NS_FAILED(rv)) show = PR_TRUE; + } + + char *showOncePref = NULL; + PRBool showOnce = PR_FALSE; + if (!show && prefBranch && aPrefName) + { + showOncePref = g_strconcat (aPrefName, ".show_once", (char *) NULL); + rv = prefBranch->GetBoolPref (showOncePref, &showOnce); + if (NS_FAILED (rv)) showOnce = PR_FALSE; + } + + if (!show && !showOnce) + { + g_free (showOncePref); + *_retval = PR_TRUE; + return; + } + + /* On 1.8.0, domWin will be always nsnull, because of + * https://bugzilla.mozilla.org/show_bug.cgi?id=277587 + */ + nsCOMPtr<nsIDOMWindow> domWin (do_GetInterface (aContext)); + GtkWidget *parent = EphyUtils::FindGtkParent (domWin); + + AutoJSContextStack stack; + rv = stack.Init (); + if (NS_FAILED (rv)) return; + + AutoWindowModalState modalState (domWin); + + GtkWidget *dialog = gtk_message_dialog_new (GTK_WINDOW (parent), + GTK_DIALOG_MODAL, aType, + aButtons, aPrimary); + + if (parent && GTK_WINDOW (parent)->group) + { + gtk_window_group_add_window (GTK_WINDOW (parent)->group, + GTK_WINDOW (dialog)); + } + + if (aSecondary) + { + gtk_message_dialog_format_secondary_text + (GTK_MESSAGE_DIALOG (dialog), aSecondary); + } + + if (aButtonText) + { + gtk_dialog_add_button (GTK_DIALOG (dialog), aButtonText, + GTK_RESPONSE_ACCEPT); + } + + gtk_dialog_set_default_response (GTK_DIALOG (dialog), aDefaultResponse); + + gtk_window_set_title (GTK_WINDOW (dialog), aTitle); + gtk_window_set_icon_name (GTK_WINDOW (dialog), EPHY_STOCK_EPHY); + + int response = gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + + *_retval = (response == GTK_RESPONSE_ACCEPT || response == GTK_RESPONSE_OK); + + if (prefBranch && showOncePref && showOnce && *_retval) + { + prefBranch->SetBoolPref (showOncePref, PR_FALSE); + } + + g_free (showOncePref); +} diff --git a/embed/xulrunner/embed/GtkNSSSecurityWarningDialogs.h b/embed/xulrunner/embed/GtkNSSSecurityWarningDialogs.h new file mode 100644 index 000000000..a84ea6585 --- /dev/null +++ b/embed/xulrunner/embed/GtkNSSSecurityWarningDialogs.h @@ -0,0 +1,83 @@ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright © 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Terry Hayes <thayes@netscape.com> + * Javier Delgadillo <javi@netscape.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** + * + * Copyright © 2005 Christian Persch + * + * $Id$ + */ + +#ifndef GTK_NSSSECURITYDIALOGS_H +#define GTK_NSSSECURITYDIALOGS_H + +#include <gtk/gtkmessagedialog.h> + +#include <nsISecurityWarningDialogs.h> + +#define GTK_NSSSECURITYWARNINGDIALOGS_CLASSNAME "Epiphany Security Warning Dialogs Class" +#define GTK_NSSSECURITYWARNINGDIALOGS_CID \ +{ \ + /* 1f5eac0a-d7e3-4f8e-b4d5-7240f7cba269 */ \ + 0x1f5eac0a, \ + 0xd7e3, \ + 0x4f8e, \ + { 0xb4, 0xd5, 0x72, 0x40, 0xf7, 0xcb, 0xa2, 0x69 } \ +} + +class GtkNSSSecurityWarningDialogs : public nsISecurityWarningDialogs +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISECURITYWARNINGDIALOGS + + GtkNSSSecurityWarningDialogs(); + virtual ~GtkNSSSecurityWarningDialogs(); + +protected: + void DoDialog (nsIInterfaceRequestor *aContext, + const char *aPrefName, + GtkMessageType aType, + GtkButtonsType aButtons, + int aDefaultResponse, + const char *aTitle, + const char *aPrimary, + const char *aSecondary, + const char *aButtonText, + PRBool *_retval); +}; + +#endif /* !GTK_NSSSECURITYDIALOGS_H */ diff --git a/embed/xulrunner/embed/Makefile.am b/embed/xulrunner/embed/Makefile.am new file mode 100644 index 000000000..ded6802e7 --- /dev/null +++ b/embed/xulrunner/embed/Makefile.am @@ -0,0 +1,159 @@ +noinst_LTLIBRARIES = libephyxulrunnerembed.la + +libephyxulrunnerembed_la_SOURCES = \ + AutoJSContextStack.cpp \ + AutoJSContextStack.h \ + AutoWindowModalState.cpp \ + AutoWindowModalState.h \ + ContentHandler.cpp \ + ContentHandler.h \ + EphyAboutModule.cpp \ + EphyAboutModule.h \ + EphyBadCertRejector.cpp \ + EphyBadCertRejector.h \ + EphyContentPolicy.cpp \ + EphyContentPolicy.h \ + EphyDirectoryProvider.cpp \ + EphyDirectoryProvider.h \ + EphyHeaderSniffer.cpp \ + EphyHeaderSniffer.h \ + EphyBrowser.cpp \ + EphyBrowser.h \ + EphyFind.cpp \ + EphyFind.h \ + EphyHistoryListener.cpp \ + EphyHistoryListener.h \ + EphyPromptService.cpp \ + EphyPromptService.h \ + EphyRedirectChannel.cpp \ + EphyRedirectChannel.h \ + EphySidebar.cpp \ + EphySidebar.h \ + EphySingle.cpp \ + EphySingle.h \ + EphyUtils.cpp \ + EphyUtils.h \ + EventContext.cpp \ + EventContext.h \ + GeckoCookiePromptService.cpp \ + GeckoCookiePromptService.h \ + GeckoFormSigningDialog.cpp \ + GeckoFormSigningDialog.h \ + GeckoPrintService.cpp \ + GeckoPrintService.h \ + GeckoPrintSession.cpp \ + GeckoPrintSession.h \ + GlobalHistory.cpp \ + GlobalHistory.h \ + MozDownload.cpp \ + MozDownload.h \ + MozRegisterComponents.cpp \ + MozRegisterComponents.h \ + mozilla-download.cpp \ + mozilla-download.h \ + mozilla-embed.cpp \ + mozilla-embed.h \ + mozilla-embed-event.cpp \ + mozilla-embed-event.h \ + mozilla-embed-find.cpp \ + mozilla-embed-find.h \ + mozilla-embed-persist.cpp \ + mozilla-embed-persist.h \ + mozilla-embed-single.cpp \ + mozilla-embed-single.h \ + mozilla-notifiers.cpp \ + mozilla-notifiers.h + +if ENABLE_FILEPICKER +libephyxulrunnerembed_la_SOURCES += \ + FilePicker.cpp \ + FilePicker.h +endif + +if HAVE_MOZILLA_PSM +libephyxulrunnerembed_la_SOURCES += \ + GtkNSSClientAuthDialogs.cpp \ + GtkNSSClientAuthDialogs.h \ + GtkNSSDialogs.cpp \ + GtkNSSDialogs.h \ + GtkNSSKeyPairDialogs.cpp \ + GtkNSSKeyPairDialogs.h \ + GtkNSSSecurityWarningDialogs.cpp\ + GtkNSSSecurityWarningDialogs.h +endif + +if ENABLE_CERTIFICATE_MANAGER +libephyxulrunnerembed_la_SOURCES += \ + mozilla-x509-cert.cpp \ + mozilla-x509-cert.h +endif + +if ENABLE_SPELLCHECKER +libephyxulrunnerembed_la_SOURCES += \ + GeckoSpellCheckEngine.cpp \ + GeckoSpellCheckEngine.h +endif + +mozilla_include_subdirs = \ + . \ + caps \ + chardet \ + chrome \ + commandhandler \ + content \ + cookie \ + docshell \ + dom \ + exthandler \ + fastfind \ + helperAppDlg \ + find \ + gfx \ + gtkembedmoz \ + history \ + js \ + layout \ + locale \ + mimetype \ + necko \ + nkcache \ + passwordmgr \ + pipboot \ + pipnss \ + pref \ + shistory \ + sidebar \ + spellchecker \ + uriloader \ + uconv \ + wallet \ + webbrowserpersist \ + webbrwsr \ + widget \ + windowwatcher \ + xmlextras \ + xpcom \ + xpconnect + +libephyxulrunnerembed_la_CPPFLAGS = \ + -I$(top_srcdir)/lib \ + -I$(top_srcdir)/embed \ + -I$(top_srcdir) \ + -I$(top_srcdir)/embed/gecko/src \ + -I$(top_builddir)/embed/gecko/src \ + -DSHARE_DIR=\"$(pkgdatadir)\" \ + -DPLUGINDIR=\"$(libdir)/epiphany/$(EPIPHANY_MAJOR)/plugins\" \ + -DMOZILLA_HOME=\"$(LIBXUL_LIBDIR)\" \ + -DMOZILLA_PREFIX=\"$(LIBXUL_PREFIX)\" \ + -DMOZILLA_NATIVE_PLUGINSDIR=\"$(libdir)/mozilla/plugins\" \ + -DUA_VERSION=\"$(EPIPHANY_UA_VERSION)\" \ + -DALLOW_PRIVATE_API \ + $(AM_CPPFLAGS) + +libephyxulrunnerembed_la_CXXFLAGS = \ + $(LIBXUL_CFLAGS) \ + $(DEPENDENCIES_CFLAGS) \ + $(AM_CXXFLAGS) + +libephyxulrunnerembed_la_LIBADD = \ + $(top_builddir)/embed/xulrunner/src/libgnomegeckoembed-0.0.la diff --git a/embed/xulrunner/embed/MozDownload.cpp b/embed/xulrunner/embed/MozDownload.cpp new file mode 100644 index 000000000..eed7adcd9 --- /dev/null +++ b/embed/xulrunner/embed/MozDownload.cpp @@ -0,0 +1,787 @@ +/* -*- 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright © 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Conrad Carlen <ccarlen@netscape.com> + * + * Adapted for epiphany by Marco Pesenti Gritti <marco@gnome.org> + * + * 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 ***** + * + * $Id$ + */ + +#include "mozilla-config.h" +#include "config.h" + +#include <stdlib.h> + +#include <glib/gi18n.h> + +#include <nsStringAPI.h> + +#include <nsComponentManagerUtils.h> +#include <nsICancelable.h> +#include <nsIChannel.h> +#include <nsIDOMDocument.h> +#include <nsIFileURL.h> +#include <nsIIOService.h> +#include <nsILocalFile.h> +#include <nsIMIMEInfo.h> +#include <nsIObserver.h> +#include <nsIRequest.h> +#include <nsIURI.h> +#include <nsIWritablePropertyBag2.h> +#include <nsIWebBrowserPersist.h> + +#include <nsMemory.h> +#include <nsNetError.h> +#include <nsServiceManagerUtils.h> + +#include "EphyBadCertRejector.h" +#include "EphyUtils.h" + +#include "eel-gconf-extensions.h" +#include "ephy-debug.h" +#include "ephy-file-helpers.h" +#include "ephy-prefs.h" +#include "mozilla-download.h" + +#include "MozDownload.h" + +/* Minimum time between progress updates */ +#define PROGRESS_RATE 500000 /* microsec */ + +const char* const persistContractID = "@mozilla.org/embedding/browser/nsWebBrowserPersist;1"; + +MozDownload::MozDownload() : + mTotalProgress(-1), + mCurrentProgress(0), + mMaxSize(-1), + mStatus(NS_OK), + mEmbedPersist(nsnull), + mDownloadState(EPHY_DOWNLOAD_INITIALISING) +{ + LOG ("MozDownload ctor (%p)", (void *) this); +} + +MozDownload::~MozDownload() +{ + LOG ("MozDownload dtor (%p)", (void *) this); + + NS_ASSERTION (!mEphyDownload, "MozillaDownload still alive!"); +} + +NS_IMPL_ISUPPORTS4 (MozDownload, + nsIWebProgressListener, + nsIWebProgressListener2, + nsITransfer, + nsIInterfaceRequestor) + +nsresult +MozDownload::InitForEmbed (nsIURI *aSource, nsIURI *aTarget, const nsAString &aDisplayName, + nsIMIMEInfo *aMIMEInfo, PRTime aStartTime, nsILocalFile *aTempFile, + nsICancelable *aCancelable, MozillaEmbedPersist *aEmbedPersist, + PRInt64 aMaxSize) +{ + mEmbedPersist = aEmbedPersist; + mMaxSize = aMaxSize; + return Init (aSource, aTarget, aDisplayName, aMIMEInfo, aStartTime, aTempFile, aCancelable); +} + +/* void init (in nsIURI aSource, in nsIURI aTarget, in AString aDisplayName, in nsIMIMEInfo aMIMEInfo, in PRTime startTime, in nsILocalFile aTempFile, in nsICancelable aCancelable); */ +NS_IMETHODIMP +MozDownload::Init (nsIURI *aSource, + nsIURI *aTarget, + const nsAString &aDisplayName, + nsIMIMEInfo *aMIMEInfo, + PRTime aStartTime, + nsILocalFile *aTempFile, + nsICancelable *aCancelable) +{ + PRBool addToView = PR_TRUE; + + if (mEmbedPersist) + { + EphyEmbedPersistFlags flags; + + flags = ephy_embed_persist_get_flags (EPHY_EMBED_PERSIST (mEmbedPersist)); + + addToView = !(flags & EPHY_EMBED_PERSIST_NO_VIEW); + } + + mSource = aSource; + mDestination = aTarget; + mStartTime = aStartTime; + mTotalProgress = 0; + mCurrentProgress = 0; + mPercentComplete = 0; + mInterval = PROGRESS_RATE; + mLastUpdate = mStartTime; + mMIMEInfo = aMIMEInfo; + + /* This will create a refcount cycle, which needs to be broken in ::OnStateChange */ + mCancelable = aCancelable; + + if (addToView) + { + DownloaderView *dview; + dview = EPHY_DOWNLOADER_VIEW + (ephy_embed_shell_get_downloader_view (embed_shell)); + mEphyDownload = mozilla_download_new (this); + g_object_add_weak_pointer (G_OBJECT (mEphyDownload), + (gpointer *) &mEphyDownload); + downloader_view_add_download (dview, mEphyDownload); + g_object_unref (mEphyDownload); + } + else + { + mEphyDownload = nsnull; + } + + return NS_OK; +} + +NS_IMETHODIMP +MozDownload::GetSource(nsIURI **aSource) +{ + NS_ENSURE_ARG_POINTER(aSource); + NS_IF_ADDREF(*aSource = mSource); + + return NS_OK; +} + +NS_IMETHODIMP +MozDownload::GetTargetFile (nsILocalFile** aTargetFile) +{ + nsresult rv; + + nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(mDestination, &rv); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr<nsIFile> file; + rv = fileURL->GetFile(getter_AddRefs(file)); + if (NS_SUCCEEDED(rv)) + rv = CallQueryInterface(file, aTargetFile); + return rv; +} + +NS_IMETHODIMP +MozDownload::GetPercentComplete(PRInt32 *aPercentComplete) +{ + NS_ENSURE_ARG_POINTER(aPercentComplete); + *aPercentComplete = mPercentComplete; + + return NS_OK; +} + +NS_IMETHODIMP +MozDownload::GetTotalProgress(PRInt64 *aTotalProgress) +{ + NS_ENSURE_ARG_POINTER(aTotalProgress); + *aTotalProgress = mTotalProgress; + + return NS_OK; +} + +NS_IMETHODIMP +MozDownload::GetCurrentProgress(PRInt64 *aCurrentProgress) +{ + NS_ENSURE_ARG_POINTER(aCurrentProgress); + *aCurrentProgress = mCurrentProgress; + + return NS_OK; +} + +NS_IMETHODIMP +MozDownload::GetState(EphyDownloadState *aDownloadState) +{ + NS_ENSURE_ARG_POINTER(aDownloadState); + *aDownloadState = mDownloadState; + + return NS_OK; +} + +NS_IMETHODIMP +MozDownload::GetElapsedTime(PRInt64 *aElapsedTime) +{ + NS_ENSURE_ARG_POINTER(aElapsedTime); + *aElapsedTime = PR_Now() - mStartTime; + + return NS_OK; +} + +NS_IMETHODIMP +MozDownload::GetMIMEInfo(nsIMIMEInfo **aMIMEInfo) +{ + NS_ENSURE_ARG_POINTER(aMIMEInfo); + NS_IF_ADDREF(*aMIMEInfo = mMIMEInfo); + + return NS_OK; +} + +NS_IMETHODIMP +MozDownload::OnStateChange (nsIWebProgress *aWebProgress, nsIRequest *aRequest, + PRUint32 aStateFlags, nsresult aStatus) +{ + nsresult rv; + + if (NS_FAILED(aStatus) && NS_SUCCEEDED(mStatus)) + mStatus = aStatus; + + if (aStateFlags & STATE_START) + { + mDownloadState = EPHY_DOWNLOAD_DOWNLOADING; + + if (mEphyDownload) + { + g_signal_emit_by_name (mEphyDownload, "changed"); + } + } + + /* We will get this even in the event of a cancel */ + /* Due to a mozilla bug [https://bugzilla.mozilla.org/show_bug.cgi?id=304353], + * we'll only get STATE_STOP if we're driven from external app handler; elsewhere + * we get STATE_STOP | STATE_IS_NETWORK | STATE_IS_REQUEST. So check first if + * STATE_IS_REQUEST is set. + */ + /* Be careful that download is only completed when STATE_IS_NETWORK is set + * and many lonely STOP events may be triggered before. + */ +#ifdef GNOME_ENABLE_DEBUG +{ + nsCString spec; + if (mSource) mSource->GetSpec(spec); + + LOG ("url %s, status %x, state %x (is-stop:%s, is-network:%s, is-request:%s)", + spec.get(), aStatus, aStateFlags, + aStateFlags & STATE_STOP ? "t" : "f", + aStateFlags & STATE_IS_NETWORK ? "t" : "f", + aStateFlags & STATE_IS_REQUEST ? "t" : "f"); +} +#endif + + if (((aStateFlags & STATE_IS_REQUEST) && + (aStateFlags & STATE_IS_NETWORK) && + (aStateFlags & STATE_STOP)) || + aStateFlags == STATE_STOP) + { + LOG ("STATE_STOP"); + + /* Keep us alive */ + nsCOMPtr<nsITransfer> kungFuDeathGrip(this); + + mDownloadState = NS_SUCCEEDED (aStatus) ? EPHY_DOWNLOAD_COMPLETED : EPHY_DOWNLOAD_FAILED; + if (mEphyDownload) + { + g_signal_emit_by_name (mEphyDownload, "changed"); + } + + /* break refcount cycle */ + mCancelable = nsnull; + + if (mEmbedPersist) + { + if (NS_SUCCEEDED (aStatus)) + { + mozilla_embed_persist_completed (mEmbedPersist); + } + else + { + mozilla_embed_persist_cancelled (mEmbedPersist); + } + } + else if (NS_SUCCEEDED (aStatus)) + { + /* see http://bugzilla.gnome.org/show_bug.cgi?id=456945 */ +#ifdef HAVE_GECKO_1_9 + return NS_OK; +#else + GnomeVFSMimeApplication *helperApp; + nsCString mimeType; + rv = mMIMEInfo->GetMIMEType (mimeType); + NS_ENSURE_SUCCESS (rv, NS_ERROR_FAILURE); + + nsString description; + mMIMEInfo->GetApplicationDescription (description); + + nsCString cDesc; + NS_UTF16ToCString (description, NS_CSTRING_ENCODING_UTF8, cDesc); + + /* HACK we use the application description to decide + if we have to open the saved file */ + if (g_str_has_prefix (cDesc.get(), "gnome-default:")) + { + /* Format gnome-default:<usertime>:<helperapp id> */ + char **str = g_strsplit (cDesc.get(), ":", -1); + g_return_val_if_fail (g_strv_length (str) == 3, NS_ERROR_FAILURE); + + char *end; + guint32 user_time = strtoul (str[1], &end, 0); + + helperApp = gnome_vfs_mime_application_new_from_desktop_id (str[2]); + if (!helperApp) return NS_ERROR_FAILURE; + + nsCString aDest; + rv = mDestination->GetSpec (aDest); + NS_ENSURE_SUCCESS (rv, NS_ERROR_FAILURE); + + ephy_file_launch_application (helperApp, aDest.get (), user_time); + + gnome_vfs_mime_application_free (helperApp); + g_strfreev (str); + } + else if (g_str_has_prefix (cDesc.get(), "gnome-browse-to-file:")) + { + /* Format gnome-browse-to-file:<usertime> */ + char **str = g_strsplit (cDesc.get(), ":", -1); + g_return_val_if_fail (g_strv_length (str) == 2, NS_ERROR_FAILURE); + + char *end; + guint32 user_time = strtoul (str[1], &end, 0); + + nsCString aDest; + rv = mDestination->GetSpec (aDest); + NS_ENSURE_SUCCESS (rv, NS_ERROR_FAILURE); + + ephy_file_browse_to (aDest.get (), user_time); + + g_strfreev (str); + } +#endif /* HAVE_GECKO_1_9 */ + } + } + + return NS_OK; +} + +NS_IMETHODIMP +MozDownload::OnProgressChange (nsIWebProgress *aWebProgress, + nsIRequest *aRequest, + PRInt32 aCurSelfProgress, + PRInt32 aMaxSelfProgress, + PRInt32 aCurTotalProgress, + PRInt32 aMaxTotalProgress) +{ + return OnProgressChange64 (aWebProgress, aRequest, + aCurSelfProgress, aMaxSelfProgress, + aCurTotalProgress, aMaxTotalProgress); +} + +/* void onProgressChange64 (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long long aCurSelfProgress, in long long aMaxSelfProgress, in long long aCurTotalProgress, + in long long aMaxTotalProgress); */ +NS_IMETHODIMP +MozDownload::OnProgressChange64 (nsIWebProgress *aWebProgress, + nsIRequest *aRequest, + PRInt64 aCurSelfProgress, + PRInt64 aMaxSelfProgress, + PRInt64 aCurTotalProgress, + PRInt64 aMaxTotalProgress) +{ + if (mMaxSize >= 0 && + ((aMaxTotalProgress > 0 && mMaxSize < aMaxTotalProgress) || + mMaxSize < aCurTotalProgress)) + { + Cancel (); + } + + if (!mRequest) + mRequest = aRequest; + + PRInt64 now = PR_Now (); + + if ((now - mLastUpdate < mInterval) && + (aMaxTotalProgress == -1 || aCurTotalProgress < aMaxTotalProgress)) + return NS_OK; + + mLastUpdate = now; + + if (aMaxTotalProgress <= 0) + { + mPercentComplete = -1; + } + else + { + /* Make sure not to round up, so we don't display 100% unless + * it's really finished! + */ + mPercentComplete = (PRInt32)(((float)aCurTotalProgress / (float)aMaxTotalProgress) * 100.0); + } + + mTotalProgress = aMaxTotalProgress; + mCurrentProgress = aCurTotalProgress; + + if (mEphyDownload) + { + g_signal_emit_by_name (mEphyDownload, "changed"); + } + + return NS_OK; +} + +#ifdef HAVE_GECKO_1_9 +/* boolean onRefreshAttempted (in nsIWebProgress aWebProgress, in nsIURI aRefreshURI, in long aDelay, in boolean aSameURI); */ +NS_IMETHODIMP +MozDownload::OnRefreshAttempted(nsIWebProgress *aWebProgress, + nsIURI *aUri, + PRInt32 aDelay, + PRBool aSameUri, + PRBool *allowRefresh) +{ + *allowRefresh = PR_TRUE; + return NS_OK; +} +#endif + +NS_IMETHODIMP +MozDownload::OnLocationChange (nsIWebProgress *aWebProgress, nsIRequest *aRequest, nsIURI *location) +{ + return NS_OK; +} + +NS_IMETHODIMP +MozDownload::OnStatusChange (nsIWebProgress *aWebProgress, nsIRequest *aRequest, + nsresult aStatus, const PRUnichar *aMessage) +{ + return NS_OK; +} + +NS_IMETHODIMP +MozDownload::OnSecurityChange (nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRUint32 state) +{ + return NS_OK; +} + +/* void getInterface (in nsIIDRef uuid, [iid_is (uuid), retval] out nsQIResult result); */ +NS_IMETHODIMP +MozDownload::GetInterface(const nsIID & uuid, void * *result) +{ + if (uuid.Equals (NS_GET_IID (nsIBadCertListener)) && + mEmbedPersist) + { + EphyEmbedPersistFlags flags; + + g_object_get (mEmbedPersist, "flags", &flags, (char *) NULL); + + if (flags & EPHY_EMBED_PERSIST_NO_CERTDIALOGS) + { + nsIBadCertListener *badCertRejector = new EphyBadCertRejector (); + if (!badCertRejector) return NS_ERROR_OUT_OF_MEMORY; + + *result = badCertRejector; + NS_ADDREF (badCertRejector); + + return NS_OK; + } + } + + return NS_ERROR_NO_INTERFACE; +} + +void +MozDownload::Cancel() +{ + if (mDownloadState != EPHY_DOWNLOAD_DOWNLOADING && + mDownloadState != EPHY_DOWNLOAD_PAUSED) + { + return; + } + + if (mCancelable) + { + /* FIXME: error code? */ + mCancelable->Cancel (NS_BINDING_ABORTED); + } +} + +void +MozDownload::Pause() +{ + if (mRequest) + { + mRequest->Suspend (); + mDownloadState = EPHY_DOWNLOAD_PAUSED; + } +} + +void +MozDownload::Resume() +{ + if (mRequest) + { + mRequest->Resume (); + mDownloadState = EPHY_DOWNLOAD_DOWNLOADING; + } +} + +nsresult InitiateMozillaDownload (nsIDOMDocument *domDocument, nsIURI *sourceURI, + nsILocalFile* inDestFile, const char *contentType, + nsIURI* inOriginalURI, MozillaEmbedPersist *embedPersist, + nsIInputStream *postData, nsISupports *aCacheKey, + PRInt64 aMaxSize) +{ + nsresult rv = NS_OK; + + EphyEmbedPersistFlags ephy_flags; + ephy_flags = ephy_embed_persist_get_flags (EPHY_EMBED_PERSIST (embedPersist)); + + if (!ephy_embed_persist_get_dest (EPHY_EMBED_PERSIST (embedPersist))) + { + nsCString cPath; + inDestFile->GetNativePath (cPath); + + ephy_embed_persist_set_dest (EPHY_EMBED_PERSIST (embedPersist), + cPath.get()); + } + + PRBool isHTML = (contentType && + (strcmp (contentType, "text/html") == 0 || + strcmp (contentType, "text/xml") == 0 || + strcmp (contentType, "application/xhtml+xml") == 0)); + + nsCOMPtr<nsIWebBrowserPersist> webPersist (do_CreateInstance(persistContractID, &rv)); + NS_ENSURE_SUCCESS (rv, rv); + + PRInt64 timeNow = PR_Now(); + + nsString fileDisplayName; + inDestFile->GetLeafName(fileDisplayName); + + nsCOMPtr<nsIIOService> ioService; + rv = EphyUtils::GetIOService (getter_AddRefs (ioService)); + NS_ENSURE_SUCCESS (rv, rv); + + nsCOMPtr<nsIURI> destURI; + ioService->NewFileURI (inDestFile, getter_AddRefs(destURI)); + + MozDownload *downloader = new MozDownload (); + /* dlListener attaches to its progress dialog here, which gains ownership */ + /* FIXME is that still true? */ + rv = downloader->InitForEmbed (inOriginalURI, destURI, fileDisplayName, + nsnull, timeNow, nsnull, webPersist, embedPersist, aMaxSize); + NS_ENSURE_SUCCESS (rv, rv); + + rv = webPersist->SetProgressListener (downloader); + NS_ENSURE_SUCCESS (rv, rv); + + PRInt32 flags = nsIWebBrowserPersist::PERSIST_FLAGS_REPLACE_EXISTING_FILES; + + if (!domDocument && !isHTML && !(ephy_flags & EPHY_EMBED_PERSIST_COPY_PAGE) && + !(ephy_flags & EPHY_EMBED_PERSIST_DO_CONVERSION)) + { + flags |= nsIWebBrowserPersist::PERSIST_FLAGS_NO_CONVERSION; + } + if (ephy_flags & EPHY_EMBED_PERSIST_COPY_PAGE) + { + flags |= nsIWebBrowserPersist::PERSIST_FLAGS_FROM_CACHE; + } + webPersist->SetPersistFlags(flags); + + /* Create a new tagged channel if we need to block cookies from server */ + if (ephy_flags & EPHY_EMBED_PERSIST_NO_COOKIES) + { + nsCOMPtr<nsIChannel> tmpChannel; + rv = ioService->NewChannelFromURI (sourceURI, getter_AddRefs (tmpChannel)); + NS_ENSURE_SUCCESS (rv, rv); + + nsCOMPtr<nsIWritablePropertyBag2> props = do_QueryInterface(tmpChannel); + rv = props->SetPropertyAsBool (NS_LITERAL_STRING("epiphany-blocking-cookies"), PR_TRUE); + NS_ENSURE_SUCCESS (rv, rv); + + rv = webPersist->SaveChannel (tmpChannel, inDestFile); + } + else if (!domDocument || !isHTML || ephy_flags & EPHY_EMBED_PERSIST_COPY_PAGE) + { + rv = webPersist->SaveURI (sourceURI, aCacheKey, nsnull, + postData, nsnull, inDestFile); + } + else + { + PRInt32 encodingFlags = 0; + nsCOMPtr<nsILocalFile> filesFolder; + + /** + * Construct a directory path to hold the associated files; mozilla + * will create the directory as needed. + */ + + nsCString cPath; + inDestFile->GetNativePath (cPath); + + char *basename = g_path_get_basename (cPath.get()); + char *dirname = g_path_get_dirname (cPath.get()); + char *dot_pos = strchr (basename, '.'); + if (dot_pos) + { + *dot_pos = 0; + } + /* translators: this is the directory name to store auxilary files when saving html files */ + char *new_basename = g_strdup_printf (_("%s Files"), basename); + char *new_path = g_build_filename (dirname, new_basename, NULL); + g_free (new_basename); + g_free (basename); + g_free (dirname); + + filesFolder = do_CreateInstance ("@mozilla.org/file/local;1"); + filesFolder->InitWithNativePath (nsCString(new_path)); + + g_free (new_path); + + rv = webPersist->SaveDocument (domDocument, inDestFile, filesFolder, + contentType, encodingFlags, 80); + } + + return rv; +} + +static char* +GetFilePath (const char *filename) +{ + const char *home_dir; + char *download_dir, *path; + + download_dir = ephy_file_get_downloads_dir (); + + if (ephy_ensure_dir_exists (download_dir, NULL)) + { + path = g_build_filename (download_dir, filename, (char *) NULL); + } + else + { + home_dir = g_get_home_dir (); + path = g_build_filename (home_dir ? home_dir : "/", filename, (char *) NULL); + } + g_free (download_dir); + + return path; +} + +static const char* +file_is_compressed (const char *filename) +{ + int i; + static const char * const compression[] = {".gz", ".bz2", ".Z", ".lz", NULL}; + + for (i = 0; compression[i] != NULL; i++) + { + if (g_str_has_suffix (filename, compression[i])) + return compression[i]; + } + + return NULL; +} + +static const char* +parse_extension (const char *filename) +{ + const char *compression; + + compression = file_is_compressed (filename); + + /* If the file is compressed we might have a double extension */ + if (compression != NULL) + { + int i; + static const char * const extensions[] = {"tar", "ps", "xcf", "dvi", "txt", "text", NULL}; + + for (i = 0; extensions[i] != NULL; i++) + { + char *suffix; + suffix = g_strdup_printf (".%s%s", extensions[i], + compression); + + if (g_str_has_suffix (filename, suffix)) + { + char *p; + + p = g_strrstr (filename, suffix); + g_free (suffix); + + return p; + } + + g_free (suffix); + } + } + + /* default case */ + return g_strrstr (filename, "."); +} + +nsresult BuildDownloadPath (const char *defaultFileName, nsILocalFile **_retval) +{ + char *path; + + path = GetFilePath (defaultFileName); + + if (g_file_test (path, G_FILE_TEST_EXISTS)) + { + int i = 1; + const char *dot_pos; + char *serial = NULL; + GString *tmp_path; + gssize position; + + dot_pos = parse_extension (defaultFileName); + if (dot_pos) + { + position = dot_pos - defaultFileName; + } + else + { + position = strlen (defaultFileName); + } + tmp_path = g_string_new (NULL); + + do { + g_free (path); + g_string_assign (tmp_path, defaultFileName); + serial = g_strdup_printf ("(%d)", i++); + g_string_insert (tmp_path, position, serial); + g_free (serial); + path = GetFilePath (tmp_path->str); + + } while (g_file_test (path, G_FILE_TEST_EXISTS)); + + g_string_free (tmp_path, TRUE); + } + + nsCOMPtr <nsILocalFile> destFile (do_CreateInstance(NS_LOCAL_FILE_CONTRACTID)); + NS_ENSURE_TRUE (destFile, NS_ERROR_FAILURE); + + destFile->InitWithNativePath (nsCString (path)); + g_free (path); + + NS_IF_ADDREF (*_retval = destFile); + return NS_OK; +} diff --git a/embed/xulrunner/embed/MozDownload.h b/embed/xulrunner/embed/MozDownload.h new file mode 100644 index 000000000..bf7f11e1b --- /dev/null +++ b/embed/xulrunner/embed/MozDownload.h @@ -0,0 +1,152 @@ +/* -*- 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright © 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Conrad Carlen <ccarlen@netscape.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** + * + * $Id$ + */ + +#ifndef MozDownload_h__ +#define MozDownload_h__ + +#include <libgnomevfs/gnome-vfs-mime-handlers.h> + +#include <nsCOMPtr.h> +#include <nsIInterfaceRequestor.h> +#include <nsITransfer.h> +#include <nsIWebProgressListener.h> + +#include "mozilla-embed-persist.h" +#include "downloader-view.h" +#include "ephy-download.h" +#include "ephy-embed-shell.h" + +class nsICancelable; +class nsIDOMDocument; +class nsIInputStream; +class nsILocalFile; +class nsIMIMEInfo; +class nsIObserver; +class nsIRequest; +class nsIURI; +class nsIWebBrowserPersist; + +/* MozDownload + Holds information used to display a single download in the UI. This object is + created in one of two ways: + (1) By nsExternalHelperAppHandler when Gecko encounters a MIME type which + it doesn't itself handle. In this case, the notifications sent to + nsIDownload are controlled by nsExternalHelperAppHandler. + (2) By the embedding app's file saving code when saving a web page or a link + target. See CHeaderSniffer.cpp. In this case, the notifications sent to + nsIDownload are controlled by the implementation of nsIWebBrowserPersist. +*/ + +#define MOZ_DOWNLOAD_CID \ +{ /* d2a2f743-f126-4f1f-1234-d4e50490f112 */ \ + 0xd2a2f743, \ + 0xf126, \ + 0x4f1f, \ + {0x12, 0x34, 0xd4, 0xe5, 0x04, 0x90, 0xf1, 0x12} \ +} + +#define MOZ_DOWNLOAD_CLASSNAME "Ephy's Download Progress Dialog" + +nsresult InitiateMozillaDownload (nsIDOMDocument *domDocument, nsIURI *sourceUri, + nsILocalFile* inDestFile, const char *contentType, + nsIURI* inOriginalURI, MozillaEmbedPersist *embedPersist, + nsIInputStream *postData, nsISupports *aCacheKey, + PRInt64 aMaxSize); +nsresult BuildDownloadPath (const char *defaultFileName, nsILocalFile **_retval); + +class MozDownload : public nsITransfer, + public nsIInterfaceRequestor +{ +public: + MozDownload(); + virtual ~MozDownload(); + + NS_DECL_ISUPPORTS + NS_DECL_NSIWEBPROGRESSLISTENER + NS_DECL_NSIWEBPROGRESSLISTENER2 + NS_DECL_NSITRANSFER + NS_DECL_NSIINTERFACEREQUESTOR + + nsresult GetMIMEInfo (nsIMIMEInfo **aMIMEInfo); + nsresult GetTargetFile (nsILocalFile **aFile); + nsresult GetSource(nsIURI * *aSource); + nsresult GetPercentComplete(PRInt32 *aPercentComplete); + + virtual void Cancel(); + virtual void Pause(); + virtual void Resume(); + + nsresult GetState (EphyDownloadState *aDownloadState); + nsresult GetCurrentProgress (PRInt64 *aCurrentProgress); + nsresult GetTotalProgress (PRInt64 *aTProgress); + nsresult GetElapsedTime (PRInt64 *aTProgress); + + nsresult InitForEmbed (nsIURI *aSource, nsIURI *aTarget, + const nsAString &aDisplayName, nsIMIMEInfo *aMIMEInfo, + PRTime aStartTime, nsILocalFile *aTempFile, + nsICancelable *aCancelable, MozillaEmbedPersist *aEmbedPersist, + PRInt64 aMaxSize); + +protected: + nsCOMPtr<nsIURI> mSource; + nsCOMPtr<nsIURI> mDestination; + + nsCOMPtr<nsIMIMEInfo> mMIMEInfo; + PRTime mStartTime; + PRTime mLastUpdate; + PRInt64 mElapsed; + PRInt32 mInterval; + PRInt32 mPercentComplete; + PRInt64 mTotalProgress; + PRInt64 mCurrentProgress; + PRInt64 mMaxSize; + + nsresult mStatus; + + nsCOMPtr<nsICancelable> mCancelable; + nsCOMPtr<nsIRequest> mRequest; + EphyDownload *mEphyDownload; + DownloaderView *mDownloaderView; + MozillaEmbedPersist *mEmbedPersist; + EphyDownloadState mDownloadState; +}; + +#endif // MozDownload_h__ diff --git a/embed/xulrunner/embed/MozRegisterComponents.cpp b/embed/xulrunner/embed/MozRegisterComponents.cpp new file mode 100644 index 000000000..e712bbc5d --- /dev/null +++ b/embed/xulrunner/embed/MozRegisterComponents.cpp @@ -0,0 +1,333 @@ +/* + * Copyright © 2001,2002,2003 Philip Langdale + * Copyright © 2003 Marco Pesenti Gritti + * Copyright © 2004, 2005, 2006 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#include "mozilla-config.h" +#include "config.h" + +#include <glib/gmessages.h> + +#include <nsStringAPI.h> + +#include <nsComponentManagerUtils.h> +#include <nsCOMPtr.h> +#include <nsCURILoader.h> +#include <nsDocShellCID.h> +#include <nsICategoryManager.h> +#include <nsIComponentManager.h> +#include <nsIComponentRegistrar.h> +#include <nsIGenericFactory.h> +#include <nsILocalFile.h> +#include <nsIScriptNameSpaceManager.h> +#include <nsIServiceManager.h> +#include <nsMemory.h> +#include <nsNetCID.h> +#include <nsServiceManagerUtils.h> + +#ifdef HAVE_GECKO_1_9 +#include <nsIClassInfoImpl.h> +#endif + +#ifdef HAVE_MOZILLA_PSM +#include <nsISecureBrowserUI.h> +#endif + +#include "ContentHandler.h" +#include "EphyAboutModule.h" +#include "EphyContentPolicy.h" +#include "EphyPromptService.h" +#include "EphySidebar.h" +#include "GeckoCookiePromptService.h" +#include "GeckoPrintService.h" +#include "GeckoPrintSession.h" +#include "GlobalHistory.h" +#include "MozDownload.h" + +#ifdef ENABLE_FILEPICKER +#include "FilePicker.h" +#endif + +#ifdef ENABLE_SPELLCHECKER +#include "GeckoSpellCheckEngine.h" +#endif + +#ifdef HAVE_MOZILLA_PSM +#include "GtkNSSClientAuthDialogs.h" +#include "GtkNSSDialogs.h" +#include "GtkNSSKeyPairDialogs.h" +#include "GtkNSSSecurityWarningDialogs.h" +#include "GeckoFormSigningDialog.h" +#endif + +NS_GENERIC_FACTORY_CONSTRUCTOR(EphyAboutModule) +NS_GENERIC_FACTORY_CONSTRUCTOR(EphyContentPolicy) +NS_GENERIC_FACTORY_CONSTRUCTOR(EphyPromptService) +NS_GENERIC_FACTORY_CONSTRUCTOR(EphySidebar) +NS_GENERIC_FACTORY_CONSTRUCTOR(GContentHandler) +NS_GENERIC_FACTORY_CONSTRUCTOR(GeckoCookiePromptService) +NS_GENERIC_FACTORY_CONSTRUCTOR(GeckoPrintService) +NS_GENERIC_FACTORY_CONSTRUCTOR(GeckoPrintSession) +NS_GENERIC_FACTORY_CONSTRUCTOR(MozDownload) +NS_GENERIC_FACTORY_CONSTRUCTOR(MozGlobalHistory) + +#ifdef ENABLE_FILEPICKER +NS_GENERIC_FACTORY_CONSTRUCTOR(GFilePicker) +#endif + +#ifdef ENABLE_SPELLCHECKER +NS_GENERIC_FACTORY_CONSTRUCTOR(GeckoSpellCheckEngine) +#endif + +#ifdef HAVE_MOZILLA_PSM +NS_GENERIC_FACTORY_CONSTRUCTOR(GtkNSSClientAuthDialogs) +NS_GENERIC_FACTORY_CONSTRUCTOR(GtkNSSDialogs) +NS_GENERIC_FACTORY_CONSTRUCTOR(GtkNSSKeyPairDialogs) +NS_GENERIC_FACTORY_CONSTRUCTOR(GtkNSSSecurityWarningDialogs) +NS_GENERIC_FACTORY_CONSTRUCTOR(GeckoFormSigningDialog) +#endif + +#define XPINSTALL_CONTRACTID NS_CONTENT_HANDLER_CONTRACTID_PREFIX "application/x-xpinstall" + +/* class information */ +NS_DECL_CLASSINFO(EphySidebar) + +/* FIXME: uninstall XPI handler */ + +static const nsModuleComponentInfo sAppComps[] = { + { + MOZ_DOWNLOAD_CLASSNAME, + MOZ_DOWNLOAD_CID, +#ifdef NS_TRANSFER_CONTRACTID + NS_TRANSFER_CONTRACTID, +#else + NS_DOWNLOAD_CONTRACTID, +#endif + MozDownloadConstructor + }, +#ifdef ENABLE_FILEPICKER + { + G_FILEPICKER_CLASSNAME, + G_FILEPICKER_CID, + G_FILEPICKER_CONTRACTID, + GFilePickerConstructor + }, +#endif +#ifdef HAVE_MOZILLA_PSM + { + GTK_NSSCLIENTAUTHDIALOGS_CLASSNAME, + GTK_NSSCLIENTAUTHDIALOGS_CID, + NS_CLIENTAUTHDIALOGS_CONTRACTID, + GtkNSSClientAuthDialogsConstructor + }, + { + GTK_NSSDIALOGS_CLASSNAME, + GTK_NSSDIALOGS_CID, + NS_BADCERTLISTENER_CONTRACTID, + GtkNSSDialogsConstructor + }, + { + GTK_NSSDIALOGS_CLASSNAME, + GTK_NSSDIALOGS_CID, + NS_CERTIFICATEDIALOGS_CONTRACTID, + GtkNSSDialogsConstructor + }, + { + GTK_NSSDIALOGS_CLASSNAME, + GTK_NSSDIALOGS_CID, + NS_DOMCRYPTODIALOGS_CONTRACTID, + GtkNSSDialogsConstructor + }, + { + GTK_NSSDIALOGS_CLASSNAME, + GTK_NSSDIALOGS_CID, + NS_TOKENDIALOGS_CONTRACTID, + GtkNSSDialogsConstructor + }, + { + GTK_NSSDIALOGS_CLASSNAME, + GTK_NSSDIALOGS_CID, + NS_TOKENPASSWORDSDIALOG_CONTRACTID, + GtkNSSDialogsConstructor + }, + { + GTK_NSSKEYPAIRDIALOGS_CLASSNAME, + GTK_NSSKEYPAIRDIALOGS_CID, + NS_GENERATINGKEYPAIRINFODIALOGS_CONTRACTID, + GtkNSSKeyPairDialogsConstructor + }, + { + GTK_NSSSECURITYWARNINGDIALOGS_CLASSNAME, + GTK_NSSSECURITYWARNINGDIALOGS_CID, + NS_SECURITYWARNINGDIALOGS_CONTRACTID, + GtkNSSSecurityWarningDialogsConstructor + }, + { + GECKO_FORMSIGNINGDIALOGS_CLASSNAME, + GECKO_FORMSIGNINGDIALOGS_CID, + NS_FORMSIGNINGDIALOG_CONTRACTID, + GeckoFormSigningDialogConstructor + }, +#endif /* HAVE_MOZILLA_PSM */ + { + NS_IHELPERAPPLAUNCHERDLG_CLASSNAME, + G_CONTENTHANDLER_CID, + NS_IHELPERAPPLAUNCHERDLG_CONTRACTID, + GContentHandlerConstructor + }, + { + EPHY_GLOBALHISTORY_CLASSNAME, + EPHY_GLOBALHISTORY_CID, + NS_GLOBALHISTORY2_CONTRACTID, + MozGlobalHistoryConstructor + }, + { + GECKO_PRINT_SERVICE_CLASSNAME, + GECKO_PRINT_SERVICE_IID, + "@mozilla.org/embedcomp/printingprompt-service;1", + GeckoPrintServiceConstructor + }, + { + GECKO_PRINT_SESSION_CLASSNAME, + GECKO_PRINT_SESSION_IID, + "@mozilla.org/gfx/printsession;1", + GeckoPrintSessionConstructor + }, + { + EPHY_CONTENT_POLICY_CLASSNAME, + EPHY_CONTENT_POLICY_CID, + EPHY_CONTENT_POLICY_CONTRACTID, + EphyContentPolicyConstructor, + EphyContentPolicy::Register, + EphyContentPolicy::Unregister + }, + { + EPHY_SIDEBAR_CLASSNAME, + EPHY_SIDEBAR_CID, + NS_SIDEBAR_CONTRACTID, + EphySidebarConstructor, + EphySidebar::Register, + EphySidebar::Unregister, + nsnull /* no factory destructor */, + NS_CI_INTERFACE_GETTER_NAME(EphySidebar), + nsnull /* no language helper */, + &NS_CLASSINFO_NAME(EphySidebar), + nsIClassInfo::DOM_OBJECT + }, + { + EPHY_ABOUT_EPIPHANY_CLASSNAME, + EPHY_ABOUT_MODULE_CID, + EPHY_ABOUT_EPIPHANY_CONTRACTID, + EphyAboutModuleConstructor + }, + { + EPHY_ABOUT_RECOVER_CLASSNAME, + EPHY_ABOUT_MODULE_CID, + EPHY_ABOUT_RECOVER_CONTRACTID, + EphyAboutModuleConstructor + }, + { + EPHY_ABOUT_NETERROR_CLASSNAME, + EPHY_ABOUT_MODULE_CID, + EPHY_ABOUT_NETERROR_CONTRACTID, + EphyAboutModuleConstructor + }, + { + EPHY_PROMPT_SERVICE_CLASSNAME, + EPHY_PROMPT_SERVICE_IID, + "@mozilla.org/embedcomp/prompt-service;1", + EphyPromptServiceConstructor + }, +#ifdef HAVE_NSINONBLOCKINGALERTSERVICE_H + { + EPHY_PROMPT_SERVICE_CLASSNAME, + EPHY_PROMPT_SERVICE_IID, + "@mozilla.org/embedcomp/nbalert-service;1", + EphyPromptServiceConstructor + }, +#endif /* HAVE_NSINONBLOCKINGALERTSERVICE_H */ +#ifdef ENABLE_SPELLCHECKER + { + GECKO_SPELL_CHECK_ENGINE_CLASSNAME, + GECKO_SPELL_CHECK_ENGINE_IID, + GECKO_SPELL_CHECK_ENGINE_CONTRACTID, + GeckoSpellCheckEngineConstructor + }, +#endif /* ENABLE_SPELLCHECK */ + { + EPHY_COOKIEPROMPTSERVICE_CLASSNAME, + EPHY_COOKIEPROMPTSERVICE_CID, + EPHY_COOKIEPROMPTSERVICE_CONTRACTID, + GeckoCookiePromptServiceConstructor + } +}; + +gboolean +mozilla_register_components (void) +{ + gboolean ret = TRUE; + nsresult rv; + + nsCOMPtr<nsIComponentRegistrar> cr; + NS_GetComponentRegistrar(getter_AddRefs(cr)); + NS_ENSURE_TRUE (cr, FALSE); + + nsCOMPtr<nsIComponentManager> cm; + NS_GetComponentManager (getter_AddRefs (cm)); + NS_ENSURE_TRUE (cm, FALSE); + + for (guint i = 0; i < G_N_ELEMENTS (sAppComps); i++) + { + nsCOMPtr<nsIGenericFactory> componentFactory; + rv = NS_NewGenericFactory(getter_AddRefs(componentFactory), + &(sAppComps[i])); + if (NS_FAILED(rv) || !componentFactory) + { + g_warning ("Failed to make a factory for %s\n", sAppComps[i].mDescription); + + ret = FALSE; + continue; // don't abort registering other components + } + + rv = cr->RegisterFactory(sAppComps[i].mCID, + sAppComps[i].mDescription, + sAppComps[i].mContractID, + componentFactory); + if (NS_FAILED(rv)) + { + g_warning ("Failed to register %s\n", sAppComps[i].mDescription); + + ret = FALSE; + } + + if (sAppComps[i].mRegisterSelfProc) + { + rv = sAppComps[i].mRegisterSelfProc (cm, nsnull, nsnull, nsnull, &sAppComps[i]); + + if (NS_FAILED (rv)) + { + g_warning ("Failed to register-self for %s\n", sAppComps[i].mDescription); + ret = FALSE; + } + } + } + + return ret; +} diff --git a/embed/xulrunner/embed/MozRegisterComponents.h b/embed/xulrunner/embed/MozRegisterComponents.h new file mode 100644 index 000000000..e8e086f3b --- /dev/null +++ b/embed/xulrunner/embed/MozRegisterComponents.h @@ -0,0 +1,28 @@ +/* + * Copyright © 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#ifndef MOZREGISTERCOMPONENTS_H +#define MOZREGISTERCOMPONENTS_H + +#include <glib.h> + +gboolean mozilla_register_components (void); + +#endif /* MOZREGISTERCOMPONENTS_H */ diff --git a/embed/xulrunner/embed/mozilla-download.cpp b/embed/xulrunner/embed/mozilla-download.cpp new file mode 100644 index 000000000..0b420547c --- /dev/null +++ b/embed/xulrunner/embed/mozilla-download.cpp @@ -0,0 +1,313 @@ +/* + * Copyright © 2003 Xan Lopez + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#include "mozilla-config.h" +#include "config.h" + +#include <nsStringAPI.h> + +#include <nsILocalFile.h> +#include <nsIMIMEInfo.h> +#include <nsIURI.h> +#include <nsMemory.h> + +#include "ephy-debug.h" + +#include "MozDownload.h" + +#include "mozilla-download.h" + +static void mozilla_download_class_init (MozillaDownloadClass *klass); +static void mozilla_download_init (MozillaDownload *ges); +static void mozilla_download_finalize (GObject *object); + +enum +{ + PROP_0, + PROP_MOZDOWNLOAD +}; + +struct _MozillaDownloadPrivate +{ + MozDownload *moz_download; +}; + +#define MOZILLA_DOWNLOAD_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), MOZILLA_TYPE_DOWNLOAD, MozillaDownloadPrivate)) + +static GObjectClass *parent_class = NULL; + +GType +mozilla_download_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) + { + const GTypeInfo our_info = + { + sizeof (MozillaDownloadClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) mozilla_download_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (MozillaDownload), + 0, /* n_preallocs */ + (GInstanceInitFunc) mozilla_download_init + }; + + type = g_type_register_static (EPHY_TYPE_DOWNLOAD, + "MozillaDownload", + &our_info, (GTypeFlags)0); + } + + return type; +} + +static char * +impl_get_target (EphyDownload *download) +{ + nsCOMPtr<nsILocalFile> targetFile; + MozDownload *mozDownload; + + mozDownload = MOZILLA_DOWNLOAD (download)->priv->moz_download; + + mozDownload->GetTargetFile (getter_AddRefs (targetFile)); + + nsCString tempPathStr; + targetFile->GetNativePath (tempPathStr); + + return g_strdup (tempPathStr.get ()); +} + +static char * +impl_get_source (EphyDownload *download) +{ + nsCOMPtr<nsIURI> uri; + MozDownload *mozDownload; + nsCString spec; + + mozDownload = MOZILLA_DOWNLOAD (download)->priv->moz_download; + + mozDownload->GetSource (getter_AddRefs (uri)); + uri->GetSpec (spec); + + return g_strdup (spec.get()); +} + +static gint64 +impl_get_current_progress (EphyDownload *download) +{ + MozDownload *mozDownload; + PRInt64 progress; + + mozDownload = MOZILLA_DOWNLOAD (download)->priv->moz_download; + + mozDownload->GetCurrentProgress (&progress); + + return progress; +} + +static EphyDownloadState +impl_get_state (EphyDownload *download) +{ + MozDownload *mozDownload; + EphyDownloadState state; + + mozDownload = MOZILLA_DOWNLOAD (download)->priv->moz_download; + + mozDownload->GetState (&state); + + return state; +} + +static gint64 +impl_get_total_progress (EphyDownload *download) +{ + MozDownload *mozDownload; + PRInt64 progress; + + mozDownload = MOZILLA_DOWNLOAD (download)->priv->moz_download; + + mozDownload->GetTotalProgress (&progress); + + return progress; +} + +static int +impl_get_percent (EphyDownload *download) +{ + MozDownload *mozDownload; + PRInt32 percent; + + mozDownload = MOZILLA_DOWNLOAD (download)->priv->moz_download; + + mozDownload->GetPercentComplete (&percent); + + return percent; +} + +static gint64 +impl_get_elapsed_time (EphyDownload *download) +{ + MozDownload *mozDownload; + PRInt64 elapsed; + + mozDownload = MOZILLA_DOWNLOAD (download)->priv->moz_download; + + mozDownload->GetElapsedTime (&elapsed); + + return elapsed / 1000000; +} + +static char* +impl_get_mime (EphyDownload *download) +{ + MozDownload *mozDownload; + nsCOMPtr<nsIMIMEInfo> mime; + nsCString mimeType; + + mozDownload = MOZILLA_DOWNLOAD (download)->priv->moz_download; + + mozDownload->GetMIMEInfo (getter_AddRefs(mime)); + if (!mime) return g_strdup ("application/octet-stream"); + + mime->GetMIMEType(mimeType); + + return g_strdup (mimeType.get()); +} + +static void +impl_cancel (EphyDownload *download) +{ + MOZILLA_DOWNLOAD (download)->priv->moz_download->Cancel (); +} + +static void +impl_pause (EphyDownload *download) +{ + MOZILLA_DOWNLOAD (download)->priv->moz_download->Pause (); +} + +static void +impl_resume (EphyDownload *download) +{ + MOZILLA_DOWNLOAD (download)->priv->moz_download->Resume (); +} + +static void +mozilla_download_finalize (GObject *object) +{ + MozillaDownload *download = MOZILLA_DOWNLOAD (object); + + NS_RELEASE (download->priv->moz_download); + + LOG ("MozillaDownload %p finalised", object); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +mozilla_download_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + MozillaDownload *download = MOZILLA_DOWNLOAD (object); + + switch (prop_id) + { + case PROP_MOZDOWNLOAD: + MozDownload *moz_download; + + moz_download = (MozDownload *)g_value_get_pointer (value); + NS_ADDREF (moz_download); + download->priv->moz_download = moz_download; + break; + } +} + +static void +mozilla_download_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + MozillaDownload *download = MOZILLA_DOWNLOAD (object); + + switch (prop_id) + { + case PROP_MOZDOWNLOAD: + g_value_set_pointer (value, download->priv->moz_download); + break; + } +} + +static void +mozilla_download_class_init (MozillaDownloadClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + EphyDownloadClass *download_class = EPHY_DOWNLOAD_CLASS (klass); + + parent_class = (GObjectClass *) g_type_class_peek_parent (klass); + + object_class->finalize = mozilla_download_finalize; + object_class->set_property = mozilla_download_set_property; + object_class->get_property = mozilla_download_get_property; + + download_class->get_elapsed_time = impl_get_elapsed_time; + download_class->get_current_progress = impl_get_current_progress; + download_class->get_total_progress = impl_get_total_progress; + download_class->get_percent = impl_get_percent; + download_class->get_target = impl_get_target; + download_class->get_source = impl_get_source; + download_class->get_state = impl_get_state; + download_class->get_mime = impl_get_mime; + download_class->cancel = impl_cancel; + download_class->pause = impl_pause; + download_class->resume = impl_resume; + + g_type_class_add_private (klass, sizeof (MozillaDownloadPrivate)); + + g_object_class_install_property (object_class, + PROP_MOZDOWNLOAD, + g_param_spec_pointer ("mozilla-download", + "Mozilla Download", + "Mozilla Download", + (GParamFlags) + (G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | + G_PARAM_CONSTRUCT_ONLY))); +} + +static void +mozilla_download_init (MozillaDownload *download) +{ + LOG ("MozillaDownload %p initialising", download); + + download->priv = MOZILLA_DOWNLOAD_GET_PRIVATE (download); +} + +EphyDownload * +mozilla_download_new (MozDownload *download) +{ + return EPHY_DOWNLOAD (g_object_new (MOZILLA_TYPE_DOWNLOAD, + "mozilla-download", download, + NULL)); +} diff --git a/embed/xulrunner/embed/mozilla-download.h b/embed/xulrunner/embed/mozilla-download.h new file mode 100644 index 000000000..071ec31af --- /dev/null +++ b/embed/xulrunner/embed/mozilla-download.h @@ -0,0 +1,61 @@ +/* + * Copyright © 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#ifndef MOZILLA_DOWNLOAD_H +#define MOZILLA_DOWNLOAD_H + +#include <glib.h> +#include <glib-object.h> + +#include "ephy-download.h" + +G_BEGIN_DECLS + +#define MOZILLA_TYPE_DOWNLOAD (mozilla_download_get_type ()) +#define MOZILLA_DOWNLOAD(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), MOZILLA_TYPE_DOWNLOAD, MozillaDownload)) +#define MOZILLA_DOWNLOAD_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), MOZILLA_TYPE_DOWNLOAD, MozillaDownloadClass)) +#define MOZILLA_IS_DOWNLOAD(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), MOZILLA_TYPE_DOWNLOAD)) +#define MOZILLA_IS_DOWNLOAD_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), MOZILLA_TYPE_DOWNLOAD)) +#define MOZILLA_DOWNLOAD_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), MOZILLA_TYPE_DOWNLOAD, MozillaDownloadClass)) + +typedef struct _MozillaDownloadClass MozillaDownloadClass; +typedef struct _MozillaDownload MozillaDownload; +typedef struct _MozillaDownloadPrivate MozillaDownloadPrivate; + +class MozDownload; + +struct _MozillaDownload +{ + EphyDownload parent; + MozillaDownloadPrivate *priv; +}; + +struct _MozillaDownloadClass +{ + EphyDownloadClass parent_class; +}; + +GType mozilla_download_get_type (void); + +EphyDownload *mozilla_download_new (MozDownload *download); + +G_END_DECLS + +#endif diff --git a/embed/xulrunner/embed/mozilla-embed-event.cpp b/embed/xulrunner/embed/mozilla-embed-event.cpp new file mode 100644 index 000000000..9b5b06d85 --- /dev/null +++ b/embed/xulrunner/embed/mozilla-embed-event.cpp @@ -0,0 +1,221 @@ +/* + * Copyright © 2000-2003 Marco Pesenti Gritti + * Copyright © 2004 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#include "mozilla-config.h" +#include "config.h" + +#include <glib/ghash.h> + +#include <nsCOMPtr.h> +#include <nsIDOMEvent.h> + +#include "ephy-debug.h" + +#include "mozilla-embed-event.h" + +#define MOZILLA_EMBED_EVENT_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), MOZILLA_TYPE_EMBED_EVENT, MozillaEmbedEventPrivate)) + +struct _MozillaEmbedEventPrivate +{ + nsIDOMEvent* dom_event; + GHashTable *props; +}; + +static void mozilla_embed_event_class_init (MozillaEmbedEventClass *klass); +static void mozilla_embed_event_init (MozillaEmbedEvent *event); +static void ephy_embed_event_iface_init (EphyEmbedEventIface *iface); + +static GObjectClass *parent_class = NULL; + +GType +mozilla_embed_event_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) + { + const GTypeInfo our_info = + { + sizeof (MozillaEmbedEventClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) mozilla_embed_event_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (MozillaEmbedEvent), + 0, /* n_preallocs */ + (GInstanceInitFunc) mozilla_embed_event_init + }; + + const GInterfaceInfo embed_event_info = + { + (GInterfaceInitFunc) ephy_embed_event_iface_init, + NULL, + NULL + }; + + type = g_type_register_static (G_TYPE_OBJECT, + "MozillaEmbedEvent", + &our_info, (GTypeFlags) 0); + + g_type_add_interface_static (type, + EPHY_TYPE_EMBED_EVENT, + &embed_event_info); + } + + return type; +} + +MozillaEmbedEvent * +mozilla_embed_event_new (gpointer dom_event) +{ + MozillaEmbedEvent *event; + + event = MOZILLA_EMBED_EVENT (g_object_new (MOZILLA_TYPE_EMBED_EVENT, NULL)); + + event->priv->dom_event = static_cast<nsIDOMEvent*>(dom_event); + NS_IF_ADDREF (event->priv->dom_event); + + return event; +} + +void +mozilla_embed_event_set_property (MozillaEmbedEvent *event, + const char *name, + GValue *value) +{ + char *value_content = g_strdup_value_contents (value); + LOG ("embed event %p set property \"%s\" to %s", event, name, value_content); + g_free (value_content); + + g_hash_table_insert (event->priv->props, + g_strdup (name), + value); +} + +static EphyEmbedEventContext +impl_get_context (EphyEmbedEvent *event) +{ + return (EphyEmbedEventContext) ((MozillaEmbedEvent *) event)->context; +} + +static guint +impl_get_button (EphyEmbedEvent *event) +{ + return ((MozillaEmbedEvent *) event)->button; +} + +static guint +impl_get_modifier (EphyEmbedEvent *event) +{ + return ((MozillaEmbedEvent *) event)->modifier; +} + +static void +impl_get_coordinates (EphyEmbedEvent *event, + guint *x, + guint *y) +{ + *x = ((MozillaEmbedEvent *) event)->x; + *y = ((MozillaEmbedEvent *) event)->y; +} + +static const GValue* +impl_get_property (EphyEmbedEvent *event, + const char *name) +{ + return (const GValue *) g_hash_table_lookup (((MozillaEmbedEvent *) event)->priv->props, name); +} + +static gboolean +impl_has_property (EphyEmbedEvent *event, + const char *name) +{ + gpointer tmp; + + tmp = g_hash_table_lookup (((MozillaEmbedEvent *) event)->priv->props, name); + + return tmp != NULL; +} + +static gpointer +impl_get_dom_event (EphyEmbedEvent *event) +{ + return static_cast<gpointer>(((MozillaEmbedEvent *) event)->priv->dom_event); +} + +static void +free_g_value (gpointer value) +{ + g_value_unset ((GValue *) value); + g_free (value); +} + +static void +mozilla_embed_event_init (MozillaEmbedEvent *event) +{ + event->priv = MOZILLA_EMBED_EVENT_GET_PRIVATE (event); + + LOG ("MozillaEmbedEvent %p initialising", event); + + event->priv->dom_event = nsnull; + event->priv->props = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, free_g_value); +} + +static void +mozilla_embed_event_finalize (GObject *object) +{ + MozillaEmbedEvent *event = MOZILLA_EMBED_EVENT (object); + + g_hash_table_destroy (event->priv->props); + + NS_IF_RELEASE (event->priv->dom_event); + event->priv->dom_event = nsnull; + + LOG ("MozillaEmbedEvent %p finalised", object); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +ephy_embed_event_iface_init (EphyEmbedEventIface *iface) +{ + iface->get_context = impl_get_context; + iface->get_button = impl_get_button; + iface->get_modifier = impl_get_modifier; + iface->get_coordinates = impl_get_coordinates; + iface->get_property = impl_get_property; + iface->has_property = impl_has_property; + iface->get_dom_event = impl_get_dom_event; +} + +static void +mozilla_embed_event_class_init (MozillaEmbedEventClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = (GObjectClass *) g_type_class_peek_parent (klass); + + object_class->finalize = mozilla_embed_event_finalize; + + g_type_class_add_private (object_class, sizeof (MozillaEmbedEventPrivate)); +} diff --git a/embed/xulrunner/embed/mozilla-embed-event.h b/embed/xulrunner/embed/mozilla-embed-event.h new file mode 100644 index 000000000..4306bef67 --- /dev/null +++ b/embed/xulrunner/embed/mozilla-embed-event.h @@ -0,0 +1,74 @@ +/* + * Copyright © 2000-2003 Marco Pesenti Gritti + * Copyright © 2004 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#ifndef MOZILLA_EMBED_EVENT_H +#define MOZILLA_EMBED_EVENT_H + +#include <glib.h> +#include <glib-object.h> + +#include "ephy-embed-event.h" + +G_BEGIN_DECLS + +#define MOZILLA_TYPE_EMBED_EVENT (mozilla_embed_event_get_type ()) +#define MOZILLA_EMBED_EVENT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), MOZILLA_TYPE_EMBED_EVENT, MozillaEmbedEvent)) +#define MOZILLA_EMBED_EVENT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), MOZILLA_TYPE_EMBED_EVENT, MozillaEmbedEventClass)) +#define MOZILLA_IS_EMBED_EVENT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), MOZILLA_TYPE_EMBED_EVENT)) +#define MOZILLA_IS_EMBED_EVENT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), MOZILLA_TYPE_EMBED_EVENT)) +#define MOZILLA_EMBED_EVENT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), MOZILLA_TYPE_EMBED_EVENT, MozillaEmbedEventClass)) + +typedef struct _MozillaEmbedEventClass MozillaEmbedEventClass; +typedef struct _MozillaEmbedEvent MozillaEmbedEvent; +typedef struct _MozillaEmbedEventPrivate MozillaEmbedEventPrivate; + +struct _MozillaEmbedEventClass +{ + GObjectClass parent_class; +}; + +struct _MozillaEmbedEvent +{ + GObject parent; + + /*< private >*/ + MozillaEmbedEventPrivate *priv; + + /*< private >*/ /* public to the embed implementation */ + guint button; + guint context; + guint modifier; + guint x; + guint y; + guint keycode; +}; + +GType mozilla_embed_event_get_type (void); + +MozillaEmbedEvent *mozilla_embed_event_new (gpointer dom_event); + +void mozilla_embed_event_set_property (MozillaEmbedEvent *event, + const char *name, + GValue *value); + +G_END_DECLS + +#endif diff --git a/embed/xulrunner/embed/mozilla-embed-find.cpp b/embed/xulrunner/embed/mozilla-embed-find.cpp new file mode 100644 index 000000000..576d8ec11 --- /dev/null +++ b/embed/xulrunner/embed/mozilla-embed-find.cpp @@ -0,0 +1,198 @@ +/* + * Copyright © 2000-2004 Marco Pesenti Gritti + * Copyright © 2003, 2004 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#include "mozilla-config.h" +#include "config.h" + +#include "ephy-debug.h" +#include "ephy-embed-find.h" +#include "ephy-embed-shell.h" + +#include "EphyFind.h" + +#include "mozilla-embed-find.h" + +#define MOZILLA_EMBED_FIND_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), MOZILLA_TYPE_EMBED_FIND, MozillaEmbedFindPrivate)) + +struct _MozillaEmbedFindPrivate +{ + EphyFind *find; +}; + +static GObjectClass *parent_class = NULL; + +static void +impl_set_embed (EphyEmbedFind *efind, + EphyEmbed *embed) +{ + MozillaEmbedFind *find = MOZILLA_EMBED_FIND (efind); + MozillaEmbedFindPrivate *priv = find->priv; + + priv->find->SetEmbed (embed); +} + +static void +impl_set_properties (EphyEmbedFind *efind, + const char *find_string, + gboolean case_sensitive) +{ + MozillaEmbedFind *find = MOZILLA_EMBED_FIND (efind); + MozillaEmbedFindPrivate *priv = find->priv; + + priv->find->SetFindProperties (find_string, case_sensitive); +} + +static EphyEmbedFindResult +impl_find (EphyEmbedFind *efind, + const char *find_string, + gboolean links_only) +{ + MozillaEmbedFind *find = MOZILLA_EMBED_FIND (efind); + MozillaEmbedFindPrivate *priv = find->priv; + + return priv->find->Find (find_string, links_only); +} + +static EphyEmbedFindResult +impl_find_again (EphyEmbedFind *efind, + gboolean forward, + gboolean links_only) +{ + MozillaEmbedFind *find = MOZILLA_EMBED_FIND (efind); + MozillaEmbedFindPrivate *priv = find->priv; + + return priv->find->FindAgain (forward, links_only); +} + +static void +impl_set_selection (EphyEmbedFind *efind, + gboolean attention) +{ + MozillaEmbedFind *find = MOZILLA_EMBED_FIND (efind); + MozillaEmbedFindPrivate *priv = find->priv; + + priv->find->SetSelectionAttention (attention); +} + +static gboolean +impl_activate_link (EphyEmbedFind *efind, + GdkModifierType mask) +{ + MozillaEmbedFind *find = MOZILLA_EMBED_FIND (efind); + MozillaEmbedFindPrivate *priv = find->priv; + + return priv->find->ActivateLink (mask); +} + +static void +ephy_find_iface_init (EphyEmbedFindIface *iface) +{ + iface->set_embed = impl_set_embed; + iface->set_properties = impl_set_properties; + iface->find = impl_find; + iface->find_again = impl_find_again; + iface->set_selection = impl_set_selection; + iface->activate_link = impl_activate_link; +} + +static void +mozilla_embed_find_init (MozillaEmbedFind *find) +{ + find->priv = MOZILLA_EMBED_FIND_GET_PRIVATE (find); + find->priv->find = new EphyFind (); +} + +static GObject * +mozilla_embed_find_constructor (GType type, guint n_construct_properties, + GObjectConstructParam *construct_params) +{ + g_object_ref (embed_shell); + + /* we depend on single because of mozilla initialization */ + ephy_embed_shell_get_embed_single (embed_shell); + + return parent_class->constructor (type, n_construct_properties, + construct_params); +} + +static void +mozilla_embed_find_finalize (GObject *object) +{ + MozillaEmbedFind *find = MOZILLA_EMBED_FIND (object); + + delete find->priv->find; + + parent_class->finalize (object); + + g_object_unref (embed_shell); +} + +static void +mozilla_embed_find_class_init (MozillaEmbedFindClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = (GObjectClass *) g_type_class_peek_parent (klass); + + object_class->constructor = mozilla_embed_find_constructor; + object_class->finalize = mozilla_embed_find_finalize; + + g_type_class_add_private (object_class, sizeof (MozillaEmbedFindPrivate)); +} + +GType +mozilla_embed_find_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) + { + const GTypeInfo our_info = + { + sizeof (MozillaEmbedFindClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) mozilla_embed_find_class_init, + NULL, + NULL, /* class_data */ + sizeof (MozillaEmbedFind), + 0, /* n_preallocs */ + (GInstanceInitFunc) mozilla_embed_find_init + }; + + const GInterfaceInfo find_info = + { + (GInterfaceInitFunc) ephy_find_iface_init, + NULL, + NULL + }; + + type = g_type_register_static (G_TYPE_OBJECT, + "MozillaEmbedFind", + &our_info, + (GTypeFlags)0); + g_type_add_interface_static (type, + EPHY_TYPE_EMBED_FIND, + &find_info); + } + + return type; +} diff --git a/embed/xulrunner/embed/mozilla-embed-find.h b/embed/xulrunner/embed/mozilla-embed-find.h new file mode 100644 index 000000000..1291f3795 --- /dev/null +++ b/embed/xulrunner/embed/mozilla-embed-find.h @@ -0,0 +1,57 @@ +/* + * Copyright © 2000-2004 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#ifndef MOZILLA_EMBED_FIND_H +#define MOZILLA_EMBED_FIND_H + +#include <glib.h> +#include <glib-object.h> + +G_BEGIN_DECLS + +#define MOZILLA_TYPE_EMBED_FIND (mozilla_embed_find_get_type ()) +#define MOZILLA_EMBED_FIND(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), MOZILLA_TYPE_EMBED_FIND, MozillaEmbedFind)) +#define MOZILLA_EMBED_FIND_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), MOZILLA_TYPE_EMBED_FIND, MozillaEmbedFindClass)) +#define MOZILLA_IS_EMBED_FIND(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), MOZILLA_TYPE_EMBED_FIND)) +#define MOZILLA_IS_EMBED_FIND_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), MOZILLA_TYPE_EMBED_FIND)) +#define MOZILLA_EMBED_FIND_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), MOZILLA_TYPE_EMBED_FIND, MozillaEmbedFindClass)) + +typedef struct _MozillaEmbedFindClass MozillaEmbedFindClass; +typedef struct _MozillaEmbedFind MozillaEmbedFind; +typedef struct _MozillaEmbedFindPrivate MozillaEmbedFindPrivate; + +struct _MozillaEmbedFind +{ + GObject parent_instance; + + /*< private >*/ + MozillaEmbedFindPrivate *priv; +}; + +struct _MozillaEmbedFindClass +{ + GObjectClass parent_class; +}; + +GType mozilla_embed_find_get_type (void); + +G_END_DECLS + +#endif diff --git a/embed/xulrunner/embed/mozilla-embed-persist.cpp b/embed/xulrunner/embed/mozilla-embed-persist.cpp new file mode 100644 index 000000000..16909b49c --- /dev/null +++ b/embed/xulrunner/embed/mozilla-embed-persist.cpp @@ -0,0 +1,416 @@ +/* + * Copyright © 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#include "mozilla-config.h" +#include "config.h" + +#include <stddef.h> + +#include <nsStringAPI.h> + +#include <nsCOMPtr.h> +#include <nsComponentManagerUtils.h> +#include <nsCWebBrowserPersist.h> +#include <nsICacheEntryDescriptor.h> +#include <nsICacheService.h> +#include <nsICacheSession.h> +#include <nsIDOMSerializer.h> +#include <nsIFile.h> +#include <nsIHistoryEntry.h> +#include <nsIInputStream.h> +#include <nsIIOService.h> +#include <nsILocalFile.h> +#include <nsISHEntry.h> +#include <nsIURI.h> +#include <nsIWebBrowserPersist.h> +#include <nsNetCID.h> +#include <nsNetError.h> +#include <nsServiceManagerUtils.h> +#include <nsXPCOM.h> + +#include "EphyBrowser.h" +#include "EphyHeaderSniffer.h" +#include "EphyUtils.h" +#include "MozDownload.h" + +#include "ephy-debug.h" +#include "ephy-embed-shell.h" +#include "ephy-file-helpers.h" +#include "mozilla-embed.h" + +#include "mozilla-embed-persist.h" + +static void +mozilla_embed_persist_class_init (MozillaEmbedPersistClass *klass); +static void +mozilla_embed_persist_init (MozillaEmbedPersist *ges); +static void +mozilla_embed_persist_finalize (GObject *object); + +#define MOZILLA_EMBED_PERSIST_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), MOZILLA_TYPE_EMBED_PERSIST, MozillaEmbedPersistPrivate)) + +struct MozillaEmbedPersistPrivate +{ + nsCOMPtr<nsIWebBrowserPersist> mPersist; +}; + +static GObjectClass *parent_class = NULL; + +GType +mozilla_embed_persist_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) + { + 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 + }; + + type = g_type_register_static (EPHY_TYPE_EMBED_PERSIST, + "MozillaEmbedPersist", + &our_info, (GTypeFlags) 0); + } + + return type; +} + +static void +mozilla_embed_persist_init (MozillaEmbedPersist *persist) +{ + persist->priv = MOZILLA_EMBED_PERSIST_GET_PRIVATE (persist); + + persist->priv->mPersist = do_CreateInstance (NS_WEBBROWSERPERSIST_CONTRACTID); +} + +static void +mozilla_embed_persist_finalize (GObject *object) +{ + MozillaEmbedPersist *persist = MOZILLA_EMBED_PERSIST (object); + + persist->priv->mPersist = nsnull; + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +void +mozilla_embed_persist_completed (MozillaEmbedPersist *persist) +{ + g_signal_emit_by_name (persist, "completed"); + g_object_unref (persist); +} + +void +mozilla_embed_persist_cancelled (MozillaEmbedPersist *persist) +{ + g_signal_emit_by_name (persist, "cancelled"); + g_object_unref (persist); +} + +static void +impl_cancel (EphyEmbedPersist *persist) +{ + nsCOMPtr<nsIWebBrowserPersist> bpersist = + MOZILLA_EMBED_PERSIST (persist)->priv->mPersist; + nsCOMPtr<nsICancelable> cancelable (do_QueryInterface (bpersist)); + if (cancelable) + { + cancelable->Cancel (NS_BINDING_ABORTED); + } + + g_object_unref (persist); +} + +static gboolean +impl_save (EphyEmbedPersist *persist) +{ + nsresult rv; + char *filename; + char *uri; + gint64 max_size; + EphyEmbed *embed; + EphyEmbedPersistFlags flags; + EphyEmbedSingle *single; + + single = EPHY_EMBED_SINGLE (ephy_embed_shell_get_embed_single (embed_shell)); + + g_object_ref (persist); + + g_object_get (persist, + "source", &uri, + "dest", &filename, + "flags", &flags, + "embed", &embed, + "max_size", &max_size, + (char *) NULL); + + g_return_val_if_fail (!(flags & EPHY_EMBED_PERSIST_COPY_PAGE) + || embed != NULL, FALSE); + + EphyBrowser *browser = NULL; + if (embed) + { + browser = (EphyBrowser *) _mozilla_embed_get_ephy_browser (MOZILLA_EMBED(embed)); + + g_object_unref (embed); + + NS_ENSURE_TRUE (browser, FALSE); + } + /* we must have one of uri or browser */ + g_assert (browser != NULL || uri != NULL); + + /* Get the uri to save to */ + nsCOMPtr<nsIURI> inURI; + if (uri) + { + /* FIXME: origin charset!! */ + rv = EphyUtils::NewURI (getter_AddRefs(inURI), nsCString(uri)); + NS_ENSURE_SUCCESS (rv, FALSE); + } + else + { + rv = browser->GetDocumentURI (getter_AddRefs (inURI)); + NS_ENSURE_SUCCESS (rv, FALSE); + } + + /* Get post data */ + nsCOMPtr<nsIInputStream> postData; + /* FIXME: don't do this on COPY_PAGE to ensure we don't end up reposting? */ + if (browser) + { + PRInt32 sindex; + + nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(browser->mWebBrowser)); + nsCOMPtr<nsISHistory> sessionHistory; + webNav->GetSessionHistory(getter_AddRefs(sessionHistory)); + nsCOMPtr<nsIHistoryEntry> entry; + sessionHistory->GetIndex(&sindex); + sessionHistory->GetEntryAtIndex(sindex, PR_FALSE, getter_AddRefs(entry)); + nsCOMPtr<nsISHEntry> shEntry(do_QueryInterface(entry)); + if (shEntry) + { + shEntry->GetPostData(getter_AddRefs(postData)); + } + } + + /* Get the DOM document if a uri is not specified */ + nsCOMPtr<nsIDOMDocument> DOMDocument; + if (!uri) + { + if (flags & EPHY_EMBED_PERSIST_MAINDOC) + { + browser->GetDocument (getter_AddRefs(DOMDocument)); + } + else + { + browser->GetTargetDocument (getter_AddRefs(DOMDocument)); + } + NS_ENSURE_TRUE (DOMDocument, FALSE); + } + + + /* Get the current page descriptor */ + nsCOMPtr<nsISupports> cacheDescriptor; + if (browser) + { + browser->GetPageDescriptor(getter_AddRefs (cacheDescriptor)); + } + + /* Try to get a descriptor from the cache session */ + /* FIXME: what about https?? */ + PRBool isHttp = PR_FALSE, isHttps = PR_FALSE; + if (!cacheDescriptor && + (flags & EPHY_EMBED_PERSIST_FROM_CACHE) && + inURI && + ((NS_SUCCEEDED (inURI->SchemeIs ("http", &isHttp)) && isHttp) || + (NS_SUCCEEDED (inURI->SchemeIs ("https", &isHttps)) && isHttps ))) + { + nsCOMPtr<nsICacheService> cacheService + (do_GetService(NS_CACHESERVICE_CONTRACTID)); + if (cacheService) + { + nsCOMPtr<nsICacheSession> cacheSession; + rv = cacheService->CreateSession ("HTTP", + nsICache::STORE_ANYWHERE, + PR_TRUE, + getter_AddRefs (cacheSession)); + if (NS_SUCCEEDED (rv) && cacheSession) + { + nsCOMPtr<nsICacheEntryDescriptor> descriptor; + + nsCString spec; + inURI->GetSpec (spec); + + rv = cacheSession->OpenCacheEntry + (spec, + nsICache::ACCESS_READ, + PR_FALSE, getter_AddRefs (descriptor)); + + cacheDescriptor = do_QueryInterface (descriptor); + + LOG ("Getting cache descriptor for '%s' rv=%x", spec.get(), rv); + } + } + } + + LOG ("Cache descriptor %p", cacheDescriptor.get()); + + /* if we have COPY_PAGE, we *need* to have a page descriptor, else we'll re-fetch + * the page, which will possibly give a different page than the original which we + * need for view source + */ + NS_ENSURE_TRUE (!(flags & EPHY_EMBED_PERSIST_COPY_PAGE) || cacheDescriptor, FALSE); + + if (filename == NULL || filename[0] == '\0') + { + /* Get a temp filename to save to */ + char *tmp_filename, *base; + base = g_build_filename (g_get_tmp_dir (), "sav-XXXXXX", (char *) NULL); + tmp_filename = ephy_file_tmp_filename (base, "html"); + g_free (base); + if (tmp_filename == NULL) return FALSE; + + nsCOMPtr<nsILocalFile> tmpFile = do_CreateInstance (NS_LOCAL_FILE_CONTRACTID); + NS_ENSURE_TRUE (tmpFile, FALSE); + + tmpFile->InitWithNativePath (nsCString (tmp_filename)); + g_free (tmp_filename); + + /* Create an header sniffer and do the save */ + nsCOMPtr<nsIWebBrowserPersist> webPersist = + MOZILLA_EMBED_PERSIST (persist)->priv->mPersist; + NS_ENSURE_TRUE (webPersist, FALSE); + + EphyHeaderSniffer* sniffer = new EphyHeaderSniffer + (webPersist, MOZILLA_EMBED_PERSIST (persist), + tmpFile, inURI, DOMDocument, postData, single); + if (!sniffer) return FALSE; + + webPersist->SetProgressListener(sniffer); + rv = webPersist->SaveURI(inURI, cacheDescriptor, nsnull /* FIXME: Referrer */, nsnull, nsnull, tmpFile); + if (NS_FAILED (rv)) return FALSE; + } + else + { + /* Filename to save to */ + nsCOMPtr<nsILocalFile> destFile; + NS_NewNativeLocalFile (nsCString(filename), + PR_TRUE, getter_AddRefs(destFile)); + NS_ENSURE_TRUE (destFile, FALSE); + + rv = InitiateMozillaDownload (DOMDocument, inURI, destFile, + nsnull, inURI, MOZILLA_EMBED_PERSIST (persist), + postData, cacheDescriptor, max_size); + if (NS_FAILED (rv)) return FALSE; + } + + g_free (uri); + g_free (filename); + + return TRUE; +} + +static char * +impl_to_string (EphyEmbedPersist *persist) +{ + EphyEmbed *embed; + nsCOMPtr<nsIDOMDocument> DOMDocument; + EphyEmbedPersistFlags flags; + EphyBrowser *browser; + nsresult rv = NS_OK; + + g_object_ref (persist); + + g_object_get (persist, + "flags", &flags, + "embed", &embed, + (char *) NULL); + g_object_unref (persist); + g_return_val_if_fail (embed != NULL, NULL); + + browser = (EphyBrowser *) _mozilla_embed_get_ephy_browser (MOZILLA_EMBED(embed)); + g_return_val_if_fail (browser != NULL, NULL); + + if (flags & EPHY_EMBED_PERSIST_MAINDOC) + { + rv = browser->GetDocument (getter_AddRefs(DOMDocument)); + } + else + { + rv = browser->GetTargetDocument (getter_AddRefs(DOMDocument)); + } + + nsCString cOutString; + nsCOMPtr<nsIDOMNode> node = do_QueryInterface(DOMDocument); + if (node) + { + nsString outString; + nsCOMPtr<nsIDOMSerializer> serializer; + serializer = do_CreateInstance(NS_XMLSERIALIZER_CONTRACTID, &rv); + if (serializer) + { + serializer->SerializeToString(node, outString); + + NS_UTF16ToCString (outString, NS_CSTRING_ENCODING_UTF8, cOutString); + } + } + + g_object_unref (embed); + + return g_strdup (cOutString.get()); +} + +static GObject * +mozilla_embed_persist_constructor (GType type, guint n_construct_properties, + GObjectConstructParam *construct_params) +{ + /* this will ensure that mozilla is started up */ + ephy_embed_shell_get_embed_single (embed_shell); + + return parent_class->constructor (type, n_construct_properties, + construct_params); +} + +static void +mozilla_embed_persist_class_init (MozillaEmbedPersistClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + EphyEmbedPersistClass *persist_class = EPHY_EMBED_PERSIST_CLASS (klass); + + parent_class = (GObjectClass *) g_type_class_peek_parent (klass); + + object_class->finalize = mozilla_embed_persist_finalize; + object_class->constructor = mozilla_embed_persist_constructor; + + persist_class->save = impl_save; + persist_class->cancel = impl_cancel; + persist_class->to_string = impl_to_string; + + g_type_class_add_private (object_class, sizeof(MozillaEmbedPersistPrivate)); +} diff --git a/embed/xulrunner/embed/mozilla-embed-persist.h b/embed/xulrunner/embed/mozilla-embed-persist.h new file mode 100644 index 000000000..edcb1eb53 --- /dev/null +++ b/embed/xulrunner/embed/mozilla-embed-persist.h @@ -0,0 +1,63 @@ +/* + * Copyright © 2000-2003 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#ifndef MOZILLA_EMBED_PERSIST_H +#define MOZILLA_EMBED_PERSIST_H + +#include <glib.h> +#include <glib-object.h> + +#include "ephy-embed-persist.h" + +G_BEGIN_DECLS + +#define MOZILLA_TYPE_EMBED_PERSIST (mozilla_embed_persist_get_type ()) +#define MOZILLA_EMBED_PERSIST(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), MOZILLA_TYPE_EMBED_PERSIST, MozillaEmbedPersist)) +#define MOZILLA_EMBED_PERSIST_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), MOZILLA_TYPE_EMBED_PERSIST, MozillaEmbedPersistClass)) +#define MOZILLA_IS_EMBED_PERSIST(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), MOZILLA_TYPE_EMBED_PERSIST)) +#define MOZILLA_IS_EMBED_PERSIST_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), MOZILLA_TYPE_EMBED_PERSIST)) +#define MOZILLA_EMBED_PERSIST_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), MOZILLA_TYPE_EMBED_PERSIST, MozillaEmbedPersistClass)) + +typedef struct MozillaEmbedPersistClass MozillaEmbedPersistClass; +typedef struct MozillaEmbedPersist MozillaEmbedPersist; +typedef struct MozillaEmbedPersistPrivate MozillaEmbedPersistPrivate; + +struct MozillaEmbedPersist +{ + EphyEmbedPersist parent; + + /*< private >*/ + MozillaEmbedPersistPrivate *priv; +}; + +struct MozillaEmbedPersistClass +{ + EphyEmbedPersistClass parent_class; +}; + +GType mozilla_embed_persist_get_type (void); + +void mozilla_embed_persist_completed (MozillaEmbedPersist *persist); + +void mozilla_embed_persist_cancelled (MozillaEmbedPersist *persist); + +G_END_DECLS + +#endif diff --git a/embed/xulrunner/embed/mozilla-embed-single.cpp b/embed/xulrunner/embed/mozilla-embed-single.cpp new file mode 100644 index 000000000..1ebc2252c --- /dev/null +++ b/embed/xulrunner/embed/mozilla-embed-single.cpp @@ -0,0 +1,1445 @@ +/* vim:set ts=8 noet sw=8: + * Copyright © 2000-2004 Marco Pesenti Gritti + * Copyright © 2003 Robert Marcano + * Copyright © 2003, 2004, 2005, 2006 Christian Persch + * Copyright © 2005 Crispin Flowerday + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#include "mozilla-config.h" + +#include "config.h" + +#include <stdlib.h> + +#include <glib.h> +#include <glib/gi18n.h> +#include <libgnomevfs/gnome-vfs-utils.h> + +#include <nsStringAPI.h> + +#include <nsComponentManagerUtils.h> +#include <nsCOMPtr.h> +#include <nsCPasswordManager.h> +#include <nsICookie2.h> +#include <nsICookieManager.h> +#include <nsICookieManager.h> +#include <nsIFile.h> +#include <nsIIOService.h> +#include <nsILocalFile.h> +#include <nsIPermission.h> +#include <nsIPermissionManager.h> +#include <nsIPrefService.h> +#include <nsIStyleSheetService.h> +#include <nsISupportsPrimitives.h> +#include <nsIURI.h> +#include <nsIWindowWatcher.h> +#include <nsMemory.h> +#include <nsServiceManagerUtils.h> + +#ifdef HAVE_MOZILLA_PSM +#include <nsIX509Cert.h> +#include <nsIX509CertDB.h> +#endif + +#ifdef ALLOW_PRIVATE_API +#include <nsICacheService.h> +#include <nsIFontEnumerator.h> +#include <nsIHttpAuthManager.h> +#include <nsIIDNService.h> +#include <nsNetCID.h> +#endif /* ALLOW_PRIVATE_API */ + +#ifndef HAVE_GECKO_1_9 +#include <nsIPassword.h> +#include <nsIPasswordManager.h> +#endif /* !HAVE_GECKO_1_9 */ + +#define XPCOM_GLUE +#include <nsXPCOMGlue.h> + +#include "gecko-init.h" +#include "gecko-init-internal.h" +#include "gecko-embed.h" +#include "gecko-embed-single.h" + +#include "ephy-file-helpers.h" +#include "eel-gconf-extensions.h" +#include "ephy-certificate-manager.h" +#include "ephy-cookie-manager.h" +#include "ephy-debug.h" +#include "ephy-embed-prefs.h" +#include "ephy-embed-shell.h" +#include "ephy-file-helpers.h" +#include "ephy-langs.h" +#include "ephy-password-manager.h" +#include "ephy-permission-manager.h" +#include "mozilla-embed.h" +#include "mozilla-notifiers.h" +#include "mozilla-x509-cert.h" + +#include "EphyBrowser.h" +#include "EphyDirectoryProvider.h" +#include "EphySingle.h" +#include "EphyUtils.h" +#include "MozRegisterComponents.h" + +#include "mozilla-embed-single.h" + +#include "AutoJSContextStack.h" + +#define MOZILLA_PROFILE_DIR "/mozilla" +#define MOZILLA_PROFILE_NAME "epiphany" +#define MOZILLA_PROFILE_FILE "prefs.js" +#define DEFAULT_PROFILE_FILE SHARE_DIR"/default-prefs.js" + +#define USER_CSS_LOAD_DELAY 500 /* ms */ + +#define MOZILLA_EMBED_SINGLE_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), MOZILLA_TYPE_EMBED_SINGLE, MozillaEmbedSinglePrivate)) + +struct MozillaEmbedSinglePrivate +{ + char *user_prefs; + + EphySingle *mSingleObserver; + + char *user_css_file; + guint user_css_enabled_notifier_id; + EphyFileMonitor *user_css_file_monitor; + guint user_css_enabled : 1; + + guint online : 1; +}; + +enum +{ + PROP_0, + PROP_NETWORK_STATUS +}; + +static void mozilla_embed_single_class_init (MozillaEmbedSingleClass *klass); +static void ephy_embed_single_iface_init (EphyEmbedSingleIface *iface); +static void ephy_cookie_manager_iface_init (EphyCookieManagerIface *iface); +static void ephy_password_manager_iface_init (EphyPasswordManagerIface *iface); +static void ephy_permission_manager_iface_init (EphyPermissionManagerIface *iface); +static void mozilla_embed_single_init (MozillaEmbedSingle *ges); + +#ifdef ENABLE_CERTIFICATE_MANAGER +static void ephy_certificate_manager_iface_init (EphyCertificateManagerIface *iface); +#endif + +static GObjectClass *parent_class = NULL; + +GType +mozilla_embed_single_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) + { + const GTypeInfo our_info = + { + sizeof (MozillaEmbedSingleClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) mozilla_embed_single_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (MozillaEmbedSingle), + 0, /* n_preallocs */ + (GInstanceInitFunc) mozilla_embed_single_init + }; + + const GInterfaceInfo embed_single_info = + { + (GInterfaceInitFunc) ephy_embed_single_iface_init, + NULL, + NULL + }; + + const GInterfaceInfo cookie_manager_info = + { + (GInterfaceInitFunc) ephy_cookie_manager_iface_init, + NULL, + NULL + }; + + const GInterfaceInfo password_manager_info = + { + (GInterfaceInitFunc) ephy_password_manager_iface_init, + NULL, + NULL + }; + + const GInterfaceInfo permission_manager_info = + { + (GInterfaceInitFunc) ephy_permission_manager_iface_init, + NULL, + NULL + }; + +#ifdef ENABLE_CERTIFICATE_MANAGER + const GInterfaceInfo certificate_manager_info = + { + (GInterfaceInitFunc) ephy_certificate_manager_iface_init, + NULL, + NULL + }; +#endif + + type = g_type_register_static (G_TYPE_OBJECT, + "MozillaEmbedSingle", + &our_info, + (GTypeFlags)0); + + g_type_add_interface_static (type, + EPHY_TYPE_EMBED_SINGLE, + &embed_single_info); + + g_type_add_interface_static (type, + EPHY_TYPE_COOKIE_MANAGER, + &cookie_manager_info); + + g_type_add_interface_static (type, + EPHY_TYPE_PASSWORD_MANAGER, + &password_manager_info); + + g_type_add_interface_static (type, + EPHY_TYPE_PERMISSION_MANAGER, + &permission_manager_info); +#ifdef ENABLE_CERTIFICATE_MANAGER + g_type_add_interface_static (type, + EPHY_TYPE_CERTIFICATE_MANAGER, + &certificate_manager_info); +#endif + } + + return type; +} + +static gboolean +mozilla_set_default_prefs (MozillaEmbedSingle *mes) +{ + nsCOMPtr<nsIPrefService> prefService; + + prefService = do_GetService (NS_PREFSERVICE_CONTRACTID); + NS_ENSURE_TRUE (prefService, FALSE); + + /* read our predefined default prefs */ + nsresult rv; + nsCOMPtr<nsILocalFile> file; + NS_NewNativeLocalFile(nsCString(DEFAULT_PROFILE_FILE), + PR_TRUE, getter_AddRefs(file)); + if (!file) return FALSE; + + rv = prefService->ReadUserPrefs (file); + if (NS_FAILED(rv)) + { + g_warning ("failed to read default preferences, error: %x", rv); + return FALSE; + } + + nsCOMPtr<nsIPrefBranch> pref; + prefService->GetBranch ("", getter_AddRefs(pref)); + NS_ENSURE_TRUE (pref, FALSE); + + /* We do this before reading the user pref file so that the user + * still can overwrite this pref. + * We don't use the default-prefs.js file since that cannot be + * localised (see bug #144909). + */ + /* translators: this is the URL that searches from the location + * entry get directed to. The search terms will be _appended_ to it, + * in url-escaped UTF-8; that means that if you're choosing google, + * the 'q=' part needs to come last. + */ + pref->SetCharPref ("keyword.URL", _("http://www.google.com/search?ie=UTF-8&oe=UTF-8&q=")); + + /* Load the default user preferences as well. This also makes the + prefs to be saved in the user's prefs.js file, instead of messing up + our global defaults file. */ + rv = prefService->ReadUserPrefs (nsnull); + if (NS_FAILED(rv)) + { + g_warning ("failed to read user preferences, error: %x", rv); + } + + pref->SetCharPref ("general.useragent.extra.epiphany", "Epiphany/" UA_VERSION); + + /* Unset old prefs, otherwise they end up in the user agent string too */ + pref->ClearUserPref ("general.useragent.vendor"); + pref->ClearUserPref ("general.useragent.vendorSub"); + + /* Don't open ftp uris with an external handler if one is setup */ + pref->SetBoolPref ("network.protocol-handler.external.ftp", PR_FALSE); + + return TRUE; +} + +static void +mozilla_embed_single_new_window_orphan_cb (GeckoEmbedSingle *moz_single, + GeckoEmbed **newEmbed, + guint chrome_mask, + EphyEmbedSingle *single) +{ + GeckoEmbedChromeFlags chrome = (GeckoEmbedChromeFlags) chrome_mask; + EphyEmbed *new_embed = NULL; + EphyEmbedChrome mask; + + if (chrome_mask & GECKO_EMBED_FLAG_OPENASCHROME) + { + *newEmbed = _mozilla_embed_new_xul_dialog (); + return; + } + + mask = _mozilla_embed_translate_chrome (chrome); + + g_signal_emit_by_name (single, "new-window", NULL, mask, + &new_embed); + + /* it's okay not to have a new embed */ + if (new_embed != NULL) + { + gecko_embed_set_chrome_mask (GECKO_EMBED (new_embed), chrome); + + *newEmbed = GECKO_EMBED (new_embed); + } +} + +static GList * +mozilla_init_plugin_add_unique_path (GList *list, + const char *path) +{ + GList *l; + char *canon; + + if (path == NULL) + return list; + + canon = gnome_vfs_make_path_name_canonical (path); + for (l = list; l != NULL; l = l->next) { + if (g_str_equal (list->data, canon) != FALSE) { + /* The path is already in the list */ + g_free (canon); + return list; + } + } + return g_list_prepend (list, canon); +} + +static GList * +mozilla_init_plugin_add_unique_paths (GList *list, + const char *path) +{ + char **paths; + guint i; + + if (path == NULL) + return list; + + paths = g_strsplit (path, ":", -1); + if (paths == NULL) + return list; + for (i = 0; paths[i] != NULL; i++) { + list = mozilla_init_plugin_add_unique_path (list, paths[i]); + } + g_strfreev (paths); + return list; +} + +static void +mozilla_init_plugin_path () +{ + GList *list, *l; + GString *path; + + list = NULL; + list = mozilla_init_plugin_add_unique_paths (list, + g_getenv ("MOZ_PLUGIN_PATH")); + list = mozilla_init_plugin_add_unique_path (list, + MOZILLA_PREFIX "/lib/mozilla/plugins"); + list = mozilla_init_plugin_add_unique_path (list, + MOZILLA_HOME "/plugins"); + list = mozilla_init_plugin_add_unique_path (list, + MOZILLA_NATIVE_PLUGINSDIR); +#ifdef HAVE_PRIVATE_PLUGINS + list = mozilla_init_plugin_add_unique_path (list, PLUGINDIR); +#endif + + list = g_list_reverse (list); + path = g_string_new ((const char *) list->data); + g_free (list->data); + l = list->next; + for (; l != NULL; l = l->next) { + path = g_string_append_c (path, ':'); + path = g_string_append (path, (const char *) l->data); + g_free (l->data); + } + g_list_free (list); + + g_setenv ("MOZ_PLUGIN_PATH", path->str, TRUE); + g_string_free (path, TRUE); +} + +static void +mozilla_init_single (MozillaEmbedSingle *mes) +{ + GeckoEmbedSingle *single; + + /* get single */ + single = gecko_embed_single_get (); + if (single == NULL) + { + g_warning ("Failed to get singleton embed object!\n"); + return; + } + + /* allow creation of orphan windows */ + g_signal_connect (G_OBJECT (single), "new_window_orphan", + G_CALLBACK (mozilla_embed_single_new_window_orphan_cb), + mes); +} + +#if defined(MOZ_NSIXULCHROMEREGISTRY_SELECTSKIN) || defined(HAVE_CHROME_NSICHROMEREGISTRYSEA_H) +static nsresult +getUILang (nsAString& aUILang) +{ + nsresult rv; + + nsCOMPtr<nsILocaleService> localeService = do_GetService (NS_LOCALESERVICE_CONTRACTID); + if (!localeService) + { + g_warning ("Could not get locale service!\n"); + return NS_ERROR_FAILURE; + } + + rv = localeService->GetLocaleComponentForUserAgent (aUILang); + + if (NS_FAILED (rv)) + { + g_warning ("Could not determine locale!\n"); + return NS_ERROR_FAILURE; + } + + return NS_OK; +} +#endif + +static void +mozilla_init_observer (MozillaEmbedSingle *single) +{ + EphySingle *es; + + es = new EphySingle (); + NS_ADDREF (single->priv->mSingleObserver = es); + + nsresult rv; + rv = es->Init (EPHY_EMBED_SINGLE (single)); + if (NS_FAILED (rv)) + { + g_warning ("Failed to initialise EphySingle!\n"); + return; + } +} + +static void +user_css_register (MozillaEmbedSingle *single) +{ + MozillaEmbedSinglePrivate *priv = single->priv; + + nsresult rv; + nsCOMPtr<nsILocalFile> file; + rv = NS_NewNativeLocalFile (nsDependentCString (priv->user_css_file), + PR_TRUE, getter_AddRefs (file)); + NS_ENSURE_SUCCESS (rv, ); + + PRBool exists = PR_FALSE; + rv = file->Exists (&exists); + if (NS_FAILED (rv) || !exists) return; + + nsCOMPtr<nsIURI> uri; + rv = EphyUtils::NewFileURI (getter_AddRefs (uri), file); + NS_ENSURE_SUCCESS (rv, ); + + nsCOMPtr<nsIStyleSheetService> service + (do_GetService ("@mozilla.org/content/style-sheet-service;1", &rv)); + NS_ENSURE_SUCCESS (rv, ); + + PRBool isRegistered = PR_FALSE; + rv = service->SheetRegistered (uri, nsIStyleSheetService::USER_SHEET, + &isRegistered); + if (NS_SUCCEEDED (rv) && isRegistered) + { + rv = service->UnregisterSheet (uri, nsIStyleSheetService::USER_SHEET); + } + + rv = service->LoadAndRegisterSheet (uri, nsIStyleSheetService::AGENT_SHEET); + if (NS_FAILED (rv)) + { + g_warning ("Registering the user stylesheet failed (rv=%x)!\n", rv); + } +} + +static void +user_css_unregister (MozillaEmbedSingle *single) +{ + MozillaEmbedSinglePrivate *priv = single->priv; + + nsresult rv; + nsCOMPtr<nsILocalFile> file; + rv = NS_NewNativeLocalFile (nsDependentCString (priv->user_css_file), + PR_TRUE, getter_AddRefs (file)); + NS_ENSURE_SUCCESS (rv, ); + + nsCOMPtr<nsIURI> uri; + rv = EphyUtils::NewFileURI (getter_AddRefs (uri), file); + NS_ENSURE_SUCCESS (rv, ); + + nsCOMPtr<nsIStyleSheetService> service + (do_GetService ("@mozilla.org/content/style-sheet-service;1", &rv)); + NS_ENSURE_SUCCESS (rv, ); + + PRBool isRegistered = PR_FALSE; + rv = service->SheetRegistered (uri, nsIStyleSheetService::USER_SHEET, + &isRegistered); + if (NS_SUCCEEDED (rv) && isRegistered) + { + rv = service->UnregisterSheet (uri, nsIStyleSheetService::USER_SHEET); + } + if (NS_FAILED (rv)) + { + g_warning ("Unregistering the user stylesheet failed (rv=%x)!\n", rv); + } +} + +static void +user_css_file_monitor_func (EphyFileMonitor *, + const char *, + GnomeVFSMonitorEventType event_type, + MozillaEmbedSingle *single) +{ + LOG ("Reregistering the user style sheet"); + + if (event_type == GNOME_VFS_MONITOR_EVENT_DELETED) + { + user_css_unregister (single); + } + else + { + user_css_register (single); + } +} + +static void +user_css_enabled_notify (GConfClient *client, + guint cnxn_id, + GConfEntry *entry, + MozillaEmbedSingle *single) +{ + MozillaEmbedSinglePrivate *priv = single->priv; + guint enabled; + + enabled = eel_gconf_get_boolean (CONF_USER_CSS_ENABLED) != FALSE; + if (priv->user_css_enabled == enabled) return; + + LOG ("User stylesheet enabled: %s", enabled ? "t" : "f"); + + priv->user_css_enabled = enabled; + + if (enabled) + { + char *uri; + + user_css_register (single); + + uri = gnome_vfs_get_uri_from_local_path (priv->user_css_file); + + g_assert (priv->user_css_file_monitor == NULL); + priv->user_css_file_monitor = + ephy_file_monitor_add (uri, + GNOME_VFS_MONITOR_FILE, + USER_CSS_LOAD_DELAY, + (EphyFileMonitorFunc) user_css_file_monitor_func, + NULL, + single); + g_free (uri); + } + else + { + if (priv->user_css_file_monitor != NULL) + { + ephy_file_monitor_cancel (priv->user_css_file_monitor); + priv->user_css_file_monitor = NULL; + } + + user_css_unregister (single); + } +} + +static void +mozilla_stylesheet_init (MozillaEmbedSingle *single) +{ + MozillaEmbedSinglePrivate *priv = single->priv; + + priv->user_css_file = g_build_filename (ephy_dot_dir (), + USER_STYLESHEET_FILENAME, + (char *) NULL); + + user_css_enabled_notify (NULL, 0, NULL, single); + priv->user_css_enabled_notifier_id = + eel_gconf_notification_add + (CONF_USER_CSS_ENABLED, + (GConfClientNotifyFunc) user_css_enabled_notify, + single); +} + +static void +mozilla_stylesheet_shutdown (MozillaEmbedSingle *single) +{ + MozillaEmbedSinglePrivate *priv = single->priv; + + if (priv->user_css_enabled_notifier_id != 0) + { + eel_gconf_notification_remove (priv->user_css_enabled_notifier_id); + priv->user_css_enabled_notifier_id = 0; + } + + if (priv->user_css_file_monitor != NULL) + { + ephy_file_monitor_cancel (priv->user_css_file_monitor); + priv->user_css_file_monitor = NULL; + } + + if (priv->user_css_file != NULL) + { + g_free (priv->user_css_file); + priv->user_css_file = NULL; + } +} + +static gboolean +impl_init (EphyEmbedSingle *esingle) +{ + MozillaEmbedSingle *single = MOZILLA_EMBED_SINGLE (esingle); + char *profile_path; + + g_setenv ("MOZILLA_POSTSCRIPT_ENABLED", "1", TRUE); + g_unsetenv ("MOZILLA_POSTSCRIPT_PRINTER_LIST"); + + NS_LogInit (); + + /* Pre initialization */ + mozilla_init_plugin_path (); + + profile_path = g_build_filename (ephy_dot_dir (), + MOZILLA_PROFILE_DIR, + (char *) NULL); + +// gecko_embed_set_comp_path (MOZILLA_HOME); + + static const GREVersionRange greVersion = { + "1.9a", PR_TRUE, + "2", PR_TRUE + }; + + char xpcomPath[PATH_MAX]; + + nsresult rv = GRE_GetGREPathWithProperties(&greVersion, 1, nsnull, 0, + xpcomPath, sizeof(xpcomPath)); + if (NS_FAILED(rv)) { + fprintf(stderr, "Couldn't find a compatible GRE.\n"); + return 1; + } + + rv = XPCOMGlueStartup(xpcomPath); + if (NS_FAILED(rv)) { + fprintf(stderr, "Couldn't start XPCOM."); + return 1; + } + + char *lastSlash = strrchr(xpcomPath, '/'); + if (lastSlash) + *lastSlash = '\0'; + + + nsCOMPtr<nsIDirectoryServiceProvider> dp = new EphyDirectoryProvider (); + if (!dp) return FALSE; + + if (!gecko_init_with_params (xpcomPath, + profile_path, + MOZILLA_PROFILE_NAME, + dp)) { + g_free (profile_path); + g_warning ("Failed to init gecko!\n"); + return FALSE; + } + + g_free (profile_path); + + mozilla_register_components (); + + mozilla_init_single (single); + + if (!mozilla_set_default_prefs (single)) + { + return FALSE; + } + + START_PROFILER ("Mozilla prefs notifiers") + mozilla_notifiers_init (); + STOP_PROFILER ("Mozilla prefs notifiers") + + mozilla_init_observer (single); + + mozilla_stylesheet_init (single); + + return TRUE; +} + +static void +prepare_close_cb (EphyEmbedShell *shell) +{ + GValue value = { 0, }; + + /* To avoid evil web sites posing an alert and thus inhibiting + * shutdown, we just turn off javascript! :) + */ + g_value_init (&value, G_TYPE_BOOLEAN); + g_value_set_boolean (&value, FALSE); + mozilla_pref_set ("javascript.enabled", &value); + g_value_unset (&value); +} + +static void +mozilla_embed_single_init (MozillaEmbedSingle *mes) +{ + mes->priv = MOZILLA_EMBED_SINGLE_GET_PRIVATE (mes); + + mes->priv->user_prefs = + g_build_filename (ephy_dot_dir (), + MOZILLA_PROFILE_DIR, + MOZILLA_PROFILE_NAME, + MOZILLA_PROFILE_FILE, + (char *) NULL); + + g_signal_connect_object (embed_shell, "prepare-close", + G_CALLBACK (prepare_close_cb), mes, + (GConnectFlags) 0); +} + +static void +mozilla_embed_single_dispose (GObject *object) +{ + MozillaEmbedSingle *single = MOZILLA_EMBED_SINGLE (object); + MozillaEmbedSinglePrivate *priv = single->priv; + + mozilla_stylesheet_shutdown (single); + + if (priv->mSingleObserver) + { + priv->mSingleObserver->Detach (); + NS_RELEASE (priv->mSingleObserver); + priv->mSingleObserver = nsnull; + } + + parent_class->dispose (object); +} + +static void +mozilla_embed_single_finalize (GObject *object) +{ + MozillaEmbedSingle *mes = MOZILLA_EMBED_SINGLE (object); + + /* Destroy EphyEmbedSingle before because some + * services depend on xpcom */ + G_OBJECT_CLASS (parent_class)->finalize (object); + + mozilla_notifiers_shutdown (); + + gecko_shutdown (); + + XPCOMGlueShutdown (); + + NS_LogTerm (); + + g_free (mes->priv->user_prefs); +} + +static void +impl_clear_cache (EphyEmbedSingle *shell) +{ + nsCOMPtr<nsICacheService> cacheService = + do_GetService (NS_CACHESERVICE_CONTRACTID); + if (!cacheService) return; + + cacheService->EvictEntries (nsICache::STORE_ANYWHERE); +} + +static void +impl_clear_auth_cache (EphyEmbedSingle *shell) +{ + nsCOMPtr<nsIHttpAuthManager> authManager = + do_GetService (NS_HTTPAUTHMANAGER_CONTRACTID); + if (!authManager) return; + + authManager->ClearAll(); +} + +static void +impl_set_network_status (EphyEmbedSingle *single, + gboolean online) +{ + nsCOMPtr<nsIIOService> io = do_GetService(NS_IOSERVICE_CONTRACTID); + if (!io) return; + + io->SetOffline (!online); +} + +static gboolean +impl_get_network_status (EphyEmbedSingle *esingle) +{ + MozillaEmbedSingle *single = MOZILLA_EMBED_SINGLE (esingle); + MozillaEmbedSinglePrivate *priv = single->priv; + + NS_ENSURE_TRUE (priv->mSingleObserver, TRUE); + + nsCOMPtr<nsIIOService> io = do_GetService(NS_IOSERVICE_CONTRACTID); + if (!io) return FALSE; /* no way to check the state, assume offline */ + + PRBool isOffline; + nsresult rv; + rv = io->GetOffline(&isOffline); + NS_ENSURE_SUCCESS (rv, FALSE); + + PRBool isOnline = !isOffline; + PRBool reallyOnline = priv->mSingleObserver->IsOnline (); + + g_return_val_if_fail (reallyOnline == isOnline, TRUE); + + return !isOffline; +} + +static const char* +impl_get_backend_name (EphyEmbedSingle *esingle) +{ + /* If you alter the return values here, remember to update + * the docs in ephy-embed-single.c */ +#if defined (HAVE_GECKO_1_10) +# error "Need to add version string for gecko 1.10" +#elif defined(HAVE_GECKO_1_9) + return "gecko-1.9"; +#elif defined(HAVE_GECKO_1_8) + return "gecko-1.8"; +#else +# error "Undefined/unsupported gecko version!" +#endif +} + +static GList * +impl_get_font_list (EphyEmbedSingle *shell, + const char *langGroup) +{ + nsresult rv; + PRUint32 fontCount; + PRUnichar **fontArray; + GList *l = NULL; + + nsCOMPtr<nsIFontEnumerator> mozFontEnumerator; + mozFontEnumerator = do_CreateInstance("@mozilla.org/gfx/fontenumerator;1"); + NS_ENSURE_TRUE (mozFontEnumerator, NULL); + + rv = mozFontEnumerator->EnumerateFonts (langGroup, nsnull, + &fontCount, &fontArray); + NS_ENSURE_SUCCESS (rv, NULL); + + for (PRUint32 i = 0; i < fontCount; i++) + { + char *gFontString; + + nsCString tmp; + NS_UTF16ToCString (nsString(fontArray[i]), + NS_CSTRING_ENCODING_UTF8, tmp); + gFontString = g_strdup (tmp.get()); + l = g_list_prepend (l, gFontString); + nsMemory::Free (fontArray[i]); + } + + nsMemory::Free (fontArray); + + return g_list_reverse (l); +} + +static GList * +impl_list_cookies (EphyCookieManager *manager) +{ + nsresult rv; + GList *cookies = NULL; + + nsCOMPtr<nsICookieManager> cookieManager = + do_GetService (NS_COOKIEMANAGER_CONTRACTID); + if (!cookieManager) return NULL; + + nsCOMPtr<nsISimpleEnumerator> cookieEnumerator; + cookieManager->GetEnumerator (getter_AddRefs(cookieEnumerator)); + NS_ENSURE_TRUE (cookieEnumerator, NULL); + + PRBool enumResult; + for (cookieEnumerator->HasMoreElements(&enumResult) ; + enumResult == PR_TRUE ; + cookieEnumerator->HasMoreElements(&enumResult)) + { + nsCOMPtr<nsICookie> keks; + rv = cookieEnumerator->GetNext (getter_AddRefs(keks)); + if (NS_FAILED (rv) || !keks) continue; + + EphyCookie *cookie = mozilla_cookie_to_ephy_cookie (keks); + if (!cookie) continue; + + cookies = g_list_prepend (cookies, cookie); + } + + return cookies; +} + +static void +impl_remove_cookie (EphyCookieManager *manager, + const EphyCookie *cookie) +{ + nsCOMPtr<nsICookieManager> cookieManager = + do_GetService (NS_COOKIEMANAGER_CONTRACTID); + if (!cookieManager) return; + + nsCOMPtr<nsIIDNService> idnService + (do_GetService ("@mozilla.org/network/idn-service;1")); + NS_ENSURE_TRUE (idnService, ); + + nsresult rv; + nsCString host; + rv = idnService->ConvertUTF8toACE (nsCString(cookie->domain), host); + NS_ENSURE_SUCCESS (rv, ); + + cookieManager->Remove (host, + nsCString(cookie->name), + nsCString(cookie->path), + PR_FALSE /* block */); +} + +static void +impl_clear_cookies (EphyCookieManager *manager) +{ + nsCOMPtr<nsICookieManager> cookieManager = + do_GetService (NS_COOKIEMANAGER_CONTRACTID); + if (!cookieManager) return; + + cookieManager->RemoveAll (); +} + +static GList * +impl_list_passwords (EphyPasswordManager *manager) +{ + GList *passwords = NULL; + +#ifndef HAVE_GECKO_1_9 + nsresult rv; + nsCOMPtr<nsIPasswordManager> passwordManager = + do_GetService (NS_PASSWORDMANAGER_CONTRACTID); + if (!passwordManager) return NULL; + + nsCOMPtr<nsIIDNService> idnService + (do_GetService ("@mozilla.org/network/idn-service;1")); + NS_ENSURE_TRUE (idnService, NULL); + + nsCOMPtr<nsISimpleEnumerator> passwordEnumerator; + passwordManager->GetEnumerator (getter_AddRefs(passwordEnumerator)); + NS_ENSURE_TRUE (passwordEnumerator, NULL); + + PRBool enumResult; + for (passwordEnumerator->HasMoreElements(&enumResult) ; + enumResult == PR_TRUE ; + passwordEnumerator->HasMoreElements(&enumResult)) + { + nsCOMPtr<nsIPassword> nsPassword; + passwordEnumerator->GetNext (getter_AddRefs(nsPassword)); + if (!nsPassword) continue; + + nsCString transfer; + rv = nsPassword->GetHost (transfer); + if (NS_FAILED (rv)) continue; + + nsCString host; + idnService->ConvertACEtoUTF8 (transfer, host); + + nsString unicodeName; + rv = nsPassword->GetUser (unicodeName); + if (NS_FAILED (rv)) continue; + + nsCString userName; + NS_UTF16ToCString (unicodeName, + NS_CSTRING_ENCODING_UTF8, userName); + + rv = nsPassword->GetPassword (unicodeName); + if (NS_FAILED (rv)) continue; + + nsCString userPassword; + NS_UTF16ToCString (unicodeName, + NS_CSTRING_ENCODING_UTF8, userPassword); + + EphyPasswordInfo *p = g_new0 (EphyPasswordInfo, 1); + + p->host = g_strdup (host.get()); + p->username = g_strdup (userName.get()); + p->password = g_strdup (userPassword.get()); + + passwords = g_list_prepend (passwords, p); + } +#endif /* !HAVE_GECKO_1_9 */ + + return passwords; +} + +static void +impl_remove_password (EphyPasswordManager *manager, + EphyPasswordInfo *info) +{ +#ifndef HAVE_GECKO_1_9 + nsCOMPtr<nsIPasswordManager> pm = + do_GetService (NS_PASSWORDMANAGER_CONTRACTID); + if (!pm) return; + + nsCOMPtr<nsIIDNService> idnService + (do_GetService ("@mozilla.org/network/idn-service;1")); + NS_ENSURE_TRUE (idnService, ); + + nsresult rv; + nsCString host; + rv = idnService->ConvertUTF8toACE (nsCString(info->host), host); + NS_ENSURE_SUCCESS (rv, ); + + nsString userName; + NS_CStringToUTF16 (nsCString(info->username), + NS_CSTRING_ENCODING_UTF8, userName); + pm->RemoveUser (host, userName); +#endif /* !HAVE_GECKO_1_9 */ +} + +static void +impl_add_password (EphyPasswordManager *manager, + EphyPasswordInfo *info) +{ +#ifndef HAVE_GECKO_1_9 + nsCOMPtr<nsIPasswordManager> pm = + do_GetService (NS_PASSWORDMANAGER_CONTRACTID); + if (!pm) return; + + nsCOMPtr<nsIIDNService> idnService + (do_GetService ("@mozilla.org/network/idn-service;1")); + NS_ENSURE_TRUE (idnService, ); + + nsresult rv; + nsCString host; + rv = idnService->ConvertUTF8toACE (nsCString(info->host), host); + NS_ENSURE_SUCCESS (rv, ); + + nsString username; + NS_CStringToUTF16 (nsCString(info->username), + NS_CSTRING_ENCODING_UTF8, username); + + nsString password; + NS_CStringToUTF16 (nsCString(info->password), + NS_CSTRING_ENCODING_UTF8, password); + + pm->AddUser(host, username, password); +#endif /* !HAVE_GECKO_1_9 */ +} + +static void +impl_permission_manager_add (EphyPermissionManager *manager, + const char *host, + const char *type, + EphyPermission permission) +{ + /* can only set allow or deny */ + g_return_if_fail (permission != EPHY_PERMISSION_DEFAULT); + g_return_if_fail (type != NULL && type[0] != '\0'); + + nsCOMPtr<nsIPermissionManager> pm + (do_GetService (NS_PERMISSIONMANAGER_CONTRACTID)); + if (!pm) return; + + nsCOMPtr<nsIURI> uri; + EphyUtils::NewURI(getter_AddRefs(uri), nsCString(host)); + if (!uri) return; + + gboolean allow = (permission == EPHY_PERMISSION_ALLOWED); + + pm->Add (uri, type, + allow ? (PRUint32) nsIPermissionManager::ALLOW_ACTION : + (PRUint32) nsIPermissionManager::DENY_ACTION); +} + +static void +impl_permission_manager_remove (EphyPermissionManager *manager, + const char *host, + const char *type) +{ + nsCOMPtr<nsIPermissionManager> pm + (do_GetService (NS_PERMISSIONMANAGER_CONTRACTID)); + if (!pm) return; + + pm->Remove (nsCString (host), type); +} + +static void +impl_permission_manager_clear (EphyPermissionManager *manager) +{ + nsCOMPtr<nsIPermissionManager> pm + (do_GetService (NS_PERMISSIONMANAGER_CONTRACTID)); + if (!pm) return; + + pm->RemoveAll (); +} + +EphyPermission +impl_permission_manager_test (EphyPermissionManager *manager, + const char *host, + const char *type) +{ + g_return_val_if_fail (type != NULL && type[0] != '\0', EPHY_PERMISSION_DEFAULT); + + nsCOMPtr<nsIPermissionManager> pm + (do_GetService (NS_PERMISSIONMANAGER_CONTRACTID)); + if (!pm) return EPHY_PERMISSION_DEFAULT; + + nsCOMPtr<nsIURI> uri; + EphyUtils::NewURI(getter_AddRefs(uri), nsCString (host)); + if (!uri) return EPHY_PERMISSION_DEFAULT; + + nsresult rv; + PRUint32 action; + rv = pm->TestPermission (uri, type, &action); + NS_ENSURE_SUCCESS (rv, EPHY_PERMISSION_DEFAULT); + + EphyPermission permission; + + switch (action) + { + case nsIPermissionManager::ALLOW_ACTION: + permission = EPHY_PERMISSION_ALLOWED; + break; + case nsIPermissionManager::DENY_ACTION: + permission = EPHY_PERMISSION_DENIED; + break; + case nsIPermissionManager::UNKNOWN_ACTION: + default: + permission = EPHY_PERMISSION_DEFAULT; + break; + } + + return permission; +} + +GList * +impl_permission_manager_list (EphyPermissionManager *manager, + const char *type) +{ + GList *list = NULL; + + nsCOMPtr<nsIPermissionManager> pm + (do_GetService (NS_PERMISSIONMANAGER_CONTRACTID)); + if (!pm) return NULL; + + nsCOMPtr<nsISimpleEnumerator> pe; + pm->GetEnumerator(getter_AddRefs(pe)); + NS_ENSURE_TRUE (pe, NULL); + + PRBool hasMore; + while (NS_SUCCEEDED (pe->HasMoreElements (&hasMore)) && hasMore) + { + nsCOMPtr<nsISupports> element; + pe->GetNext (getter_AddRefs (element)); + + nsCOMPtr<nsIPermission> perm (do_QueryInterface (element)); + if (!perm) continue; + + nsresult rv; + nsCString str; + rv = perm->GetType(str); + if (NS_FAILED (rv)) continue; + + if (strcmp (str.get(), type) == 0) + { + EphyPermissionInfo *info = + mozilla_permission_to_ephy_permission (perm); + + if (info != NULL) + { + list = g_list_prepend (list, info); + } + } + } + + return list; +} + +static GtkWidget * +impl_open_window (EphyEmbedSingle *single, + EphyEmbed *parent, + const char *address, + const char *name, + const char *features) +{ + nsresult rv; + AutoJSContextStack stack; + rv = stack.Init (); + if (NS_FAILED (rv)) return NULL; + + nsCOMPtr<nsIDOMWindow> domWindow; + if (parent) + { + EphyBrowser *browser; + + browser = (EphyBrowser *) _mozilla_embed_get_ephy_browser (MOZILLA_EMBED(parent)); + g_return_val_if_fail (browser != NULL, NULL); + + browser->GetDOMWindow (getter_AddRefs (domWindow)); + } + + nsCOMPtr<nsIWindowWatcher> wWatch(do_GetService ("@mozilla.org/embedcomp/window-watcher;1")); + nsCOMPtr<nsIDOMWindow> newWindow; + wWatch->OpenWindow (domWindow, address, name, features, nsnull, + getter_AddRefs (newWindow)); + + return EphyUtils::FindEmbed (newWindow); +} + +#ifdef ENABLE_CERTIFICATE_MANAGER + +static gboolean +impl_remove_certificate (EphyCertificateManager *manager, + EphyX509Cert *cert) +{ + nsresult rv; + + nsCOMPtr<nsIX509CertDB> certDB; + certDB = do_GetService (NS_X509CERTDB_CONTRACTID); + if (!certDB) return FALSE; + + nsCOMPtr<nsIX509Cert> mozCert; + rv = mozilla_x509_cert_get_mozilla_cert (MOZILLA_X509_CERT (cert), + getter_AddRefs (mozCert)); + if (NS_FAILED (rv)) return FALSE; + + rv = certDB->DeleteCertificate (mozCert); + if (NS_FAILED (rv)) return FALSE; + + return TRUE; +} + +#define NICK_DELIMITER PRUnichar('\001') + +static GList * +retrieveCerts (PRUint32 type) +{ + nsresult rv; + + nsCOMPtr<nsIX509CertDB> certDB; + certDB = do_GetService (NS_X509CERTDB_CONTRACTID); + if (!certDB) return NULL; + + PRUint32 count; + PRUnichar **certNameList = NULL; + + rv = certDB->FindCertNicknames (NULL, type, &count, &certNameList); + if (NS_FAILED (rv)) return NULL; + + LOG("Certificates found: %i", count); + + GList *list = NULL; + for (PRUint32 i = 0; i < count; i++) + { + /* HACK HACK, this is EVIL, the string for each cert is: + <DELIMITER>nicknameOrEmailAddress<DELIMITER>dbKey + So we need to chop off the dbKey to look it up in the database. + + https://bugzilla.mozilla.org/show_bug.cgi?id=214742 + */ + nsCString full_string; + NS_UTF16ToCString (nsString(certNameList[i]), + NS_CSTRING_ENCODING_UTF8, full_string); + + const char *key = full_string.get(); + char *pos = strrchr (key, NICK_DELIMITER); + if (!pos) continue; + + nsCOMPtr<nsIX509Cert> mozilla_cert; + rv = certDB->FindCertByDBKey (pos, NULL, getter_AddRefs (mozilla_cert)); + if (NS_FAILED (rv)) continue; + + MozillaX509Cert *cert = mozilla_x509_cert_new (mozilla_cert); + list = g_list_prepend (list, cert); + } + + NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY (count, certNameList); + return list; +} + +static GList * +impl_get_certificates (EphyCertificateManager *manager, + EphyX509CertType type) +{ + int moz_type = nsIX509Cert::USER_CERT; + switch (type) + { + case PERSONAL_CERTIFICATE: + moz_type = nsIX509Cert::USER_CERT; + break; + case SERVER_CERTIFICATE: + moz_type = nsIX509Cert::SERVER_CERT; + break; + case CA_CERTIFICATE: + moz_type = nsIX509Cert::CA_CERT; + break; + } + return retrieveCerts (moz_type); +} + +static gboolean +impl_import (EphyCertificateManager *manager, + const gchar *file) +{ + nsresult rv; + nsCOMPtr<nsIX509CertDB> certDB; + certDB = do_GetService (NS_X509CERTDB_CONTRACTID); + if (!certDB) return FALSE; + + nsCOMPtr<nsILocalFile> localFile; + localFile = do_CreateInstance (NS_LOCAL_FILE_CONTRACTID); + + // TODO Is this correct ? + nsString path; + NS_CStringToUTF16 (nsCString(file), + NS_CSTRING_ENCODING_UTF8, path); + + + localFile->InitWithPath (path); + rv = certDB->ImportPKCS12File(NULL, localFile); + if (NS_FAILED (rv)) return FALSE; + + return TRUE; +} + +#endif /* ENABLE_CERTIFICATE_MANAGER */ + +static void +mozilla_embed_single_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + EphyEmbedSingle *single = EPHY_EMBED_SINGLE (object); + + switch (prop_id) + { + case PROP_NETWORK_STATUS: + g_value_set_boolean (value, ephy_embed_single_get_network_status (single)); + break; + } +} + +static void +mozilla_embed_single_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + EphyEmbedSingle *single = EPHY_EMBED_SINGLE (object); + + switch (prop_id) + { + case PROP_NETWORK_STATUS: + ephy_embed_single_set_network_status (single, g_value_get_boolean (value)); + break; + } +} +static void +mozilla_embed_single_class_init (MozillaEmbedSingleClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = (GObjectClass *) g_type_class_peek_parent (klass); + + object_class->dispose = mozilla_embed_single_dispose; + object_class->finalize = mozilla_embed_single_finalize; + object_class->get_property = mozilla_embed_single_get_property; + object_class->set_property = mozilla_embed_single_set_property; + + g_object_class_override_property (object_class, PROP_NETWORK_STATUS, "network-status"); + + g_type_class_add_private (object_class, sizeof (MozillaEmbedSinglePrivate)); +} + +static void +ephy_embed_single_iface_init (EphyEmbedSingleIface *iface) +{ + iface->init = impl_init; + iface->clear_cache = impl_clear_cache; + iface->clear_auth_cache = impl_clear_auth_cache; + iface->set_network_status = impl_set_network_status; + iface->get_network_status = impl_get_network_status; + iface->get_font_list = impl_get_font_list; + iface->open_window = impl_open_window; + iface->get_backend_name = impl_get_backend_name; +} + +static void +ephy_cookie_manager_iface_init (EphyCookieManagerIface *iface) +{ + iface->list = impl_list_cookies; + iface->remove = impl_remove_cookie; + iface->clear = impl_clear_cookies; +} + +static void +ephy_password_manager_iface_init (EphyPasswordManagerIface *iface) +{ + iface->add = impl_add_password; + iface->remove = impl_remove_password; + iface->list = impl_list_passwords; +} + +static void +ephy_permission_manager_iface_init (EphyPermissionManagerIface *iface) +{ + iface->add = impl_permission_manager_add; + iface->remove = impl_permission_manager_remove; + iface->clear = impl_permission_manager_clear; + iface->test = impl_permission_manager_test; + iface->list = impl_permission_manager_list; +} + +#ifdef ENABLE_CERTIFICATE_MANAGER + +static void +ephy_certificate_manager_iface_init (EphyCertificateManagerIface *iface) +{ + iface->get_certificates = impl_get_certificates; + iface->remove_certificate = impl_remove_certificate; + iface->import = impl_import; +} + +#endif /* ENABLE_CERTIFICATE_MANAGER */ diff --git a/embed/xulrunner/embed/mozilla-embed-single.h b/embed/xulrunner/embed/mozilla-embed-single.h new file mode 100644 index 000000000..960b6eb5b --- /dev/null +++ b/embed/xulrunner/embed/mozilla-embed-single.h @@ -0,0 +1,57 @@ +/* + * Copyright © 2000-2003 Marco Pesenti Gritti + * Copyright © 2003 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#ifndef MOZILLA_EMBED_SINGLE_H +#define MOZILLA_EMBED_SINGLE_H + +#include <glib-object.h> + +G_BEGIN_DECLS + +#define MOZILLA_TYPE_EMBED_SINGLE (mozilla_embed_single_get_type ()) +#define MOZILLA_EMBED_SINGLE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), MOZILLA_TYPE_EMBED_SINGLE, MozillaEmbedSingle)) +#define MOZILLA_EMBED_SINGLE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), MOZILLA_TYPE_EMBED_SINGLE, MozillaEmbedSingleClass)) +#define MOZILLA_IS_EMBED_SINGLE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), MOZILLA_TYPE_EMBED_SINGLE)) +#define MOZILLA_IS_EMBED_SINGLE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), MOZILLA_TYPE_EMBED_SINGLE)) +#define MOZILLA_EMBED_SINGLE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), MOZILLA_TYPE_EMBED_SINGLE, MozillaEmbedSingleClass)) + +typedef struct MozillaEmbedSingle MozillaEmbedSingle; +typedef struct MozillaEmbedSingleClass MozillaEmbedSingleClass; +typedef struct MozillaEmbedSinglePrivate MozillaEmbedSinglePrivate; + +struct MozillaEmbedSingle +{ + GObject parent; + + /*< private >*/ + MozillaEmbedSinglePrivate *priv; +}; + +struct MozillaEmbedSingleClass +{ + GObjectClass parent_class; +}; + +GType mozilla_embed_single_get_type (void); + +G_END_DECLS + +#endif diff --git a/embed/xulrunner/embed/mozilla-embed.cpp b/embed/xulrunner/embed/mozilla-embed.cpp new file mode 100644 index 000000000..854299c46 --- /dev/null +++ b/embed/xulrunner/embed/mozilla-embed.cpp @@ -0,0 +1,1273 @@ +/* + * Copyright © 2000-2004 Marco Pesenti Gritti + * Copyright © 2003, 2004 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#include "mozilla-config.h" +#include "config.h" + +#include <nsStringAPI.h> + +#include <nsIDOMKeyEvent.h> +#include <nsIDOMMouseEvent.h> +#include <nsIRequest.h> +#include <nsIURI.h> +#include <nsIWebNavigation.h> +#include <nsIWebProgressListener.h> +#include <nsMemory.h> + +#include "EphyBrowser.h" +#include "EphyUtils.h" +#include "EventContext.h" + +#include "gecko-dom-event.h" +#include "gecko-dom-event-internal.h" + +#include "ephy-command-manager.h" +#include "ephy-debug.h" +#include "ephy-embed-shell.h" +#include "ephy-embed-single.h" +#include "ephy-string.h" +#include "mozilla-embed-event.h" + +#include "mozilla-embed.h" + +static void mozilla_embed_class_init (MozillaEmbedClass *klass); +static void mozilla_embed_init (MozillaEmbed *gs); +static void mozilla_embed_destroy (GtkObject *object); +static void mozilla_embed_finalize (GObject *object); +static void ephy_embed_iface_init (EphyEmbedIface *iface); + +static void mozilla_embed_location_changed_cb (GeckoEmbed *embed, + MozillaEmbed *membed); +static void mozilla_embed_net_state_all_cb (GeckoEmbed *embed, + const char *aURI, + gint state, + guint status, + MozillaEmbed *membed); +static gboolean mozilla_embed_dom_mouse_click_cb(GeckoEmbed *embed, + GeckoDOMEvent *dom_event, + MozillaEmbed *membed); +static gboolean mozilla_embed_dom_mouse_down_cb (GeckoEmbed *embed, + GeckoDOMEvent *dom_event, + MozillaEmbed *membed); +static gboolean mozilla_embed_dom_key_press_cb (GeckoEmbed *embed, + GeckoDOMEvent *dom_event, + MozillaEmbed *membed); +static void mozilla_embed_new_window_cb (GeckoEmbed *embed, + GeckoEmbed **newEmbed, + guint chrome_mask, + MozillaEmbed *membed); +static void mozilla_embed_security_change_cb (GeckoEmbed *embed, + gpointer request, + PRUint32 state, + MozillaEmbed *membed); +static EphyEmbedSecurityLevel mozilla_embed_security_level (PRUint32 state); + +#define MOZILLA_EMBED_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), MOZILLA_TYPE_EMBED, MozillaEmbedPrivate)) + +typedef enum +{ + MOZILLA_EMBED_LOAD_STARTED, + MOZILLA_EMBED_LOAD_REDIRECTING, + MOZILLA_EMBED_LOAD_LOADING, + MOZILLA_EMBED_LOAD_STOPPED +} MozillaEmbedLoadState; + +struct MozillaEmbedPrivate +{ + EphyBrowser *browser; + MozillaEmbedLoadState load_state; +}; + +#define WINDOWWATCHER_CONTRACTID "@mozilla.org/embedcomp/window-watcher;1" + +static GObjectClass *parent_class = NULL; + +static void +impl_manager_do_command (EphyCommandManager *manager, + const char *command) +{ + MozillaEmbedPrivate *mpriv = MOZILLA_EMBED(manager)->priv; + + mpriv->browser->DoCommand (command); +} + +static gboolean +impl_manager_can_do_command (EphyCommandManager *manager, + const char *command) +{ + MozillaEmbedPrivate *mpriv = MOZILLA_EMBED(manager)->priv; + nsresult rv; + PRBool enabled; + + rv = mpriv->browser->GetCommandState (command, &enabled); + + return NS_SUCCEEDED (rv) ? enabled : FALSE; +} + +static void +ephy_command_manager_iface_init (EphyCommandManagerIface *iface) +{ + iface->do_command = impl_manager_do_command; + iface->can_do_command = impl_manager_can_do_command; +} + +GType +mozilla_embed_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) + { + 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 + }; + + const GInterfaceInfo embed_info = + { + (GInterfaceInitFunc) ephy_embed_iface_init, + NULL, + NULL + }; + + const GInterfaceInfo ephy_command_manager_info = + { + (GInterfaceInitFunc) ephy_command_manager_iface_init, + NULL, + NULL + }; + + type = g_type_register_static (GECKO_TYPE_EMBED, + "MozillaEmbed", + &our_info, + (GTypeFlags)0); + g_type_add_interface_static (type, + EPHY_TYPE_EMBED, + &embed_info); + g_type_add_interface_static (type, + EPHY_TYPE_COMMAND_MANAGER, + &ephy_command_manager_info); + } + + return type; +} + +static void +mozilla_embed_grab_focus (GtkWidget *widget) +{ + GtkWidget *child; + + child = gtk_bin_get_child (GTK_BIN (widget)); + + if (child != NULL) + { + gtk_widget_grab_focus (child); + } + else + { + g_warning ("Need to realize the embed before grabbing focus!\n"); + } +} + +static void +impl_close (EphyEmbed *embed) +{ + MozillaEmbedPrivate *mpriv = MOZILLA_EMBED (embed)->priv; + + mpriv->browser->Close (); +} + +static void +mozilla_embed_realize (GtkWidget *widget) +{ + MozillaEmbedPrivate *mpriv = MOZILLA_EMBED (widget)->priv; + + GTK_WIDGET_CLASS (parent_class)->realize (widget); + + /* Initialise our helper class */ + nsresult rv; + rv = mpriv->browser->Init (GECKO_EMBED (widget)); + if (NS_FAILED (rv)) + { + g_warning ("EphyBrowser initialization failed for %p\n", widget); + return; + } +} + +static GObject * +mozilla_embed_constructor (GType type, guint n_construct_properties, + GObjectConstructParam *construct_params) +{ + g_object_ref (embed_shell); + + /* we depend on single because of mozilla initialization */ + ephy_embed_shell_get_embed_single (embed_shell); + + return parent_class->constructor (type, n_construct_properties, + construct_params); +} + +static void +mozilla_embed_class_init (MozillaEmbedClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkObjectClass *gtk_object_class = GTK_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + parent_class = (GObjectClass *) g_type_class_peek_parent (klass); + + object_class->constructor = mozilla_embed_constructor; + object_class->finalize = mozilla_embed_finalize; + + gtk_object_class->destroy = mozilla_embed_destroy; + + widget_class->grab_focus = mozilla_embed_grab_focus; + widget_class->realize = mozilla_embed_realize; + + g_type_class_add_private (object_class, sizeof(MozillaEmbedPrivate)); +} + +static void +mozilla_embed_init (MozillaEmbed *embed) +{ + embed->priv = MOZILLA_EMBED_GET_PRIVATE (embed); + embed->priv->browser = new EphyBrowser (); + + g_signal_connect_object (embed, "location", + G_CALLBACK (mozilla_embed_location_changed_cb), + embed, (GConnectFlags) 0); + g_signal_connect_object (embed, "net_state_all", + G_CALLBACK (mozilla_embed_net_state_all_cb), + embed, (GConnectFlags) 0); + g_signal_connect_object (embed, "dom_mouse_click", + G_CALLBACK (mozilla_embed_dom_mouse_click_cb), + embed, (GConnectFlags) 0); + g_signal_connect_object (embed, "dom_mouse_down", + G_CALLBACK (mozilla_embed_dom_mouse_down_cb), + embed, (GConnectFlags) 0); + g_signal_connect_object (embed, "dom-key-press", + G_CALLBACK (mozilla_embed_dom_key_press_cb), + embed, (GConnectFlags) 0); + g_signal_connect_object (embed, "new_window", + G_CALLBACK (mozilla_embed_new_window_cb), + embed, (GConnectFlags) 0); + g_signal_connect_object (embed, "security_change", + G_CALLBACK (mozilla_embed_security_change_cb), + embed, (GConnectFlags) 0); +} + +gpointer +_mozilla_embed_get_ephy_browser (MozillaEmbed *embed) +{ + g_return_val_if_fail (embed->priv->browser != NULL, NULL); + + return embed->priv->browser; +} + +static void +mozilla_embed_destroy (GtkObject *object) +{ + MozillaEmbed *embed = MOZILLA_EMBED (object); + + if (embed->priv->browser) + { + embed->priv->browser->Destroy(); + } + + GTK_OBJECT_CLASS (parent_class)->destroy (object); +} + +static void +mozilla_embed_finalize (GObject *object) +{ + MozillaEmbed *embed = MOZILLA_EMBED (object); + + if (embed->priv->browser) + { + delete embed->priv->browser; + embed->priv->browser = nsnull; + } + + G_OBJECT_CLASS (parent_class)->finalize (object); + + g_object_unref (embed_shell); +} + +static void +impl_load_url (EphyEmbed *embed, + const char *url) +{ + gecko_embed_load_url (GECKO_EMBED (embed), url); +} + +static char * impl_get_location (EphyEmbed *embed, gboolean toplevel); + +static void +impl_load (EphyEmbed *embed, + const char *url, + EphyEmbedLoadFlags flags, + EphyEmbed *preview_embed) +{ + EphyBrowser *browser; + + browser = MOZILLA_EMBED(embed)->priv->browser; + g_return_if_fail (browser != NULL); + + nsCOMPtr<nsIURI> uri; + if (preview_embed != NULL) + { + EphyBrowser *pbrowser; + + pbrowser = MOZILLA_EMBED(preview_embed)->priv->browser; + if (pbrowser != NULL) + { + pbrowser->GetDocumentURI (getter_AddRefs (uri)); + } + } + +#ifdef HAVE_GECKO_1_8_1 + if (flags & EPHY_EMBED_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) + { + browser->LoadURI (url, nsIWebNavigation::LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP, uri); + } + else +#endif /* HAVE_GECKO_1_8_1 */ + { + browser->LoadURI (url, nsIWebNavigation::LOAD_FLAGS_NONE, uri); + } +} + +static void +impl_stop_load (EphyEmbed *embed) +{ + gecko_embed_stop_load (GECKO_EMBED(embed)); +} + +static gboolean +impl_can_go_back (EphyEmbed *embed) +{ + return gecko_embed_can_go_back (GECKO_EMBED(embed)); +} + +static gboolean +impl_can_go_forward (EphyEmbed *embed) +{ + return gecko_embed_can_go_forward (GECKO_EMBED(embed)); +} + +static gboolean +mozilla_embed_get_uri_parent (MozillaEmbed *membed, + const char *aUri, + nsCString &aParent) +{ + nsresult rv; + nsCString encoding; + rv = membed->priv->browser->GetEncoding (encoding); + if (NS_FAILED (rv)) return FALSE; + + nsCOMPtr<nsIURI> uri; + rv = EphyUtils::NewURI (getter_AddRefs(uri), nsCString(aUri), encoding.get()); + if (NS_FAILED(rv) || !uri) return FALSE; + + /* Don't support going 'up' with chrome url's, mozilla handily + * fixes them up for us, so it doesn't work properly, see + * rdf/chrome/src/nsChromeProtocolHandler.cpp::NewURI() + * (the Canonify() call) + */ + nsCString scheme; + rv = uri->GetScheme (scheme); + if (NS_FAILED(rv) || !scheme.Length()) return FALSE; + if (strcmp (scheme.get(), "chrome") == 0) return FALSE; + + nsCString path; + rv = uri->GetPath(path); + if (NS_FAILED(rv) || !path.Length()) return FALSE; + if (strcmp (path.get (), "/") == 0) return FALSE; + + const char *slash = strrchr (path.BeginReading(), '/'); + if (!slash) return FALSE; + + if (slash[1] == '\0') + { + /* ends with a slash - a directory, go to parent */ + rv = uri->Resolve (nsCString(".."), aParent); + } + else + { + /* it's a file, go to the directory */ + rv = uri->Resolve (nsCString("."), aParent); + } + + return NS_SUCCEEDED (rv); +} + +static gboolean +impl_can_go_up (EphyEmbed *embed) +{ + MozillaEmbed *membed = MOZILLA_EMBED (embed); + char *address; + gboolean result; + + address = ephy_embed_get_location (embed, TRUE); + if (address == NULL) return FALSE; + + nsCString parent; + result = mozilla_embed_get_uri_parent (membed, address, parent); + g_free (address); + + return result; +} + +static GSList * +impl_get_go_up_list (EphyEmbed *embed) +{ + MozillaEmbed *membed = MOZILLA_EMBED (embed); + GSList *l = NULL; + char *address, *s; + + address = ephy_embed_get_location (embed, TRUE); + if (address == NULL) return NULL; + + s = address; + nsCString parent; + while (mozilla_embed_get_uri_parent (membed, s, parent)) + { + s = g_strdup (parent.get()); + l = g_slist_prepend (l, s); + } + + g_free (address); + + return g_slist_reverse (l); +} + +static void +impl_go_back (EphyEmbed *embed) +{ + gecko_embed_go_back (GECKO_EMBED(embed)); +} + +static void +impl_go_forward (EphyEmbed *embed) +{ + gecko_embed_go_forward (GECKO_EMBED(embed)); +} + +static void +impl_go_up (EphyEmbed *embed) +{ + MozillaEmbed *membed = MOZILLA_EMBED (embed); + char *uri; + + uri = ephy_embed_get_location (embed, TRUE); + if (uri == NULL) return; + + gboolean rv; + nsCString parent_uri; + rv = mozilla_embed_get_uri_parent (membed, uri, parent_uri); + g_free (uri); + + g_return_if_fail (rv != FALSE); + + ephy_embed_load_url (embed, parent_uri.get ()); +} + +static char * +impl_get_title (EphyEmbed *embed) +{ + return gecko_embed_get_title (GECKO_EMBED (embed)); +} + +static char * +impl_get_link_message (EphyEmbed *embed) +{ + return gecko_embed_get_link_message (GECKO_EMBED (embed)); +} + +static char * +impl_get_js_status (EphyEmbed *embed) +{ + return gecko_embed_get_js_status (GECKO_EMBED (embed)); +} + +static char * +impl_get_location (EphyEmbed *embed, + gboolean toplevel) +{ + MozillaEmbedPrivate *mpriv = MOZILLA_EMBED(embed)->priv; + nsresult rv; + + nsCOMPtr<nsIURI> uri; + if (toplevel) + { + rv = mpriv->browser->GetDocumentURI (getter_AddRefs (uri)); + } + else + { + rv = mpriv->browser->GetTargetDocumentURI (getter_AddRefs (uri)); + } + + if (NS_FAILED (rv)) return NULL; + + nsCOMPtr<nsIURI> furi; + rv = uri->Clone (getter_AddRefs (furi)); + /* Some nsIURI impls return NS_OK even though they didn't put anything in the outparam!! */ + if (NS_FAILED (rv) || !furi) furi.swap(uri); + + /* Hide password part */ + nsCString user; + furi->GetUsername (user); + furi->SetUserPass (user); + + nsCString url; + furi->GetSpec (url); + + return url.Length() ? g_strdup (url.get()) : NULL; +} + +static void +impl_reload (EphyEmbed *embed, + gboolean force) +{ + guint32 mflags = GECKO_EMBED_FLAG_RELOADNORMAL; + + if (force) + { + mflags = GECKO_EMBED_FLAG_RELOADBYPASSPROXYANDCACHE; + } + + gecko_embed_reload (GECKO_EMBED(embed), mflags); +} + +static void +impl_set_zoom (EphyEmbed *embed, + float zoom) +{ + EphyBrowser *browser; + nsresult rv; + + g_return_if_fail (zoom > 0.0); + + browser = MOZILLA_EMBED(embed)->priv->browser; + g_return_if_fail (browser != NULL); + + rv = browser->SetZoom (zoom); + + if (NS_SUCCEEDED (rv)) + { + g_signal_emit_by_name (embed, "ge_zoom_change", zoom); + } +} + +static float +impl_get_zoom (EphyEmbed *embed) +{ + MozillaEmbedPrivate *mpriv = MOZILLA_EMBED(embed)->priv; + float f; + + nsresult rv; + rv = mpriv->browser->GetZoom (&f); + + if (NS_SUCCEEDED (rv)) + { + return f; + } + + return 1.0; +} + +static void +impl_scroll_lines (EphyEmbed *embed, + int num_lines) +{ + MozillaEmbedPrivate *mpriv = MOZILLA_EMBED(embed)->priv; + + mpriv->browser->ScrollLines (num_lines); +} + +static void +impl_scroll_pages (EphyEmbed *embed, + int num_pages) +{ + MozillaEmbedPrivate *mpriv = MOZILLA_EMBED(embed)->priv; + + mpriv->browser->ScrollPages (num_pages); +} + +static void +impl_scroll_pixels (EphyEmbed *embed, + int dx, + int dy) +{ + MozillaEmbedPrivate *mpriv = MOZILLA_EMBED(embed)->priv; + + mpriv->browser->ScrollPixels (dx, dy); +} + +static int +impl_shistory_n_items (EphyEmbed *embed) +{ + MozillaEmbedPrivate *mpriv = MOZILLA_EMBED(embed)->priv; + nsresult rv; + int count, index; + + rv = mpriv->browser->GetSHInfo (&count, &index); + + return NS_SUCCEEDED(rv) ? count : 0; +} + +static void +impl_shistory_get_nth (EphyEmbed *embed, + int nth, + gboolean is_relative, + char **aUrl, + char **aTitle) +{ + nsresult rv; + nsCString url; + PRUnichar *title; + MozillaEmbedPrivate *mpriv = MOZILLA_EMBED(embed)->priv; + + if (is_relative) + { + nth += ephy_embed_shistory_get_pos (embed); + } + + rv = mpriv->browser->GetSHUrlAtIndex(nth, url); + + *aUrl = (NS_SUCCEEDED (rv) && url.Length()) ? g_strdup(url.get()) : NULL; + + rv = mpriv->browser->GetSHTitleAtIndex(nth, &title); + + if (title) + { + nsCString cTitle; + NS_UTF16ToCString (nsString(title), + NS_CSTRING_ENCODING_UTF8, cTitle); + *aTitle = g_strdup (cTitle.get()); + nsMemory::Free (title); + } + else + { + *aTitle = NULL; + } +} + +static int +impl_shistory_get_pos (EphyEmbed *embed) +{ + MozillaEmbedPrivate *mpriv = MOZILLA_EMBED(embed)->priv; + nsresult rv; + int count, index; + + rv = mpriv->browser->GetSHInfo (&count, &index); + + return NS_SUCCEEDED(rv) ? index : 0; +} + +static void +impl_shistory_go_nth (EphyEmbed *embed, + int nth) +{ + MozillaEmbedPrivate *mpriv = MOZILLA_EMBED(embed)->priv; + + mpriv->browser->GoToHistoryIndex (nth); +} + +static void +impl_shistory_copy (EphyEmbed *source, + EphyEmbed *dest, + gboolean copy_back, + gboolean copy_forward, + gboolean copy_current) +{ + MozillaEmbedPrivate *spriv = MOZILLA_EMBED(source)->priv; + MozillaEmbedPrivate *dpriv = MOZILLA_EMBED(dest)->priv; + + spriv->browser->CopySHistory(dpriv->browser, copy_back, + copy_forward, copy_current); +} + +static void +impl_get_security_level (EphyEmbed *embed, + EphyEmbedSecurityLevel *level, + char **description) +{ + MozillaEmbedPrivate *mpriv = MOZILLA_EMBED (embed)->priv; + + if (level) *level = EPHY_EMBED_STATE_IS_UNKNOWN; + if (description) *description = NULL; + + nsresult rv; + PRUint32 state; + nsCString desc; + rv = mpriv->browser->GetSecurityInfo (&state, desc); + if (NS_FAILED (rv)) return; + + if (level) *level = mozilla_embed_security_level (state); + if (description) *description = g_strdup (desc.get()); +} + +static void +impl_show_page_certificate (EphyEmbed *embed) +{ + MozillaEmbedPrivate *mpriv = MOZILLA_EMBED (embed)->priv; + + mpriv->browser->ShowCertificate (); +} + +static void +impl_print (EphyEmbed *embed) +{ + MozillaEmbedPrivate *mpriv = MOZILLA_EMBED(embed)->priv; + + mpriv->browser->Print (); +} + +static void +impl_set_print_preview_mode (EphyEmbed *embed, gboolean preview_mode) +{ + MozillaEmbedPrivate *mpriv = MOZILLA_EMBED(embed)->priv; + + mpriv->browser->SetPrintPreviewMode (preview_mode); +} + +static int +impl_print_preview_n_pages (EphyEmbed *embed) +{ + MozillaEmbedPrivate *mpriv = MOZILLA_EMBED(embed)->priv; + nsresult rv; + int num; + + rv = mpriv->browser->PrintPreviewNumPages(&num); + + return NS_SUCCEEDED (rv) ? num : 0; +} + +static void +impl_print_preview_navigate (EphyEmbed *embed, + EphyEmbedPrintPreviewNavType type, + int page) +{ + MozillaEmbedPrivate *mpriv = MOZILLA_EMBED(embed)->priv; + + mpriv->browser->PrintPreviewNavigate(type, page); +} + +static void +impl_set_encoding (EphyEmbed *embed, + const char *encoding) +{ + MozillaEmbedPrivate *mpriv = MOZILLA_EMBED(embed)->priv; + nsresult rv; + nsCString currEnc; + + g_return_if_fail (encoding != NULL); + + rv = mpriv->browser->GetEncoding (currEnc); + if (NS_FAILED (rv)) return; + + if (strcmp (currEnc.get(), encoding) != 0 || + encoding[0] == '\0' && !ephy_embed_has_automatic_encoding (embed)) + { + rv = mpriv->browser->ForceEncoding (encoding); + if (NS_FAILED (rv)) return; + } + + gecko_embed_reload (GECKO_EMBED (embed), + GECKO_EMBED_FLAG_RELOADCHARSETCHANGE); +} + +static char * +impl_get_encoding (EphyEmbed *embed) +{ + MozillaEmbedPrivate *mpriv = MOZILLA_EMBED(embed)->priv; + nsresult rv; + nsCString encoding; + + rv = mpriv->browser->GetEncoding (encoding); + + if (NS_FAILED (rv) || !encoding.Length()) + { + return NULL; + } + + return g_strdup (encoding.get()); +} + +static gboolean +impl_has_automatic_encoding (EphyEmbed *embed) +{ + MozillaEmbedPrivate *mpriv = MOZILLA_EMBED(embed)->priv; + nsresult rv; + nsCString encoding; + + rv = mpriv->browser->GetForcedEncoding (encoding); + + if (NS_FAILED (rv) || !encoding.Length()) + { + return TRUE; + } + + return FALSE; +} + +static gboolean +impl_has_modified_forms (EphyEmbed *embed) +{ + MozillaEmbedPrivate *mpriv = MOZILLA_EMBED(embed)->priv; + nsresult rv; + + PRBool modified; + rv = mpriv->browser->GetHasModifiedForms (&modified); + + return NS_SUCCEEDED (rv) ? modified : FALSE; +} + +static void +mozilla_embed_location_changed_cb (GeckoEmbed *embed, + MozillaEmbed *membed) +{ + char *location; + + location = gecko_embed_get_location (embed); + g_signal_emit_by_name (membed, "ge-location", location); + g_free (location); +} + +static void +update_load_state (MozillaEmbed *membed, gint state) +{ + MozillaEmbedPrivate *priv = membed->priv; + + if (state & GECKO_EMBED_FLAG_IS_DOCUMENT && + state & (GECKO_EMBED_FLAG_START | GECKO_EMBED_FLAG_STOP)) + { + g_signal_emit_by_name (membed, "ge-document-type", + priv->browser->GetDocumentType ()); + } + + if (state & GECKO_EMBED_FLAG_RESTORING && + priv->load_state == MOZILLA_EMBED_LOAD_STARTED) + { + priv->load_state = MOZILLA_EMBED_LOAD_LOADING; + + char *address; + address = gecko_embed_get_location (GECKO_EMBED (membed)); + g_signal_emit_by_name (membed, "ge-content-change", address); + g_free (address); + } + + if (state & GECKO_EMBED_FLAG_IS_NETWORK) + { + if (state & GECKO_EMBED_FLAG_START) + { + priv->load_state = MOZILLA_EMBED_LOAD_STARTED; + } + else if (state & GECKO_EMBED_FLAG_STOP) + { + priv->load_state = MOZILLA_EMBED_LOAD_STOPPED; + } + } + else if (state & GECKO_EMBED_FLAG_START && + state & GECKO_EMBED_FLAG_IS_REQUEST) + { + if (priv->load_state == MOZILLA_EMBED_LOAD_REDIRECTING) + { + priv->load_state = MOZILLA_EMBED_LOAD_STARTED; + } + else if (priv->load_state != MOZILLA_EMBED_LOAD_LOADING) + { + priv->load_state = MOZILLA_EMBED_LOAD_LOADING; + + char *address; + address = gecko_embed_get_location (GECKO_EMBED (membed)); + g_signal_emit_by_name (membed, "ge_content_change", address); + g_free (address); + } + } + else if (state & GECKO_EMBED_FLAG_REDIRECTING && + priv->load_state == MOZILLA_EMBED_LOAD_STARTED) + { + priv->load_state = MOZILLA_EMBED_LOAD_REDIRECTING; + } +} + +static void +mozilla_embed_net_state_all_cb (GeckoEmbed *embed, const char *aURI, + gint state, guint status, + MozillaEmbed *membed) +{ + EphyEmbedNetState estate = EPHY_EMBED_STATE_UNKNOWN; + int i; + + struct + { + guint state; + EphyEmbedNetState embed_state; + } + conversion_map [] = + { + { GECKO_EMBED_FLAG_START, EPHY_EMBED_STATE_START }, + { GECKO_EMBED_FLAG_STOP, EPHY_EMBED_STATE_STOP }, + { GECKO_EMBED_FLAG_REDIRECTING, EPHY_EMBED_STATE_REDIRECTING }, + { GECKO_EMBED_FLAG_TRANSFERRING, EPHY_EMBED_STATE_TRANSFERRING }, + { GECKO_EMBED_FLAG_NEGOTIATING, EPHY_EMBED_STATE_NEGOTIATING }, + { GECKO_EMBED_FLAG_IS_REQUEST, EPHY_EMBED_STATE_IS_REQUEST }, + { GECKO_EMBED_FLAG_IS_DOCUMENT, EPHY_EMBED_STATE_IS_DOCUMENT }, + { GECKO_EMBED_FLAG_IS_NETWORK, EPHY_EMBED_STATE_IS_NETWORK }, + { GECKO_EMBED_FLAG_RESTORING, EPHY_EMBED_STATE_RESTORING }, + { 0, EPHY_EMBED_STATE_UNKNOWN } + }; + + for (i = 0; conversion_map[i].state != 0; i++) + { + if (state & conversion_map[i].state) + { + estate = (EphyEmbedNetState) (estate | conversion_map[i].embed_state); + } + } + + update_load_state (membed, state); + + g_signal_emit_by_name (membed, "ge_net_state", aURI, /* FIXME: (gulong) */ estate); +} + +static gboolean +mozilla_embed_emit_mouse_signal (MozillaEmbed *embed, + GeckoDOMEvent *dom_event, + const char *signal_name) +{ + MozillaEmbedPrivate *mpriv = embed->priv; + MozillaEmbedEvent *info; + EventContext event_context; + gint return_value = FALSE; + nsresult rv; + + if (dom_event == NULL) return FALSE; + + nsCOMPtr<nsIDOMEvent> domEvent (gecko_dom_event_get_I (dom_event)); + nsCOMPtr<nsIDOMMouseEvent> ev (do_QueryInterface (domEvent)); + NS_ENSURE_TRUE (ev, FALSE); + nsCOMPtr<nsIDOMEvent> dev = do_QueryInterface (ev); + NS_ENSURE_TRUE (dev, FALSE); + + info = mozilla_embed_event_new (static_cast<gpointer>(dev)); + + event_context.Init (mpriv->browser); + rv = event_context.GetMouseEventInfo (ev, MOZILLA_EMBED_EVENT (info)); + if (NS_FAILED (rv)) + { + g_object_unref (info); + return FALSE; + } + + nsCOMPtr<nsIDOMDocument> domDoc; + rv = event_context.GetTargetDocument (getter_AddRefs(domDoc)); + if (NS_SUCCEEDED (rv)) + { + mpriv->browser->PushTargetDocument (domDoc); + + g_signal_emit_by_name (embed, signal_name, + info, &return_value); + mpriv->browser->PopTargetDocument (); + } + + g_object_unref (info); + + return return_value; +} + +static gboolean +mozilla_embed_dom_mouse_click_cb (GeckoEmbed *embed, + GeckoDOMEvent *dom_event, + MozillaEmbed *membed) +{ + return mozilla_embed_emit_mouse_signal (membed, dom_event, + "ge_dom_mouse_click"); +} + +static gboolean +mozilla_embed_dom_mouse_down_cb (GeckoEmbed *embed, + GeckoDOMEvent *dom_event, + MozillaEmbed *membed) +{ + return mozilla_embed_emit_mouse_signal (membed, dom_event, + "ge_dom_mouse_down"); +} + +static gint +mozilla_embed_dom_key_press_cb (GeckoEmbed *embed, + GeckoDOMEvent *dom_event, + MozillaEmbed *membed) +{ + gint retval = FALSE; + + if (dom_event == NULL) return FALSE; + + nsCOMPtr<nsIDOMEvent> domEvent (gecko_dom_event_get_I (dom_event)); + nsCOMPtr<nsIDOMKeyEvent> ev (do_QueryInterface (domEvent)); + NS_ENSURE_TRUE (ev, FALSE); + + if (!EventContext::CheckKeyPress (ev)) return FALSE; + + GdkEvent *event = gtk_get_current_event (); + if (event == NULL) return FALSE; /* shouldn't happen! */ + + g_return_val_if_fail (GDK_KEY_PRESS == event->type, FALSE); + + g_signal_emit_by_name (embed, "ge-search-key-press", event, &retval); + + gdk_event_free (event); + + return retval; +} + +EphyEmbedChrome +_mozilla_embed_translate_chrome (GeckoEmbedChromeFlags flags) +{ + static const struct + { + guint mozilla_flag; + guint ephy_flag; + } + conversion_map [] = + { + { GECKO_EMBED_FLAG_MENUBARON, EPHY_EMBED_CHROME_MENUBAR }, + { GECKO_EMBED_FLAG_TOOLBARON, EPHY_EMBED_CHROME_TOOLBAR }, + { GECKO_EMBED_FLAG_STATUSBARON, EPHY_EMBED_CHROME_STATUSBAR }, + { GECKO_EMBED_FLAG_PERSONALTOOLBARON, EPHY_EMBED_CHROME_BOOKMARKSBAR }, + }; + + guint mask = 0, i; + + for (i = 0; i < G_N_ELEMENTS (conversion_map); i++) + { + if (flags & conversion_map[i].mozilla_flag) + { + mask |= conversion_map[i].ephy_flag; + } + } + + return (EphyEmbedChrome) mask; +} + +static void +mozilla_embed_new_window_cb (GeckoEmbed *embed, + GeckoEmbed **newEmbed, + guint chrome_mask, + MozillaEmbed *membed) +{ + GeckoEmbedChromeFlags chrome = (GeckoEmbedChromeFlags) chrome_mask; + EphyEmbed *new_embed = NULL; + GObject *single; + EphyEmbedChrome mask; + + if (chrome & GECKO_EMBED_FLAG_OPENASCHROME) + { + *newEmbed = _mozilla_embed_new_xul_dialog (); + return; + } + + mask = _mozilla_embed_translate_chrome (chrome); + + single = ephy_embed_shell_get_embed_single (embed_shell); + g_signal_emit_by_name (single, "new-window", embed, mask, + &new_embed); + + g_assert (new_embed != NULL); + + gecko_embed_set_chrome_mask (GECKO_EMBED (new_embed), chrome); + + g_signal_emit_by_name (membed, "ge-new-window", new_embed); + + *newEmbed = GECKO_EMBED (new_embed); +} + +static void +mozilla_embed_security_change_cb (GeckoEmbed *embed, + gpointer requestptr, + PRUint32 state, + MozillaEmbed *membed) +{ + g_signal_emit_by_name (membed, "ge_security_change", + mozilla_embed_security_level (state)); +} + +static EphyEmbedSecurityLevel +mozilla_embed_security_level (PRUint32 state) +{ + EphyEmbedSecurityLevel level; + + switch (state) + { + case nsIWebProgressListener::STATE_IS_INSECURE: + level = EPHY_EMBED_STATE_IS_INSECURE; + break; + case nsIWebProgressListener::STATE_IS_BROKEN: + level = EPHY_EMBED_STATE_IS_BROKEN; + break; + case nsIWebProgressListener::STATE_IS_SECURE| + nsIWebProgressListener::STATE_SECURE_HIGH: + level = EPHY_EMBED_STATE_IS_SECURE_HIGH; + break; + case nsIWebProgressListener::STATE_IS_SECURE| + nsIWebProgressListener::STATE_SECURE_MED: + level = EPHY_EMBED_STATE_IS_SECURE_MED; + break; + case nsIWebProgressListener::STATE_IS_SECURE| + nsIWebProgressListener::STATE_SECURE_LOW: + level = EPHY_EMBED_STATE_IS_SECURE_LOW; + break; + default: + level = EPHY_EMBED_STATE_IS_UNKNOWN; + break; + } + return level; +} + +static void +ephy_embed_iface_init (EphyEmbedIface *iface) +{ + iface->load_url = impl_load_url; + iface->load = impl_load; + iface->stop_load = impl_stop_load; + iface->can_go_back = impl_can_go_back; + iface->can_go_forward =impl_can_go_forward; + iface->can_go_up = impl_can_go_up; + iface->get_go_up_list = impl_get_go_up_list; + iface->go_back = impl_go_back; + iface->go_forward = impl_go_forward; + iface->go_up = impl_go_up; + iface->get_title = impl_get_title; + iface->get_location = impl_get_location; + iface->get_link_message = impl_get_link_message; + iface->get_js_status = impl_get_js_status; + iface->reload = impl_reload; + iface->set_zoom = impl_set_zoom; + iface->get_zoom = impl_get_zoom; + iface->scroll_lines = impl_scroll_lines; + iface->scroll_pages = impl_scroll_pages; + iface->scroll_pixels = impl_scroll_pixels; + iface->shistory_n_items = impl_shistory_n_items; + iface->shistory_get_nth = impl_shistory_get_nth; + iface->shistory_get_pos = impl_shistory_get_pos; + iface->shistory_go_nth = impl_shistory_go_nth; + iface->shistory_copy = impl_shistory_copy; + iface->get_security_level = impl_get_security_level; + iface->show_page_certificate = impl_show_page_certificate; + iface->close = impl_close; + iface->set_encoding = impl_set_encoding; + iface->get_encoding = impl_get_encoding; + iface->has_automatic_encoding = impl_has_automatic_encoding; + iface->print = impl_print; + iface->set_print_preview_mode = impl_set_print_preview_mode; + iface->print_preview_n_pages = impl_print_preview_n_pages; + iface->print_preview_navigate = impl_print_preview_navigate; + iface->has_modified_forms = impl_has_modified_forms; +} + +static void +xul_visibility_cb (GtkWidget *embed, gboolean visibility, GtkWidget *window) +{ + if (visibility) + { + gtk_widget_show (window); + } + else + { + gtk_widget_hide (window); + } +} + +static void +xul_size_to_cb (GtkWidget *embed, gint width, gint height, gpointer dummy) +{ + gtk_widget_set_size_request (embed, width, height); +} + +static void +xul_new_window_cb (GeckoEmbed *embed, + GeckoEmbed **retval, + guint chrome_mask, + gpointer dummy) +{ + g_assert (chrome_mask & GECKO_EMBED_FLAG_OPENASCHROME); + + *retval = _mozilla_embed_new_xul_dialog (); +} + +static void +xul_title_cb (GeckoEmbed *embed, + GtkWindow *window) +{ + char *title; + + title = gecko_embed_get_title (embed); + gtk_window_set_title (window, title); + g_free (title); +} + +GeckoEmbed * +_mozilla_embed_new_xul_dialog (void) +{ + GtkWidget *window, *embed; + + g_object_ref (embed_shell); + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + g_object_set_data_full (G_OBJECT (window), "EmbedShellRef", + embed_shell, + (GDestroyNotify) g_object_unref); + g_signal_connect_object (embed_shell, "prepare_close", + G_CALLBACK (gtk_widget_destroy), window, + (GConnectFlags) G_CONNECT_SWAPPED); + + embed = gecko_embed_new (); + gtk_widget_show (embed); + gtk_container_add (GTK_CONTAINER (window), embed); + + g_signal_connect_object (embed, "destroy_browser", + G_CALLBACK (gtk_widget_destroy), + window, G_CONNECT_SWAPPED); + g_signal_connect_object (embed, "visibility", + G_CALLBACK (xul_visibility_cb), + window, (GConnectFlags) 0); + g_signal_connect_object (embed, "size_to", + G_CALLBACK (xul_size_to_cb), + NULL, (GConnectFlags) 0); + g_signal_connect_object (embed, "new_window", + G_CALLBACK (xul_new_window_cb), + NULL, (GConnectFlags) 0); + g_signal_connect_object (embed, "title", + G_CALLBACK (xul_title_cb), + window, (GConnectFlags) 0); + + return GECKO_EMBED (embed); +} diff --git a/embed/xulrunner/embed/mozilla-embed.h b/embed/xulrunner/embed/mozilla-embed.h new file mode 100644 index 000000000..be03cd6c3 --- /dev/null +++ b/embed/xulrunner/embed/mozilla-embed.h @@ -0,0 +1,66 @@ +/* + * Copyright © 2000-2004 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#ifndef MOZILLA_EMBED_H +#define MOZILLA_EMBED_H + +#include <glib.h> +#include <glib-object.h> + +#include "gecko-embed.h" +#include "gecko-embed-types.h" + +#include "ephy-embed.h" + +G_BEGIN_DECLS + +#define MOZILLA_TYPE_EMBED (mozilla_embed_get_type ()) +#define MOZILLA_EMBED(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), MOZILLA_TYPE_EMBED, MozillaEmbed)) +#define MOZILLA_EMBED_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), MOZILLA_TYPE_EMBED, MozillaEmbedClass)) +#define MOZILLA_IS_EMBED(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), MOZILLA_TYPE_EMBED)) +#define MOZILLA_IS_EMBED_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), MOZILLA_TYPE_EMBED)) +#define MOZILLA_EMBED_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), MOZILLA_TYPE_EMBED, MozillaEmbedClass)) + +typedef struct MozillaEmbed MozillaEmbed; +typedef struct MozillaEmbedPrivate MozillaEmbedPrivate; + +struct MozillaEmbed +{ + GeckoEmbed parent_instance; + + /*< private >*/ + MozillaEmbedPrivate *priv; +}; + +typedef GeckoEmbedClass MozillaEmbedClass; + +GType mozilla_embed_get_type (void); + +/* The following are private to the embed implementation */ + +gpointer _mozilla_embed_get_ephy_browser (MozillaEmbed *embed); + +GeckoEmbed *_mozilla_embed_new_xul_dialog (void); + +EphyEmbedChrome _mozilla_embed_translate_chrome (GeckoEmbedChromeFlags flags); + +G_END_DECLS + +#endif diff --git a/embed/xulrunner/embed/mozilla-notifiers.cpp b/embed/xulrunner/embed/mozilla-notifiers.cpp new file mode 100644 index 000000000..9901bdbe2 --- /dev/null +++ b/embed/xulrunner/embed/mozilla-notifiers.cpp @@ -0,0 +1,1257 @@ +/* +* Copyright © 2000 Nate Case +* Copyright © 2000-2004 Marco Pesenti Gritti +* Copyright © 2003, 2004 Christian Persch +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2, OR (AT YOUR OPTION) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +* $Id$ +*/ + +#include "mozilla-config.h" +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <glib/gi18n.h> +#include <gdk/gdkx.h> +#include <gtk/gtksettings.h> + +#include <nsCOMPtr.h> +#include <nsIPrefService.h> +#include <nsIServiceManager.h> +#include <nsMemory.h> +#include <nsServiceManagerUtils.h> + +#include "eel-gconf-extensions.h" +#include "ephy-debug.h" +#include "ephy-embed-prefs.h" +#include "ephy-embed-shell.h" +#include "ephy-encodings.h" +#include "ephy-langs.h" +#include "ephy-node.h" +#include "ephy-prefs.h" + +#include "mozilla-notifiers.h" + +/* define to migrate epiphany 1.0 font preferences */ +#define MIGRATE_PIXEL_SIZE + +#define MAX_FONT_SIZE 128 + +/* Keeps the list of the notifiers we installed for mozilla prefs */ +/* to be able to remove them when exiting */ +static GList *notifiers = NULL; +static nsIPrefBranch *gPrefBranch; + +typedef struct +{ + char *gconf_key; + char *mozilla_pref; + PrefValueTransformFunc func; + gpointer user_data; + guint cnxn_id; +} PrefData; + +static void +free_pref_data (PrefData *data) +{ + g_free (data->gconf_key); + g_free (data->mozilla_pref); + + g_slice_free (PrefData, data); +} + +static gboolean +transform_accept_languages_list (GConfEntry *gcentry, + GValue *value, + gpointer user_data) +{ + GConfValue *gcvalue; + GArray *array; + GSList *languages, *l; + char **langs; + + gcvalue = gconf_entry_get_value (gcentry); + if (gcvalue == NULL || + gcvalue->type != GCONF_VALUE_LIST || + gconf_value_get_list_type (gcvalue) != GCONF_VALUE_STRING) return FALSE; + + languages = gconf_value_get_list (gcvalue); + + array = g_array_new (TRUE, FALSE, sizeof (char *)); + + for (l = languages; l != NULL; l = l->next) + { + const char *lang; + + lang = gconf_value_get_string ((GConfValue *) l->data); + + if (lang != NULL && strcmp (lang, "system") == 0) + { + ephy_langs_append_languages (array); + } + else if (lang != NULL && lang[0] != '\0') + { + char *str; + str = g_ascii_strdown (lang, -1); + g_array_append_val (array, str); + } + } + + ephy_langs_sanitise (array); + + langs = (char **) g_array_free (array, FALSE); + + g_value_init (value, G_TYPE_STRING); + g_value_take_string (value, g_strjoinv (",", langs)); + + g_strfreev (langs); + + return TRUE; +} + +static gboolean +transform_cache_size (GConfEntry *gcentry, + GValue *value, + gpointer user_data) +{ + GConfValue *gcvalue; + + gcvalue = gconf_entry_get_value (gcentry); + if (gcvalue == NULL || + gcvalue->type != GCONF_VALUE_INT) return FALSE; + + g_value_init (value, G_TYPE_INT); + g_value_set_int (value, gconf_value_get_int (gcvalue) * 1024); + + return TRUE; +} + +static gboolean +transform_cookies_accept_mode (GConfEntry *gcentry, + GValue *value, + gpointer user_data) + +{ + GConfValue *gcvalue; + const char *mode; + int mozilla_mode = 0; + + gcvalue = gconf_entry_get_value (gcentry); + if (gcvalue == NULL || + gcvalue->type != GCONF_VALUE_STRING) return FALSE; + + mode = gconf_value_get_string (gcvalue); + if (mode == NULL) return FALSE; + + if (strcmp (mode, "anywhere") == 0) + { + mozilla_mode = 0; + } + else if (strcmp (mode, "current site") == 0) + { + mozilla_mode = 1; + } + else if (strcmp (mode, "nowhere") == 0) + { + mozilla_mode = 2; + } + + g_value_init (value, G_TYPE_INT); + g_value_set_int (value, mozilla_mode); + + return TRUE; +} + +static gboolean +transform_encoding (GConfEntry *gcentry, + GValue *value, + gpointer user_data) +{ + GConfValue *gcvalue; + EphyEncodings *encodings; + EphyNode *node; + const char *code; + gboolean is_autodetector; + + gcvalue = gconf_entry_get_value (gcentry); + if (gcvalue == NULL || + gcvalue->type != GCONF_VALUE_STRING) return FALSE; + + code = gconf_value_get_string (gcvalue); + if (code == NULL) return FALSE; + + encodings = EPHY_ENCODINGS (ephy_embed_shell_get_encodings (embed_shell)); + node = ephy_encodings_get_node (encodings, code, FALSE); + if (node == NULL) return FALSE; + + is_autodetector = ephy_node_get_property_boolean (node, EPHY_NODE_ENCODING_PROP_IS_AUTODETECTOR); + if (is_autodetector != GPOINTER_TO_INT (user_data)) return FALSE; + + g_value_init (value, G_TYPE_STRING); + g_value_set_string (value, code); + + return TRUE; +} + +static gboolean +transform_image_animation_mode (GConfEntry *gcentry, + GValue *value, + gpointer user_data) + +{ + GConfValue *gcvalue; + const char *mode; + + gcvalue = gconf_entry_get_value (gcentry); + if (gcvalue == NULL || + gcvalue->type != GCONF_VALUE_STRING) return FALSE; + + mode = gconf_value_get_string (gcvalue); + if (mode == NULL) return FALSE; + + if (strcmp (mode, "disabled") == 0) + { + mode = "none"; + } + + g_value_init (value, G_TYPE_STRING); + g_value_set_string (value, mode); + + return TRUE; +} + +static gboolean +transform_proxy_ignore_list (GConfEntry *gcentry, + GValue *value, + gpointer user_data) +{ + GConfValue *gcvalue; + GArray *array; + GSList *hosts, *l; + char **strings; + + gcvalue = gconf_entry_get_value (gcentry); + if (gcvalue == NULL || + gcvalue->type != GCONF_VALUE_LIST || + gconf_value_get_list_type (gcvalue) != GCONF_VALUE_STRING) return FALSE; + + hosts = gconf_value_get_list (gcvalue); + + array = g_array_new (TRUE, FALSE, sizeof (char *)); + + for (l = hosts; l != NULL; l = l->next) + { + const char *host; + + host = gconf_value_get_string ((GConfValue *) l->data); + + if (host != NULL && host[0] != '\0') + { + g_array_append_val (array, host); + } + } + + strings = (char **) g_array_free (array, FALSE); + + g_value_init (value, G_TYPE_STRING); + g_value_take_string (value, g_strjoinv (",", strings)); + + /* the strings themselves are const */ + g_free (strings); + + return TRUE; +} + +static gboolean +transform_proxy_mode (GConfEntry *gcentry, + GValue *value, + gpointer user_data) +{ + GConfValue *gcvalue; + const char *mode; + int mozilla_mode = 0; + + gcvalue = gconf_entry_get_value (gcentry); + if (gcvalue == NULL || + gcvalue->type != GCONF_VALUE_STRING) return FALSE; + + mode = gconf_value_get_string (gcvalue); + if (mode == NULL) return FALSE; + + if (strcmp (mode, "manual") == 0) + { + mozilla_mode = 1; + } + else if (strcmp (mode, "auto") == 0) + { + mozilla_mode = 2; + } + + g_value_init (value, G_TYPE_INT); + g_value_set_int (value, mozilla_mode); + + return TRUE; +} + +static gboolean +transform_use_own_fonts (GConfEntry *gcentry, + GValue *value, + gpointer user_data) +{ + GConfValue *gcvalue; + + gcvalue = gconf_entry_get_value (gcentry); + if (gcvalue == NULL || + gcvalue->type != GCONF_VALUE_BOOL) return FALSE; + + g_value_init (value, G_TYPE_INT); + g_value_set_int (value, gconf_value_get_bool (gcvalue) ? 0 : 1); + + return TRUE; +} + +extern "C" gboolean +mozilla_notifier_transform_bool (GConfEntry *gcentry, + GValue *value, + gpointer user_data) +{ + GConfValue *gcvalue; + + gcvalue = gconf_entry_get_value (gcentry); + if (gcvalue == NULL || + gcvalue->type != GCONF_VALUE_BOOL) return FALSE; + + g_value_init (value, G_TYPE_BOOLEAN); + g_value_set_boolean (value, gconf_value_get_bool (gcvalue)); + + return TRUE; +} + +extern "C" gboolean +mozilla_notifier_transform_bool_invert (GConfEntry *gcentry, + GValue *value, + gpointer user_data) +{ + GConfValue *gcvalue; + + gcvalue = gconf_entry_get_value (gcentry); + if (gcvalue == NULL || + gcvalue->type != GCONF_VALUE_BOOL) return FALSE; + + g_value_init (value, G_TYPE_BOOLEAN); + g_value_set_boolean (value, !gconf_value_get_bool (gcvalue)); + + return TRUE; +} + +extern "C" gboolean +mozilla_notifier_transform_int (GConfEntry *gcentry, + GValue *value, + gpointer user_data) +{ + GConfValue *gcvalue; + + gcvalue = gconf_entry_get_value (gcentry); + if (gcvalue == NULL || + gcvalue->type != GCONF_VALUE_INT) return FALSE; + + g_value_init (value, G_TYPE_INT); + g_value_set_int (value, gconf_value_get_int (gcvalue)); + + return TRUE; +} + +extern "C" gboolean +mozilla_notifier_transform_string (GConfEntry *gcentry, + GValue *value, + gpointer user_data) +{ + GConfValue *gcvalue; + const char *str; + + gcvalue = gconf_entry_get_value (gcentry); + if (gcvalue == NULL || + gcvalue->type != GCONF_VALUE_STRING) return FALSE; + + str = gconf_value_get_string (gcvalue); + if (str == NULL) return FALSE; + + g_value_init (value, G_TYPE_STRING); + g_value_set_string (value, str); + + return TRUE; +} + +static const PrefData notifier_entries[] = +{ + { CONF_BROWSE_WITH_CARET, + "accessibility.browsewithcaret", + mozilla_notifier_transform_bool }, + { CONF_NETWORK_CACHE_SIZE, + "browser.cache.disk.capacity", + transform_cache_size }, + { CONF_RENDERING_USE_OWN_COLORS, + "browser.display.use_document_colors", + mozilla_notifier_transform_bool_invert }, + { CONF_RENDERING_USE_OWN_FONTS, + "browser.display.use_document_fonts", + transform_use_own_fonts }, + { CONF_SECURITY_ALLOW_POPUPS, + "dom.disable_open_during_load", + mozilla_notifier_transform_bool_invert }, + { CONF_DISPLAY_SMOOTHSCROLL, + "general.smoothScroll", + mozilla_notifier_transform_bool }, + { CONF_IMAGE_ANIMATION_MODE, + "image.animation_mode", + transform_image_animation_mode }, + { CONF_RENDERING_LANGUAGE, + "intl.accept_languages", + transform_accept_languages_list }, + { CONF_LANGUAGE_DEFAULT_ENCODING, + "intl.charset.default", + transform_encoding, + GINT_TO_POINTER (FALSE) }, + { CONF_LANGUAGE_AUTODETECT_ENCODING, + "intl.charset.detector", + transform_encoding, + GINT_TO_POINTER (TRUE) }, + { CONF_SECURITY_JAVA_ENABLED, + "security.enable_java", + mozilla_notifier_transform_bool }, + { CONF_SECURITY_JAVASCRIPT_ENABLED, + "javascript.enabled", + mozilla_notifier_transform_bool }, + { CONF_NETWORK_PROXY_AUTO_URL, + "network.proxy.autoconfig_url", + mozilla_notifier_transform_string }, + { CONF_NETWORK_HTTP_PROXY, + "network.proxy.http", + mozilla_notifier_transform_string }, + { CONF_NETWORK_HTTP_PROXY_PORT, + "network.proxy.http_port", + mozilla_notifier_transform_int }, + { CONF_NETWORK_FTP_PROXY, + "network.proxy.ftp", + mozilla_notifier_transform_string }, + { CONF_NETWORK_FTP_PROXY_PORT, + "network.proxy.ftp_port", + mozilla_notifier_transform_int }, + { CONF_NETWORK_SSL_PROXY, + "network.proxy.ssl", + mozilla_notifier_transform_string }, + { CONF_NETWORK_SSL_PROXY_PORT, + "network.proxy.ssl_port", + mozilla_notifier_transform_int }, + { CONF_NETWORK_SOCKS_PROXY, + "network.proxy.socks", + mozilla_notifier_transform_string }, + { CONF_NETWORK_SOCKS_PROXY_PORT, + "network.proxy.socks_port", + mozilla_notifier_transform_int }, + { CONF_NETWORK_PROXY_IGNORE_HOSTS, + "network.proxy.no_proxies_on", + transform_proxy_ignore_list }, + { CONF_NETWORK_PROXY_MODE, + "network.proxy.type", + transform_proxy_mode }, + { CONF_SECURITY_COOKIES_ACCEPT, + "network.cookie.cookieBehavior", + transform_cookies_accept_mode }, + { CONF_PRIVACY_REMEMBER_PASSWORDS, + "signon.rememberSignons", + mozilla_notifier_transform_bool } +}; + +gboolean +mozilla_pref_set (const char *pref, + const GValue *value) +{ + NS_ENSURE_TRUE (gPrefBranch, FALSE); + + g_return_val_if_fail (pref != NULL, FALSE); + g_return_val_if_fail (value != NULL, FALSE); + + nsresult rv; + PRInt32 prefType; + rv = gPrefBranch->GetPrefType (pref, &prefType); + if (NS_FAILED (rv)) + { + /* probably just an unset pref */ + prefType = nsIPrefBranch::PREF_INVALID; + rv = NS_OK; + } + + switch (G_VALUE_TYPE (value)) + { + case G_TYPE_INT: + { + if (prefType != nsIPrefBranch::PREF_INT && + prefType != nsIPrefBranch::PREF_INVALID) + break; + + PRInt32 old_value = 0; + PRInt32 new_value = g_value_get_int (value); + rv = gPrefBranch->GetIntPref (pref, &old_value); + if (NS_FAILED (rv) || old_value != new_value) + { + rv = gPrefBranch->SetIntPref (pref, new_value); + } + break; + } + case G_TYPE_BOOLEAN: + { + if (prefType != nsIPrefBranch::PREF_BOOL && + prefType != nsIPrefBranch::PREF_INVALID) + break; + + PRBool old_value = PR_FALSE; + PRBool new_value = g_value_get_boolean (value); + rv = gPrefBranch->GetBoolPref (pref, &old_value); + if (NS_FAILED (rv) || old_value != new_value) + { + rv = gPrefBranch->SetBoolPref (pref, new_value); + } + break; + } + case G_TYPE_STRING: + { + if (prefType != nsIPrefBranch::PREF_STRING && + prefType != nsIPrefBranch::PREF_INVALID) + break; + + const char *new_value = g_value_get_string (value); + if (new_value == NULL) + { + rv = gPrefBranch->ClearUserPref (pref); + } + else + { + char *old_value = nsnull; + + rv = gPrefBranch->GetCharPref (pref, &old_value); + if (NS_FAILED (rv) || + old_value == nsnull || + strcmp (old_value, new_value) != 0) + { + rv = gPrefBranch->SetCharPref (pref, new_value); + } + + if (old_value) + { + nsMemory::Free (old_value); + } + } + break; + } + default: + g_return_val_if_reached (FALSE); + rv = NS_ERROR_FAILURE; + break; + } + + return NS_SUCCEEDED (rv) != PR_FALSE; +} + +static void +notify_cb (GConfClient *client, + guint cnxn_id, + GConfEntry *gcentry, + PrefData *data) +{ + GValue value = { 0, }; + + g_return_if_fail (gcentry != NULL); + g_assert (data != NULL); + + if (data->func (gcentry, &value, data->user_data)) + { + mozilla_pref_set (data->mozilla_pref, &value); + g_value_unset (&value); + } + else + { + /* Reset the pref */ + NS_ENSURE_TRUE (gPrefBranch, ); + gPrefBranch->ClearUserPref (data->mozilla_pref); + } +} + +extern "C" guint +mozilla_notifier_add (const char *gconf_key, + const char *mozilla_pref, + PrefValueTransformFunc func, + gpointer user_data) +{ + GConfClient *client; + PrefData *data; + GError *error = NULL; + guint cnxn_id; + + g_return_val_if_fail (gconf_key != NULL, 0); + g_return_val_if_fail (mozilla_pref != NULL, 0); + g_return_val_if_fail (func, 0); + + client = eel_gconf_client_get_global (); + g_return_val_if_fail (client != NULL, 0); + + data = g_slice_new (PrefData); + data->gconf_key = g_strdup (gconf_key); + data->mozilla_pref = g_strdup (mozilla_pref); + data->func = func; + data->user_data = user_data; + + cnxn_id = gconf_client_notify_add (client, gconf_key, + (GConfClientNotifyFunc) notify_cb, + data, (GFreeFunc) free_pref_data, + &error); + if (eel_gconf_handle_error (&error)) + { + if (cnxn_id != EEL_GCONF_UNDEFINED_CONNECTION) + { + gconf_client_notify_remove (client, cnxn_id); + } + + return 0; + } + + data->cnxn_id = cnxn_id; + notifiers = g_list_prepend (notifiers, data); + + gconf_client_notify (client, gconf_key); + + return cnxn_id; +} + +static int +find_data (const PrefData *a, + gconstpointer idptr) +{ + return a->cnxn_id != GPOINTER_TO_UINT (idptr); +} + +extern "C" void +mozilla_notifier_remove (guint id) +{ + GList *l; + + g_return_if_fail (id != 0); + + l = g_list_find_custom (notifiers, GUINT_TO_POINTER (id), + (GCompareFunc) find_data); + g_return_if_fail (l != NULL); + + notifiers = g_list_delete_link (notifiers, l); + eel_gconf_notification_remove (id); +} + +#ifdef MIGRATE_PIXEL_SIZE + +#define INT_ROUND(a) gint((a) + 0.5f) + +/** +* This function gets the dpi in the same way that mozilla gets the dpi, +* this allows us to convert from pixels to points easily +*/ +static gint +mozilla_get_dpi () +{ + GtkSettings* settings = gtk_settings_get_default (); + gint dpi = 0; + + /* Use the gdk-xft-dpi setting if it is set */ + if (g_object_class_find_property (G_OBJECT_GET_CLASS (G_OBJECT (settings)), + "gtk-xft-dpi")) + { + g_object_get (G_OBJECT (settings), "gtk-xft-dpi", &dpi, (char *) NULL); + if (dpi) return INT_ROUND (dpi / PANGO_SCALE); + } + + /* Fall back to what xft thinks it is */ + char *val = XGetDefault (GDK_DISPLAY (), "Xft", "dpi"); + if (val) + { + char *e; + double d = strtod(val, &e); + if (e != val) return INT_ROUND (d); + } + + /* Fall back to calculating manually from the gdk screen settings */ + float screenWidthIn = float (gdk_screen_width_mm()) / 25.4f; + return INT_ROUND (gdk_screen_width() / screenWidthIn); +} + +static void +migrate_font_gconf_key (const char *pixel_key, + const char *point_key) +{ + int size; + + size = eel_gconf_get_integer (pixel_key); + + if (size > 0) + { + /* Use doubles to get more accurate arithmetic */ + double dpi = (double) mozilla_get_dpi (); + double value = (double) eel_gconf_get_integer (pixel_key); + gint point = INT_ROUND ((value * 72) / dpi); + + eel_gconf_set_integer (point_key, point); + } +} + +#endif + +static gboolean +parse_pango_font (const char *font, + char **name, + int *size) +{ + PangoFontMask mask = (PangoFontMask) (PANGO_FONT_MASK_FAMILY | PANGO_FONT_MASK_SIZE); + + PangoFontDescription *desc = pango_font_description_from_string (font); + if (desc == NULL) return FALSE; + + if ((pango_font_description_get_set_fields (desc) & mask) != mask) + { + pango_font_description_free (desc); + return FALSE; + } + + *size = PANGO_PIXELS (pango_font_description_get_size (desc)); + *name = g_strdup (pango_font_description_get_family (desc)); + + pango_font_description_free (desc); + + LOG ("Parsed pango font description '%s' -> name:%s, size:%d", + font, *name ? *name : "-", *size); + + return *name != NULL && *size > 0; +} + +typedef struct +{ + guint cnxn_id; + char **font_name_prefs; + char **font_size_prefs; + char *font_name; + int font_size; +} DesktopFontData; + +static gboolean +transform_font_name (GConfEntry *gcentry, + GValue *value, + gpointer user_data) +{ + DesktopFontData *data = (DesktopFontData *) user_data; + GConfValue *gcvalue; + const char *font_name; + + gcvalue = gconf_entry_get_value (gcentry); + if (gconf_entry_get_is_default (gcentry) || + gcvalue == NULL || + gcvalue->type != GCONF_VALUE_STRING) + { + font_name = data->font_name; + } + else + { + font_name = gconf_value_get_string (gcvalue); + if ((font_name == NULL || font_name[0] == '\0')) + { + font_name = data->font_name; + } + } + + LOG ("%s value for key '%s'", + gconf_entry_get_is_default (gcentry) ? "default" : "NON-default", + gconf_entry_get_key (gcentry)); + + if (font_name == NULL) return FALSE; + + LOG ("Inferred font name '%s' for key '%s'", + font_name, gconf_entry_get_key (gcentry)); + + g_value_init (value, G_TYPE_STRING); + g_value_set_string (value, font_name); + + return TRUE; +} + +static gboolean +transform_font_size (GConfEntry *gcentry, + GValue *value, + gpointer user_data) +{ + DesktopFontData *data = (DesktopFontData *) user_data; + GConfValue *gcvalue; + int size = 0; + + gcvalue = gconf_entry_get_value (gcentry); + if (gconf_entry_get_is_default (gcentry) || + gcvalue == NULL || + gcvalue->type != GCONF_VALUE_INT) + { + size = data->font_size; + } + else + { + size = gconf_value_get_int (gcvalue); + } + + if (size <= 0 || size > MAX_FONT_SIZE) return FALSE; + + g_value_init (value, G_TYPE_INT); + g_value_set_int (value, size); + + return TRUE; +} + +static void +notify_desktop_font_cb (GConfClient *client, + guint cnxn_id, + GConfEntry *gcentry, + DesktopFontData *data) +{ + GConfValue *gcvalue; + char *name = NULL; + int size = 0, i; + + gcvalue = gconf_entry_get_value (gcentry); + if (gcvalue != NULL && + gcvalue->type == GCONF_VALUE_STRING && + parse_pango_font (gconf_value_get_string (gcvalue), &name, &size)) + { + LOG ("Desktop font %s -> name=%s, size=%d", + gconf_entry_get_key (gcentry), name, size); + + g_free (data->font_name); + data->font_name = name; + data->font_size = size; + } + else + { + g_free (name); + + g_free (data->font_name); + data->font_name = NULL; + data->font_size = 0; + } + + for (i = 0; data->font_name_prefs[i] != NULL; ++i) + { + gconf_client_notify (client, data->font_name_prefs[i]); + } + for (i = 0; data->font_size_prefs[i] != NULL; ++i) + { + gconf_client_notify (client, data->font_size_prefs[i]); + } +} + +typedef struct +{ + guint cnxn_id; + char **prefs; + int size; +} MinimumFontSizeData; + +static gboolean +transform_minimum_font_size (GConfEntry *gcentry, + GValue *value, + gpointer user_data) +{ + MinimumFontSizeData *data = (MinimumFontSizeData *) user_data; + GConfValue *gcvalue; + int size = 0; + + gcvalue = gconf_entry_get_value (gcentry); + if (gcvalue == NULL || + gcvalue->type != GCONF_VALUE_INT) + { + size = data->size; + } + else + { + size = MAX (gconf_value_get_int (gcvalue), + data->size); + } + + if (size <= 0) return FALSE; + + g_value_init (value, G_TYPE_INT); + g_value_set_int (value, size); + + return TRUE; +} + +static void +notify_minimum_size_cb (GConfClient *client, + guint cnxn_id, + GConfEntry *entry, + MinimumFontSizeData *data) +{ + GConfValue *gcvalue; + int i; + + data->size = 0; + + gcvalue = gconf_entry_get_value (entry); + /* happens on initial notify if the key doesn't exist */ + if (gcvalue != NULL && + gcvalue->type == GCONF_VALUE_INT) + { + data->size = gconf_value_get_int (gcvalue); + data->size = MAX (data->size, 0); + } + + LOG ("Minimum font size now %d", data->size); + + for (i = 0; data->prefs[i] != NULL; ++i) + { + gconf_client_notify (client, data->prefs[i]); + } +} + +static DesktopFontData *desktop_font_data; +static MinimumFontSizeData *minimum_font_size_data; + +static void +mozilla_font_notifiers_init (void) +{ + static const char *types [] = { "variable", "monospace" }; + const EphyFontsLanguageInfo *font_languages; + guint n_font_languages, i; + + eel_gconf_monitor_add ("/desktop/gnome/interface"); + + font_languages = ephy_font_languages (); + n_font_languages = ephy_font_n_languages (); + + desktop_font_data = g_new0 (DesktopFontData, 2); + desktop_font_data[0].font_name_prefs = g_new0 (char*, n_font_languages + 1); + desktop_font_data[0].font_size_prefs = g_new0 (char*, n_font_languages + 1); + desktop_font_data[1].font_name_prefs = g_new0 (char*, n_font_languages + 1); + desktop_font_data[1].font_size_prefs = g_new0 (char*, n_font_languages + 1); + + desktop_font_data[0].cnxn_id = + eel_gconf_notification_add (CONF_DESKTOP_FONT_VARIABLE, + (GConfClientNotifyFunc) notify_desktop_font_cb, + &desktop_font_data[0]); + eel_gconf_notify (CONF_DESKTOP_FONT_VARIABLE); + + desktop_font_data[1].cnxn_id = + eel_gconf_notification_add (CONF_DESKTOP_FONT_MONOSPACE, + (GConfClientNotifyFunc) notify_desktop_font_cb, + &desktop_font_data[1]); + eel_gconf_notify (CONF_DESKTOP_FONT_MONOSPACE); + + minimum_font_size_data = g_new0 (MinimumFontSizeData, 1); + minimum_font_size_data->prefs = g_new0 (char*, n_font_languages + 1); + + minimum_font_size_data->cnxn_id = + eel_gconf_notification_add (CONF_RENDERING_FONT_MIN_SIZE, + (GConfClientNotifyFunc) notify_minimum_size_cb, + minimum_font_size_data); + eel_gconf_notify (CONF_RENDERING_FONT_MIN_SIZE); + +#ifdef MIGRATE_PIXEL_SIZE + gboolean migrate_size; + + migrate_size = (eel_gconf_get_integer (CONF_SCHEMA_VERSION) + < EPIPHANY_SCHEMA_VERSION); + if (migrate_size) + { + eel_gconf_set_integer (CONF_SCHEMA_VERSION, EPIPHANY_SCHEMA_VERSION); + } +#endif + + for (i=0; i < n_font_languages; i++) + { + const char *code = font_languages[i].code; + guint k; + char key[255], pref[255]; +#ifdef MIGRATE_PIXEL_SIZE + char old_key[255]; +#endif + + for (k = 0; k < G_N_ELEMENTS (types); k++) + { + g_snprintf (key, sizeof (key), "%s_%s_%s", + CONF_RENDERING_FONT, types[k], code); + g_snprintf (pref, sizeof (pref), "font.name.%s.%s", + types[k], code); + + desktop_font_data[k].font_name_prefs[i] = g_strdup (key); + + mozilla_notifier_add (key, pref, + transform_font_name, + &desktop_font_data[k]); + } + +#ifdef MIGRATE_PIXEL_SIZE + if (migrate_size) + { + char *type; + + type = eel_gconf_get_string (CONF_RENDERING_FONT_TYPE_OLD); + if (type && (strcmp (type, "serif") == 0 || + strcmp (type, "sans-serif") == 0)) + { + char *family; + + g_snprintf (old_key, sizeof (old_key), "%s_%s_%s", + CONF_RENDERING_FONT, type, code); + g_snprintf (key, sizeof (key), "%s_%s_%s", + CONF_RENDERING_FONT, "variable", code); + + family = eel_gconf_get_string (old_key); + if (family) + { + eel_gconf_set_string (key, family); + g_free (family); + } + } + + g_free (type); + } +#endif + + /* FIXME is it "minimum-size" or "min-size" !!? */ + g_snprintf (key, sizeof (key), "%s_%s", + CONF_RENDERING_FONT_MIN_SIZE, code); + g_snprintf (pref, sizeof (pref), "font.minimum-size.%s", code); + + minimum_font_size_data->prefs[i] = g_strdup (key); + + mozilla_notifier_add (key, pref, transform_minimum_font_size, + minimum_font_size_data); + +#ifdef MIGRATE_PIXEL_SIZE + if (migrate_size) + { + g_snprintf (old_key, sizeof (key), "%s_%s", + CONF_RENDERING_FONT_MIN_SIZE_OLD, code); + migrate_font_gconf_key (old_key, key); + } +#endif + + g_snprintf (key, sizeof (key), "%s_%s", + CONF_RENDERING_FONT_FIXED_SIZE, code); + g_snprintf (pref, sizeof (pref), "font.size.fixed.%s", code); + + desktop_font_data[1].font_size_prefs[i] = g_strdup (key); + mozilla_notifier_add (key, pref, transform_font_size, + &desktop_font_data[1]); + +#ifdef MIGRATE_PIXEL_SIZE + if (migrate_size) + { + g_snprintf (old_key, sizeof (old_key), "%s_%s", + CONF_RENDERING_FONT_FIXED_SIZE_OLD, code); + migrate_font_gconf_key (old_key, key); + } +#endif + + g_snprintf (key, sizeof (key), "%s_%s", + CONF_RENDERING_FONT_VAR_SIZE, code); + g_snprintf (pref, sizeof (pref), "font.size.variable.%s", code); + + desktop_font_data[0].font_size_prefs[i] = g_strdup (key); + mozilla_notifier_add (key, pref, transform_font_size, + &desktop_font_data[0]); + +#ifdef MIGRATE_PIXEL_SIZE + if (migrate_size) + { + g_snprintf (old_key, sizeof (old_key), "%s_%s", + CONF_RENDERING_FONT_VAR_SIZE_OLD, code); + migrate_font_gconf_key (old_key, key); + } +#endif + } +} + +static void +mozilla_font_notifiers_shutdown (void) +{ + eel_gconf_monitor_remove ("/desktop/gnome/interface"); + + eel_gconf_notification_remove (desktop_font_data[0].cnxn_id); + eel_gconf_notification_remove (desktop_font_data[1].cnxn_id); + eel_gconf_notification_remove (minimum_font_size_data->cnxn_id); + + g_free (desktop_font_data[0].font_name); + g_free (desktop_font_data[1].font_name); + + g_strfreev (desktop_font_data[0].font_name_prefs); + g_strfreev (desktop_font_data[0].font_size_prefs); + g_strfreev (desktop_font_data[1].font_name_prefs); + g_strfreev (desktop_font_data[1].font_size_prefs); + g_strfreev (minimum_font_size_data->prefs); + + g_free (desktop_font_data); + g_free (minimum_font_size_data); +} + +#if 0 +static void +notify_generic_cb (GConfClient *client, + guint cnxn_id, + GConfEntry *gcentry, + gpointer data) +{ + GConfValue *gcvalue; + const char *key, *pref; + static const gsize len = strlen ("/apps/epiphany/web/gecko_prefs/"); + GValue value = { 0, }; + + key = gconf_entry_get_key (gcentry); + if (!key || strlen (key) <= len) return; + + pref = key + len; + + gcvalue = gconf_entry_get_value (gcentry); + if (!gcvalue) return; + + switch (gcvalue->type) + { + case GCONF_VALUE_STRING: + g_value_init (&value, G_TYPE_STRING); + g_value_set_static_string (&value, gconf_value_get_string (gcvalue)); + break; + case GCONF_VALUE_INT: + g_value_init (&value, G_TYPE_INT); + g_value_set_int (&value, gconf_value_get_int (gcvalue)); + break; + case GCONF_VALUE_BOOL: + g_value_init (&value, G_TYPE_BOOLEAN); + g_value_set_boolean (&value, gconf_value_get_bool (gcvalue)); + break; + /* case GCONF_VALUE_INVALID: */ + /* case GCONF_VALUE_FLOAT: */ + /* case GCONF_VALUE_SCHEMA: */ + /* case GCONF_VALUE_LIST: */ + /* case GCONF_VALUE_PAIR: */ + default: + g_warning ("Unsupported value type for key '%s'\n", key); + return; + } + + g_assert (G_IS_VALUE (&value)); + mozilla_pref_set (pref, &value); + g_value_unset (&value); +} + +static void +mozilla_generic_notifier_init (void) +{ + GConfClient *client; + GError *error = NULL; + guint cnxn_id; + PrefData *data; + GSList *list, *l; + + client = eel_gconf_client_get_global (); + + cnxn_id = gconf_client_notify_add (client, "/apps/epiphany/web/gecko_prefs", + (GConfClientNotifyFunc) notify_generic_cb, + NULL, NULL, &error); + if (eel_gconf_handle_error (&error)) + { + if (cnxn_id != EEL_GCONF_UNDEFINED_CONNECTION) + { + gconf_client_notify_remove (client, cnxn_id); + } + + return; + } + + data = g_slice_new0 (PrefData); + data->cnxn_id = cnxn_id; + notifiers = g_list_prepend (notifiers, data); + + list = gconf_client_all_entries (client, "/apps/epiphany/web/gecko_prefs", NULL); + for (l = list; l != NULL; l = l->next) + { + GConfEntry *gcentry = (GConfEntry *) l->data; + + notify_generic_cb (client, cnxn_id, gcentry, NULL); + gconf_entry_unref (gcentry); + } + g_slist_free (list); +} +#endif + +extern "C" gboolean +mozilla_notifiers_init (void) +{ + guint i; + + eel_gconf_monitor_add ("/apps/epiphany/web"); + eel_gconf_monitor_add ("/system/proxy"); + eel_gconf_monitor_add ("/system/http_proxy"); + + /* the pref service conveniently implements the root pref branch */ + gPrefBranch = nsnull; + nsresult rv = CallGetService (NS_PREFSERVICE_CONTRACTID, &gPrefBranch); + if (NS_FAILED (rv) || !gPrefBranch) + { + g_warning ("Failed to get the pref service!\n"); + return FALSE; + } + +#if 0 + /* First init the generic notifier, so our regular prefs override prefs set there */ + mozilla_generic_notifier_init (); +#endif + + for (i = 0; i < G_N_ELEMENTS (notifier_entries); i++) + { + mozilla_notifier_add (notifier_entries[i].gconf_key, + notifier_entries[i].mozilla_pref, + notifier_entries[i].func, + notifier_entries[i].user_data); + } + + mozilla_font_notifiers_init (); + + return TRUE; +} + +static void +remove_notification (PrefData *data) +{ + eel_gconf_notification_remove (data->cnxn_id); +} + +extern "C" void +mozilla_notifiers_shutdown (void) +{ + NS_IF_RELEASE (gPrefBranch); + gPrefBranch = nsnull; + + mozilla_font_notifiers_shutdown (); + + eel_gconf_monitor_remove ("/apps/epiphany/web"); + eel_gconf_monitor_remove ("/system/proxy"); + eel_gconf_monitor_remove ("/system/http_proxy"); + + g_list_foreach (notifiers, (GFunc) remove_notification, NULL); + g_list_free (notifiers); +} diff --git a/embed/xulrunner/embed/mozilla-notifiers.h b/embed/xulrunner/embed/mozilla-notifiers.h new file mode 100644 index 000000000..d1fe6d7aa --- /dev/null +++ b/embed/xulrunner/embed/mozilla-notifiers.h @@ -0,0 +1,58 @@ +/* + * Copyright © 2000 Nate Case + * Copyright © 2000-2004 Marco Pesenti Gritti + * Copyright © 2003, 2004 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#ifndef MOZILLA_NOTIFIERS_H +#define MOZILLA_NOTIFIERS_H + +#include <glib.h> +#include <glib-object.h> +#include <gconf/gconf.h> + +G_BEGIN_DECLS + +typedef gboolean (* PrefValueTransformFunc) (GConfEntry*, GValue*, gpointer); + +gboolean mozilla_notifier_transform_bool (GConfEntry*, GValue*, gpointer); + +gboolean mozilla_notifier_transform_bool_invert (GConfEntry*, GValue*, gpointer); + +gboolean mozilla_notifier_transform_int (GConfEntry*, GValue*, gpointer); + +gboolean mozilla_notifier_transform_string (GConfEntry*, GValue*, gpointer); + +guint mozilla_notifier_add (const char *gconf_key, + const char *mozilla_pref, + PrefValueTransformFunc func, + gpointer user_data); + +void mozilla_notifier_remove (guint id); + +gboolean mozilla_pref_set (const char *pref, + const GValue *value); + +gboolean mozilla_notifiers_init (void); + +void mozilla_notifiers_shutdown (void); + +G_END_DECLS + +#endif diff --git a/embed/xulrunner/embed/mozilla-x509-cert.cpp b/embed/xulrunner/embed/mozilla-x509-cert.cpp new file mode 100644 index 000000000..8774425cd --- /dev/null +++ b/embed/xulrunner/embed/mozilla-x509-cert.cpp @@ -0,0 +1,261 @@ +/* + * Copyright © 2003 Robert Marcano + * Copyright © 2005 Crispin Flowerday + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#include "mozilla-config.h" +#include "config.h" + +#include <nsStringAPI.h> + +#include "ephy-debug.h" + +#include "mozilla-x509-cert.h" + +#define MOZILLA_X509_CERT_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), \ + MOZILLA_TYPE_X509_CERT, MozillaX509CertPrivate)) + +static void mozilla_x509_cert_class_init (MozillaX509CertClass *klass); +static void ephy_x509_cert_init (EphyX509CertIface *iface); +static void mozilla_x509_cert_init (MozillaX509Cert *cert); + +struct _MozillaX509CertPrivate +{ + nsIX509Cert * mozilla_cert; + gchar *title; +}; + +enum +{ + PROP_0, + PROP_MOZILLA_CERT +}; + +static GObjectClass *parent_class = NULL; + +GType +mozilla_x509_cert_get_type (void) +{ + static GType mozilla_x509_cert_type = 0; + + if (mozilla_x509_cert_type == 0) + { + const GTypeInfo our_info = + { + sizeof (MozillaX509CertClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) mozilla_x509_cert_class_init, + NULL, + NULL, /* class_data */ + sizeof (MozillaX509Cert), + 0, /* n_preallocs */ + (GInstanceInitFunc) mozilla_x509_cert_init + }; + + const GInterfaceInfo x509_cert_info = + { + (GInterfaceInitFunc) ephy_x509_cert_init, /* interface_init */ + NULL, /* interface_finalize */ + NULL /* interface_data */ + }; + + mozilla_x509_cert_type = g_type_register_static (G_TYPE_OBJECT, + "MozillaX509Cert", + &our_info, + (GTypeFlags)0); + g_type_add_interface_static (mozilla_x509_cert_type, + EPHY_TYPE_X509_CERT, + &x509_cert_info); + } + + return mozilla_x509_cert_type; +} + +static void +mozilla_x509_cert_set_mozilla_cert (MozillaX509Cert *cert, + nsIX509Cert *mozilla_cert) +{ + nsCOMPtr<nsIX509Cert> tmpcert = cert->priv->mozilla_cert; + + if (cert->priv->mozilla_cert) + { + NS_RELEASE (cert->priv->mozilla_cert); + } + + cert->priv->mozilla_cert = mozilla_cert; + NS_IF_ADDREF (cert->priv->mozilla_cert); +} + + +nsresult +mozilla_x509_cert_get_mozilla_cert (MozillaX509Cert *cert, nsIX509Cert**aCert) +{ + *aCert = cert->priv->mozilla_cert; + NS_IF_ADDREF (*aCert); + + return *aCert ? NS_OK : NS_ERROR_FAILURE; +} + +static const char* +impl_get_title (EphyX509Cert *cert) +{ + MozillaX509Cert *m_cert = MOZILLA_X509_CERT (cert); + + /* lazy initialization of the title private variable */ + if (m_cert->priv->title != NULL) + { + return m_cert->priv->title; + } + + /* This title logic is adapted from Mozilla source at + mozilla/security/manager/ssl/src/nsCertTree.cpp */ + nsString name; + m_cert->priv->mozilla_cert->GetCommonName (name); + if (name.Length()) + { + nsCString cname; + NS_UTF16ToCString (name, NS_CSTRING_ENCODING_UTF8, cname); + + m_cert->priv->title = g_strdup (cname.get()); + } + else + { + /* No common name, so get the nickname instead */ + nsString nick; + m_cert->priv->mozilla_cert->GetNickname (nick); + + nsCString cnick; + NS_UTF16ToCString (nick, NS_CSTRING_ENCODING_UTF8, cnick); + + const char * str = cnick.get(); + char * colon = strchr (str, ':'); + if (colon) + { + m_cert->priv->title = g_strdup (colon+1); + } + else + { + m_cert->priv->title = g_strdup (cnick.get()); + } + } + + return m_cert->priv->title; +} + +static void +impl_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + MozillaX509Cert *cert = MOZILLA_X509_CERT (object); + + switch (prop_id) + { + case PROP_MOZILLA_CERT: + mozilla_x509_cert_set_mozilla_cert(cert, + (nsIX509Cert*)g_value_get_pointer (value)); + break; + default: + break; + } +} + +static void +impl_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + MozillaX509Cert *cert = MOZILLA_X509_CERT (object); + + switch (prop_id) + { + case PROP_MOZILLA_CERT: + g_value_set_pointer (value, cert->priv->mozilla_cert); + break; + default: + break; + } +} + +static void +mozilla_x509_cert_init (MozillaX509Cert *cert) +{ + cert->priv = MOZILLA_X509_CERT_GET_PRIVATE (cert); +} + +static void +mozilla_x509_cert_finalize (GObject *object) +{ + MozillaX509Cert *cert = MOZILLA_X509_CERT (object); + + LOG ("Finalizing MozillaX509Cert %p", cert); + + if (cert->priv->mozilla_cert) + { + NS_RELEASE (cert->priv->mozilla_cert); + } + + if (cert->priv->title) + { + g_free (cert->priv->title); + } + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +ephy_x509_cert_init (EphyX509CertIface *iface) +{ + iface->get_title = impl_get_title; +} + +static void +mozilla_x509_cert_class_init (MozillaX509CertClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = (GObjectClass*)g_type_class_peek_parent (klass); + + object_class->finalize = mozilla_x509_cert_finalize; + object_class->set_property = impl_set_property; + object_class->get_property = impl_get_property; + + g_object_class_install_property (object_class, + PROP_MOZILLA_CERT, + g_param_spec_pointer ("mozilla-cert", + "Mozilla-Cert", + "Mozilla XPCOM certificate", + (GParamFlags)(G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY))); + + g_type_class_add_private (object_class, sizeof (MozillaX509CertPrivate)); +} + +MozillaX509Cert * +mozilla_x509_cert_new (nsIX509Cert *moz_cert) +{ + MozillaX509Cert *cert; + + cert = (MozillaX509Cert*)g_object_new (MOZILLA_TYPE_X509_CERT, + "mozilla-cert", moz_cert, + (char *) NULL); + return cert; +} diff --git a/embed/xulrunner/embed/mozilla-x509-cert.h b/embed/xulrunner/embed/mozilla-x509-cert.h new file mode 100644 index 000000000..9bb61d216 --- /dev/null +++ b/embed/xulrunner/embed/mozilla-x509-cert.h @@ -0,0 +1,63 @@ +/* + * Copyright © 2003 Robert Marcano + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#ifndef MOZILLA_X509_CERT_H +#define MOZILLA_X509_CERT_H + +#include "ephy-x509-cert.h" + +#include <glib-object.h> + +#include <nsCOMPtr.h> +#include <nsIX509Cert.h> + +G_BEGIN_DECLS + +#define MOZILLA_TYPE_X509_CERT (mozilla_x509_cert_get_type ()) +#define MOZILLA_X509_CERT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MOZILLA_TYPE_X509_CERT, MozillaX509Cert)) +#define MOZILLA_X509_CERT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MOZILLA_TYPE_X509_CERT, MozillaX509CertClass)) +#define MOZILLA_IS_X509_CERT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MOZILLA_TYPE_X509_CERT)) +#define MOZILLA_IS_X509_CERT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MOZILLA_TYPE_X509_CERT)) +#define MOZILLA_X509_CERT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MOZILLA_TYPE_X509_CERT, MozillaX509CertClass)) + +typedef struct _MozillaX509Cert MozillaX509Cert; +typedef struct _MozillaX509CertPrivate MozillaX509CertPrivate; +typedef struct _MozillaX509CertClass MozillaX509CertClass; + +struct _MozillaX509Cert +{ + GObject parent; + MozillaX509CertPrivate *priv; +}; + +struct _MozillaX509CertClass +{ + GObjectClass parent_class; +}; + +GType mozilla_x509_cert_get_type (void); + +MozillaX509Cert *mozilla_x509_cert_new (nsIX509Cert *aMozCert); + +nsresult mozilla_x509_cert_get_mozilla_cert (MozillaX509Cert *cert, nsIX509Cert **cert); + +G_END_DECLS + +#endif diff --git a/embed/xulrunner/src/AutoJSContextStack.cpp b/embed/xulrunner/src/AutoJSContextStack.cpp new file mode 100644 index 000000000..1e02b60fd --- /dev/null +++ b/embed/xulrunner/src/AutoJSContextStack.cpp @@ -0,0 +1,48 @@ +/* + * Copyright © 2006 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id$ + */ + +#include <mozilla-config.h> +#include "config.h" + +#include "AutoJSContextStack.h" + +#include <nsIServiceManager.h> +#include <nsServiceManagerUtils.h> + +AutoJSContextStack::~AutoJSContextStack() +{ + if (mStack) { + JSContext* cx; + mStack->Pop (&cx); + + NS_ASSERTION(cx == nsnull, "We pushed a null context but popped a non-null context!?"); + } +} + +nsresult +AutoJSContextStack::Init() +{ + nsresult rv; + mStack = do_GetService ("@mozilla.org/js/xpc/ContextStack;1", &rv); + if (NS_FAILED (rv)) + return rv; + + return mStack->Push (nsnull); +} diff --git a/embed/xulrunner/src/AutoJSContextStack.h b/embed/xulrunner/src/AutoJSContextStack.h new file mode 100644 index 000000000..5294e7d4e --- /dev/null +++ b/embed/xulrunner/src/AutoJSContextStack.h @@ -0,0 +1,41 @@ +/* + * Copyright © 2006 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id$ + */ + +#ifndef AUTO_JSCONTEXTSTACK_H +#define AUTO_JSCONTEXTSTACK_H + +struct JSContext; + +#include <nsCOMPtr.h> +#include <nsIJSContextStack.h> + +class AutoJSContextStack +{ + public: + AutoJSContextStack () { } + ~AutoJSContextStack (); + + nsresult Init (); + + private: + nsCOMPtr<nsIJSContextStack> mStack; +}; + +#endif diff --git a/embed/xulrunner/src/AutoWindowModalState.cpp b/embed/xulrunner/src/AutoWindowModalState.cpp new file mode 100644 index 000000000..ca7596b38 --- /dev/null +++ b/embed/xulrunner/src/AutoWindowModalState.cpp @@ -0,0 +1,43 @@ +/* + * Copyright © 2006 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id$ + */ + +#include <mozilla-config.h> +#include "config.h" + +#include "AutoWindowModalState.h" + +AutoWindowModalState::AutoWindowModalState (nsIDOMWindow *aWindow) +{ +#ifdef HAVE_GECKO_1_9 + mWindow = do_QueryInterface (aWindow); + if (mWindow) { + mWindow->EnterModalState (); + } +#endif +} + +AutoWindowModalState::~AutoWindowModalState() +{ +#ifdef HAVE_GECKO_1_9 + if (mWindow) { + mWindow->LeaveModalState (); + } +#endif +} diff --git a/embed/xulrunner/src/AutoWindowModalState.h b/embed/xulrunner/src/AutoWindowModalState.h new file mode 100644 index 000000000..bccefede2 --- /dev/null +++ b/embed/xulrunner/src/AutoWindowModalState.h @@ -0,0 +1,38 @@ +/* + * Copyright © 2006 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id$ + */ + +#ifndef AUTO_WINDOWMODALSTATE_H +#define AUTO_WINDOWMODALSTATE_H + +#include <nsCOMPtr.h> +#include <nsPIDOMWindow.h> + +class AutoWindowModalState +{ + public: + AutoWindowModalState (nsIDOMWindow *); + ~AutoWindowModalState (); + + private: + + nsCOMPtr<nsPIDOMWindow> mWindow; +}; + +#endif diff --git a/embed/xulrunner/src/EmbedContentListener.cpp b/embed/xulrunner/src/EmbedContentListener.cpp new file mode 100644 index 000000000..8a3280488 --- /dev/null +++ b/embed/xulrunner/src/EmbedContentListener.cpp @@ -0,0 +1,159 @@ +/* + * Copyright © Christopher Blizzard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * --------------------------------------------------------------------------- + * Derived from Mozilla.org code, which had the following attributions: + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Christopher Blizzard. Portions created by Christopher Blizzard are Copyright © Christopher Blizzard. All Rights Reserved. + * Portions created by the Initial Developer are Copyright © 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Christopher Blizzard <blizzard@mozilla.org> + * --------------------------------------------------------------------------- + * + * $Id$ + */ + +#include <mozilla-config.h> +#include "config.h" + +#include <strings.h> + +#include "nsIURI.h" +#include <nsMemory.h> + +#include "EmbedContentListener.h" +#include "GeckoBrowser.h" +#include "gecko-embed-signals.h" + +#include "nsServiceManagerUtils.h" +#include "nsIWebNavigationInfo.h" +#include "nsDocShellCID.h" + +EmbedContentListener::EmbedContentListener(void) +{ + mOwner = nsnull; +} + +EmbedContentListener::~EmbedContentListener() +{ +} + +NS_IMPL_ISUPPORTS2(EmbedContentListener, + nsIURIContentListener, + nsISupportsWeakReference) + +nsresult +EmbedContentListener::Init(GeckoBrowser *aOwner) +{ + mOwner = aOwner; + return NS_OK; +} + +NS_IMETHODIMP +EmbedContentListener::OnStartURIOpen(nsIURI *aURI, + PRBool *aAbortOpen) +{ + nsresult rv; + + nsEmbedCString specString; + rv = aURI->GetSpec(specString); + + if (NS_FAILED(rv)) + return rv; + + gboolean retval = FALSE; + g_signal_emit (mOwner->mOwningWidget, + gecko_embed_signals[OPEN_URI], 0, + specString.get(), &retval); + + *aAbortOpen = retval; + + return NS_OK; +} + +NS_IMETHODIMP +EmbedContentListener::DoContent(const char *aContentType, + PRBool aIsContentPreferred, + nsIRequest *aRequest, + nsIStreamListener **aContentHandler, + PRBool *aAbortProcess) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +EmbedContentListener::IsPreferred(const char *aContentType, + char **aDesiredContentType, + PRBool *aCanHandleContent) +{ + return CanHandleContent(aContentType, PR_TRUE, aDesiredContentType, + aCanHandleContent); +} + +NS_IMETHODIMP +EmbedContentListener::CanHandleContent(const char *aContentType, + PRBool aIsContentPreferred, + char **aDesiredContentType, + PRBool *_retval) +{ + *_retval = PR_FALSE; + *aDesiredContentType = nsnull; + + if (aContentType) { + nsCOMPtr<nsIWebNavigationInfo> webNavInfo( + do_GetService(NS_WEBNAVIGATION_INFO_CONTRACTID)); + if (webNavInfo) { + PRUint32 canHandle; + nsresult rv = + webNavInfo->IsTypeSupported(nsDependentCString(aContentType), + mOwner ? mOwner->mNavigation.get() : nsnull, + &canHandle); + NS_ENSURE_SUCCESS(rv, rv); + *_retval = (canHandle != nsIWebNavigationInfo::UNSUPPORTED); + } + } + return NS_OK; +} + +NS_IMETHODIMP +EmbedContentListener::GetLoadCookie(nsISupports **aLoadCookie) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +EmbedContentListener::SetLoadCookie(nsISupports *aLoadCookie) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +EmbedContentListener::GetParentContentListener(nsIURIContentListener **aParent) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +EmbedContentListener::SetParentContentListener(nsIURIContentListener *aParent) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} diff --git a/embed/xulrunner/src/EmbedContentListener.h b/embed/xulrunner/src/EmbedContentListener.h new file mode 100644 index 000000000..427d8263e --- /dev/null +++ b/embed/xulrunner/src/EmbedContentListener.h @@ -0,0 +1,63 @@ +/* + * Copyright © Christopher Blizzard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * --------------------------------------------------------------------------- + * Derived from Mozilla.org code, which had the following attributions: + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Christopher Blizzard. Portions created by Christopher Blizzard are Copyright © Christopher Blizzard. All Rights Reserved. + * Portions created by the Initial Developer are Copyright © 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Christopher Blizzard <blizzard@mozilla.org> + * --------------------------------------------------------------------------- + * + * $Id$ + */ + +#ifndef __EmbedContentListener_h +#define __EmbedContentListener_h + +#include <nsIURIContentListener.h> +#include <nsWeakReference.h> + +class GeckoBrowser; + +class EmbedContentListener : public nsIURIContentListener, + public nsSupportsWeakReference +{ + public: + + EmbedContentListener(); + virtual ~EmbedContentListener(); + + nsresult Init (GeckoBrowser *aOwner); + + NS_DECL_ISUPPORTS + + NS_DECL_NSIURICONTENTLISTENER + + private: + + GeckoBrowser *mOwner; + +}; + +#endif /* __EmbedContentListener_h */ diff --git a/embed/xulrunner/src/EmbedEventListener.cpp b/embed/xulrunner/src/EmbedEventListener.cpp new file mode 100644 index 000000000..e4803b8bd --- /dev/null +++ b/embed/xulrunner/src/EmbedEventListener.cpp @@ -0,0 +1,183 @@ +/* + * Copyright © Christopher Blizzard + * Copyright © 2006 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * --------------------------------------------------------------------------- + * Derived from Mozilla.org code, which had the following attributions: + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Christopher Blizzard. Portions created by Christopher Blizzard are Copyright © Christopher Blizzard. All Rights Reserved. + * Portions created by the Initial Developer are Copyright © 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Christopher Blizzard <blizzard@mozilla.org> + * --------------------------------------------------------------------------- + * + * $Id$ + */ + +#include <mozilla-config.h> +#include "config.h" + +#include <nsCOMPtr.h> +#include <nsIDOMMouseEvent.h> + +#include "nsIDOMKeyEvent.h" +#include "nsIDOMUIEvent.h" + +#include "EmbedEventListener.h" +#include "GeckoBrowser.h" + +#include "gecko-embed-signals.h" +#include "gecko-dom-event.h" +#include "gecko-dom-event-internal.h" +#include "gecko-dom-event-private.h" + +EmbedEventListener::EmbedEventListener(GeckoBrowser *aOwner) + : mOwner(aOwner) +{ +} + +EmbedEventListener::~EmbedEventListener() +{ +} + +NS_IMPL_ADDREF(EmbedEventListener) +NS_IMPL_RELEASE(EmbedEventListener) +NS_INTERFACE_MAP_BEGIN(EmbedEventListener) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMKeyListener) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIDOMEventListener, nsIDOMKeyListener) + NS_INTERFACE_MAP_ENTRY(nsIDOMKeyListener) + NS_INTERFACE_MAP_ENTRY(nsIDOMMouseListener) + NS_INTERFACE_MAP_ENTRY(nsIDOMUIListener) + NS_INTERFACE_MAP_ENTRY(nsIDOMContextMenuListener) +NS_INTERFACE_MAP_END + +inline NS_METHOD +EmbedEventListener::Emit(nsIDOMEvent *aDOMEvent, + GeckoEmbedSignals signal, + GeckoDOMEventType type) +{ + if (!aDOMEvent) + return NS_OK; + + // g_print ("Emitting signal '%s'\n", g_signal_name (gecko_embed_signals[signal])); + + /* Check if there are any handlers connected */ + if (!g_signal_has_handler_pending (mOwner->mOwningWidget, + gecko_embed_signals[signal], + 0, FALSE /* FIXME: correct? */)) { + return NS_OK; + } + + GeckoDOMEvent event; + GECKO_DOM_EVENT_STATIC_INIT (event, aDOMEvent); + + gboolean retval = FALSE; + g_signal_emit (mOwner->mOwningWidget, + gecko_embed_signals[signal], 0, + (GeckoDOMEvent*) &event, &retval); + if (retval) { + aDOMEvent->StopPropagation(); + aDOMEvent->PreventDefault(); + } + + GECKO_DOM_EVENT_STATIC_DEINIT (event); + + return NS_OK; +} + +NS_IMETHODIMP +EmbedEventListener::KeyDown(nsIDOMEvent* aDOMEvent) +{ + return Emit(aDOMEvent, DOM_KEY_DOWN, TYPE_KEY_EVENT); +} + +NS_IMETHODIMP +EmbedEventListener::KeyPress(nsIDOMEvent* aDOMEvent) +{ + return Emit(aDOMEvent, DOM_KEY_PRESS, TYPE_KEY_EVENT); +} + +NS_IMETHODIMP +EmbedEventListener::KeyUp(nsIDOMEvent* aDOMEvent) +{ + return Emit(aDOMEvent, DOM_KEY_UP, TYPE_KEY_EVENT); +} + +NS_IMETHODIMP +EmbedEventListener::MouseDown(nsIDOMEvent* aDOMEvent) +{ + return Emit(aDOMEvent, DOM_MOUSE_DOWN, TYPE_MOUSE_EVENT); +} + +NS_IMETHODIMP +EmbedEventListener::MouseUp(nsIDOMEvent* aDOMEvent) +{ + return Emit(aDOMEvent, DOM_MOUSE_UP, TYPE_MOUSE_EVENT); +} + +NS_IMETHODIMP +EmbedEventListener::MouseClick(nsIDOMEvent* aDOMEvent) +{ + return Emit(aDOMEvent, DOM_MOUSE_CLICK, TYPE_MOUSE_EVENT); +} + +NS_IMETHODIMP +EmbedEventListener::MouseDblClick(nsIDOMEvent* aDOMEvent) +{ + return Emit(aDOMEvent, DOM_MOUSE_DOUBLE_CLICK, TYPE_MOUSE_EVENT); +} + +NS_IMETHODIMP +EmbedEventListener::MouseOver(nsIDOMEvent* aDOMEvent) +{ + return Emit(aDOMEvent, DOM_MOUSE_OVER, TYPE_MOUSE_EVENT); +} + +NS_IMETHODIMP +EmbedEventListener::MouseOut(nsIDOMEvent* aDOMEvent) +{ + return Emit(aDOMEvent, DOM_MOUSE_OUT, TYPE_MOUSE_EVENT); +} + +NS_IMETHODIMP +EmbedEventListener::FocusIn(nsIDOMEvent* aDOMEvent) +{ + return Emit(aDOMEvent, DOM_FOCUS_IN, TYPE_UI_EVENT); +} + +NS_IMETHODIMP +EmbedEventListener::FocusOut(nsIDOMEvent* aDOMEvent) +{ + return Emit(aDOMEvent, DOM_FOCUS_OUT, TYPE_UI_EVENT); +} + +NS_IMETHODIMP +EmbedEventListener::Activate(nsIDOMEvent* aDOMEvent) +{ + return Emit(aDOMEvent, DOM_ACTIVATE, TYPE_UI_EVENT); +} + +NS_IMETHODIMP +EmbedEventListener::ContextMenu(nsIDOMEvent* aDOMEvent) +{ + return Emit(aDOMEvent, DOM_CONTEXT_MENU, TYPE_MOUSE_EVENT); +} diff --git a/embed/xulrunner/src/EmbedEventListener.h b/embed/xulrunner/src/EmbedEventListener.h new file mode 100644 index 000000000..e1ea99d31 --- /dev/null +++ b/embed/xulrunner/src/EmbedEventListener.h @@ -0,0 +1,102 @@ +/* + * Copyright © Christopher Blizzard + * Copyright © 2006 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * --------------------------------------------------------------------------- + * Derived from Mozilla.org code, which had the following attributions: + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Christopher Blizzard. Portions created by Christopher Blizzard are Copyright © Christopher Blizzard. All Rights Reserved. + * Portions created by the Initial Developer are Copyright © 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Christopher Blizzard <blizzard@mozilla.org> + * --------------------------------------------------------------------------- + * + * $Id$ + */ + +#ifndef __EmbedEventListener_h +#define __EmbedEventListener_h + +#include <nsIDOMKeyListener.h> +#include <nsIDOMMouseListener.h> +#include <nsIDOMUIListener.h> +#include <nsIDOMContextMenuListener.h> + +#include <gecko-embed-signals.h> + +class GeckoBrowser; + +class EmbedEventListener : public nsIDOMKeyListener, + public nsIDOMMouseListener, + public nsIDOMUIListener, + public nsIDOMContextMenuListener +{ + public: + + EmbedEventListener(GeckoBrowser *aOwner); + virtual ~EmbedEventListener(); + + NS_DECL_ISUPPORTS + + // nsIDOMEventListener + + NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent) { return NS_OK; } + + // nsIDOMKeyListener + + NS_IMETHOD KeyDown(nsIDOMEvent* aDOMEvent); + NS_IMETHOD KeyUp(nsIDOMEvent* aDOMEvent); + NS_IMETHOD KeyPress(nsIDOMEvent* aDOMEvent); + + // nsIDOMMouseListener + + NS_IMETHOD MouseDown(nsIDOMEvent* aDOMEvent); + NS_IMETHOD MouseUp(nsIDOMEvent* aDOMEvent); + NS_IMETHOD MouseClick(nsIDOMEvent* aDOMEvent); + NS_IMETHOD MouseDblClick(nsIDOMEvent* aDOMEvent); + NS_IMETHOD MouseOver(nsIDOMEvent* aDOMEvent); + NS_IMETHOD MouseOut(nsIDOMEvent* aDOMEvent); + + // nsIDOMUIListener + + NS_IMETHOD Activate(nsIDOMEvent* aDOMEvent); + NS_IMETHOD FocusIn(nsIDOMEvent* aDOMEvent); + NS_IMETHOD FocusOut(nsIDOMEvent* aDOMEvent); + + // nsIDOMContextMenuListener + NS_IMETHOD ContextMenu(nsIDOMEvent *aDOMEvent); + + private: + GeckoBrowser *mOwner; + + enum GeckoDOMEventType { + TYPE_KEY_EVENT, + TYPE_MOUSE_EVENT, + TYPE_UI_EVENT + }; + + NS_METHOD Emit(nsIDOMEvent *aDOMEvent, + GeckoEmbedSignals signal, + GeckoDOMEventType); +}; + +#endif /* __EmbedEventListener_h */ diff --git a/embed/xulrunner/src/EmbedProgress.cpp b/embed/xulrunner/src/EmbedProgress.cpp new file mode 100644 index 000000000..d31e9f850 --- /dev/null +++ b/embed/xulrunner/src/EmbedProgress.cpp @@ -0,0 +1,224 @@ +/* + * Copyright © Christopher Blizzard + * Copyright © 2006 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * --------------------------------------------------------------------------- + * Derived from Mozilla.org code, which had the following attributions: + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Christopher Blizzard. Portions created by Christopher Blizzard are Copyright © Christopher Blizzard. All Rights Reserved. + * Portions created by the Initial Developer are Copyright © 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Christopher Blizzard <blizzard@mozilla.org> + * --------------------------------------------------------------------------- + * + * $Id$ + */ + +#include <mozilla-config.h> +#include "config.h" + +#include "EmbedProgress.h" + +#include <nsIChannel.h> +#include <nsIWebProgress.h> +#include <nsIDOMWindow.h> + +#include "nsIURI.h" +#include "nsMemory.h" + +#include "gecko-embed-types.h" + +#include "gecko-embed-signals.h" + +EmbedProgress::EmbedProgress() +: mOwner(nsnull) +{ +} + +EmbedProgress::~EmbedProgress() +{ +} + +/* FIXME implement nsIWebProgressListener2 */ +NS_IMPL_ISUPPORTS2(EmbedProgress, + nsIWebProgressListener, + nsISupportsWeakReference) + +nsresult +EmbedProgress::Init(GeckoBrowser *aOwner) +{ + mOwner = aOwner; + return NS_OK; +} + +NS_IMETHODIMP +EmbedProgress::OnStateChange(nsIWebProgress *aWebProgress, + nsIRequest *aRequest, + PRUint32 aStateFlags, + nsresult aStatus) +{ + // give the widget a chance to attach any listeners + mOwner->ContentStateChange(); + // if we've got the start flag, emit the signal + if ((aStateFlags & GECKO_EMBED_FLAG_IS_NETWORK) && + (aStateFlags & GECKO_EMBED_FLAG_START)) + { + g_signal_emit (mOwner->mOwningWidget, gecko_embed_signals[NET_START], 0); + } + + nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest); + if (!channel) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIURI> requestURI; + channel->GetURI(getter_AddRefs(requestURI)); + if (!requestURI) return NS_ERROR_FAILURE; + + if (IsCurrentURI(requestURI)) + { + // for people who know what they are doing + g_signal_emit (mOwner->mOwningWidget, + gecko_embed_signals[NET_STATE], 0, + aStateFlags, aStatus); + } + + nsEmbedCString uriString; + requestURI->GetSpec(uriString); + g_signal_emit (mOwner->mOwningWidget, gecko_embed_signals[NET_STATE_ALL], 0, + uriString.get(), (gint)aStateFlags, (gint)aStatus); + // and for stop, too + if ((aStateFlags & GECKO_EMBED_FLAG_IS_NETWORK) && + (aStateFlags & GECKO_EMBED_FLAG_STOP)) + { + g_signal_emit (mOwner->mOwningWidget, gecko_embed_signals[NET_STOP], 0); + // let our owner know that the load finished + mOwner->ContentFinishedLoading(); + } + + return NS_OK; +} + +NS_IMETHODIMP +EmbedProgress::OnProgressChange(nsIWebProgress *aWebProgress, + nsIRequest *aRequest, + PRInt32 aCurSelfProgress, + PRInt32 aMaxSelfProgress, + PRInt32 aCurTotalProgress, + PRInt32 aMaxTotalProgress) +{ + nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest); + if (!channel) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIURI> requestURI; + channel->GetURI(getter_AddRefs(requestURI)); + if (!requestURI) return NS_ERROR_FAILURE; + + // is it the same as the current uri? + if (IsCurrentURI(requestURI)) { + g_signal_emit (mOwner->mOwningWidget, + gecko_embed_signals[PROGRESS], 0, + aCurTotalProgress, aMaxTotalProgress); + } + + nsEmbedCString uriString; + requestURI->GetSpec(uriString); + g_signal_emit (mOwner->mOwningWidget, + gecko_embed_signals[PROGRESS_ALL], 0, + uriString.get(), + aCurTotalProgress, aMaxTotalProgress); + return NS_OK; +} + +NS_IMETHODIMP +EmbedProgress::OnLocationChange(nsIWebProgress *aWebProgress, + nsIRequest *aRequest, + nsIURI *aLocation) +{ + nsEmbedCString newURI; + NS_ENSURE_ARG_POINTER(aLocation); + aLocation->GetSpec(newURI); + + // Make sure that this is the primary frame change and not + // just a subframe. + PRBool isSubFrameLoad = PR_FALSE; + if (aWebProgress) { + nsCOMPtr<nsIDOMWindow> domWindow; + nsCOMPtr<nsIDOMWindow> topDomWindow; + + aWebProgress->GetDOMWindow(getter_AddRefs(domWindow)); + + // get the root dom window + if (domWindow) + domWindow->GetTop(getter_AddRefs(topDomWindow)); + + if (domWindow != topDomWindow) + isSubFrameLoad = PR_TRUE; + } + + if (!isSubFrameLoad) { + mOwner->SetURI(newURI.get()); + g_signal_emit (mOwner->mOwningWidget, gecko_embed_signals[LOCATION], 0); + } + + return NS_OK; +} + +NS_IMETHODIMP +EmbedProgress::OnStatusChange(nsIWebProgress *aWebProgress, + nsIRequest *aRequest, + nsresult aStatus, + const PRUnichar *aMessage) +{ + // need to make a copy so we can safely cast to a void * + nsEmbedString message(aMessage); + PRUnichar *tmpString = NS_StringCloneData(message); + + g_signal_emit (mOwner->mOwningWidget, + gecko_embed_signals[STATUS_CHANGE], 0, + static_cast<void *>(aRequest), + static_cast<int>(aStatus), + static_cast<void *>(tmpString)); + + nsMemory::Free(tmpString); + + return NS_OK; +} + +NS_IMETHODIMP +EmbedProgress::OnSecurityChange(nsIWebProgress *aWebProgress, + nsIRequest *aRequest, + PRUint32 aState) +{ + g_signal_emit (mOwner->mOwningWidget, + gecko_embed_signals[SECURITY_CHANGE], 0, + static_cast<void *>(aRequest), + aState); + return NS_OK; +} + +PRBool +EmbedProgress::IsCurrentURI(nsIURI *aURI) +{ + nsEmbedCString spec; + aURI->GetSpec(spec); + + return strcmp(mOwner->mURI.get(), spec.get()) == 0; +} diff --git a/embed/xulrunner/src/EmbedProgress.h b/embed/xulrunner/src/EmbedProgress.h new file mode 100644 index 000000000..ca4d2187f --- /dev/null +++ b/embed/xulrunner/src/EmbedProgress.h @@ -0,0 +1,63 @@ +/* + * Copyright © Christopher Blizzard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * --------------------------------------------------------------------------- + * Derived from Mozilla.org code, which had the following attributions: + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Christopher Blizzard. Portions created by Christopher Blizzard are Copyright © Christopher Blizzard. All Rights Reserved. + * Portions created by the Initial Developer are Copyright © 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Christopher Blizzard <blizzard@mozilla.org> + * --------------------------------------------------------------------------- + * + * $Id$ + */ + +#ifndef __EmbedProgress_h +#define __EmbedProgress_h + +#include <nsIWebProgressListener.h> +#include <nsWeakReference.h> +#include <nsIURI.h> +#include "GeckoBrowser.h" + +class EmbedProgress : public nsIWebProgressListener, + public nsSupportsWeakReference +{ + public: + EmbedProgress(); + virtual ~EmbedProgress(); + + nsresult Init(GeckoBrowser *aOwner); + + NS_DECL_ISUPPORTS + + NS_DECL_NSIWEBPROGRESSLISTENER + + private: + + GeckoBrowser *mOwner; + + PRBool IsCurrentURI(nsIURI *aURI); +}; + +#endif /* __EmbedProgress_h */ diff --git a/embed/xulrunner/src/EmbedStream.cpp b/embed/xulrunner/src/EmbedStream.cpp new file mode 100644 index 000000000..6cd08d400 --- /dev/null +++ b/embed/xulrunner/src/EmbedStream.cpp @@ -0,0 +1,311 @@ +/* + * Copyright © Christopher Blizzard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * --------------------------------------------------------------------------- + * Derived from Mozilla.org code, which had the following attributions: + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Christopher Blizzard. Portions created by Christopher Blizzard are Copyright © Christopher Blizzard. All Rights Reserved. + * Portions created by the Initial Developer are Copyright © 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Christopher Blizzard <blizzard@mozilla.org> + * --------------------------------------------------------------------------- + * + * $Id$ + */ + +#include <mozilla-config.h> +#include <config.h> + +#include <nsIPipe.h> +#include <nsIInputStream.h> +#include <nsIOutputStream.h> +#include <nsIContentViewerContainer.h> +#include <nsIDocumentLoaderFactory.h> +#include <nsNetUtil.h> +#include <prmem.h> + +#include "nsXPCOMCID.h" +#include "nsICategoryManager.h" + +#include "nsIContentViewer.h" + +#include "EmbedStream.h" +#include "EmbedPrivate.h" +#include "EmbedWindow.h" +#include "nsReadableUtils.h" + +// nsIInputStream interface + +NS_IMPL_ISUPPORTS1(EmbedStream, nsIInputStream) + +EmbedStream::EmbedStream() +{ + mOwner = nsnull; + mOffset = 0; + mDoingStream = PR_FALSE; +} + +EmbedStream::~EmbedStream() +{ +} + +void +EmbedStream::InitOwner(EmbedPrivate *aOwner) +{ + mOwner = aOwner; +} + +NS_METHOD +EmbedStream::Init(void) +{ + nsresult rv = NS_OK; + + nsCOMPtr<nsIInputStream> bufInStream; + nsCOMPtr<nsIOutputStream> bufOutStream; + + rv = NS_NewPipe(getter_AddRefs(bufInStream), + getter_AddRefs(bufOutStream)); + + if (NS_FAILED(rv)) return rv; + + mInputStream = bufInStream; + mOutputStream = bufOutStream; + return NS_OK; +} + +NS_METHOD +EmbedStream::OpenStream(const char *aBaseURI, const char *aContentType) +{ + NS_ENSURE_ARG_POINTER(aBaseURI); + NS_ENSURE_ARG_POINTER(aContentType); + + nsresult rv = NS_OK; + + // if we're already doing a stream then close the current one + if (mDoingStream) + CloseStream(); + + // set our state + mDoingStream = PR_TRUE; + + // initialize our streams + rv = Init(); + if (NS_FAILED(rv)) + return rv; + + // get the content area of our web browser + nsCOMPtr<nsIWebBrowser> browser; + mOwner->mWindow->GetWebBrowser(getter_AddRefs(browser)); + + // get the viewer container + nsCOMPtr<nsIContentViewerContainer> viewerContainer; + viewerContainer = do_GetInterface(browser); + + // create a new uri object + nsCOMPtr<nsIURI> uri; + nsCAutoString spec(aBaseURI); + rv = NS_NewURI(getter_AddRefs(uri), spec.get()); + + if (NS_FAILED(rv)) + return rv; + + // create a new load group + rv = NS_NewLoadGroup(getter_AddRefs(mLoadGroup), nsnull); + if (NS_FAILED(rv)) + return rv; + + // create a new input stream channel + rv = NS_NewInputStreamChannel(getter_AddRefs(mChannel), uri, + static_cast<nsIInputStream *>(this), + nsDependentCString(aContentType), + EmptyCString()); + if (NS_FAILED(rv)) + return rv; + + // set the channel's load group + rv = mChannel->SetLoadGroup(mLoadGroup); + if (NS_FAILED(rv)) + return rv; + + // find a document loader for this content type + + nsXPIDLCString docLoaderContractID; + nsCOMPtr<nsICategoryManager> catMan(do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv)); + if (NS_FAILED(rv)) + return rv; + rv = catMan->GetCategoryEntry("Gecko-Content-Viewers", aContentType, + getter_Copies(docLoaderContractID)); + if (NS_FAILED(rv)) + return rv; + + nsCOMPtr<nsIDocumentLoaderFactory> docLoaderFactory; + docLoaderFactory = do_GetService(docLoaderContractID.get(), &rv); + if (NS_FAILED(rv)) + return rv; + + // ok, create an instance of the content viewer for that command and + // mime type + nsCOMPtr<nsIContentViewer> contentViewer; + rv = docLoaderFactory->CreateInstance("view", mChannel, mLoadGroup, + aContentType, viewerContainer, + nsnull, + getter_AddRefs(mStreamListener), + getter_AddRefs(contentViewer)); + if (NS_FAILED(rv)) + return rv; + + // set the container viewer container for this content view + rv = contentViewer->SetContainer(viewerContainer); + if (NS_FAILED(rv)) + return rv; + + // embed this sucker + rv = viewerContainer->Embed(contentViewer, "view", nsnull); + if (NS_FAILED(rv)) + return rv; + + // start our request + nsCOMPtr<nsIRequest> request = do_QueryInterface(mChannel); + rv = mStreamListener->OnStartRequest(request, NULL); + if (NS_FAILED(rv)) + return rv; + + return NS_OK; +} + +NS_METHOD +EmbedStream::AppendToStream(const char *aData, gint32 aLen) +{ + nsresult rv; + + // append the data + rv = Append(aData, aLen); + if (NS_FAILED(rv)) + return rv; + + // notify our listeners + nsCOMPtr<nsIRequest> request = do_QueryInterface(mChannel); + rv = mStreamListener->OnDataAvailable(request, + NULL, + static_cast<nsIInputStream *>(this), + mOffset, /* offset */ + aLen); /* len */ + // move our counter + mOffset += aLen; + if (NS_FAILED(rv)) + return rv; + + return NS_OK; +} + +NS_METHOD +EmbedStream::CloseStream(void) +{ + nsresult rv = NS_OK; + + NS_ENSURE_STATE(mDoingStream); + mDoingStream = PR_FALSE; + + nsCOMPtr<nsIRequest> request = do_QueryInterface(mChannel, &rv); + if (NS_FAILED(rv)) + goto loser; + + rv = mStreamListener->OnStopRequest(request, NULL, NS_OK); + if (NS_FAILED(rv)) + return rv; + + loser: + mLoadGroup = nsnull; + mChannel = nsnull; + mStreamListener = nsnull; + mOffset = 0; + + return rv; +} + +NS_METHOD +EmbedStream::Append(const char *aData, PRUint32 aLen) +{ + nsresult rv = NS_OK; + PRUint32 bytesWritten = 0; + rv = mOutputStream->Write(aData, aLen, &bytesWritten); + if (NS_FAILED(rv)) + return rv; + + NS_ASSERTION(bytesWritten == aLen, + "underlying byffer couldn't handle the write"); + return rv; +} + +NS_IMETHODIMP +EmbedStream::Available(PRUint32 *_retval) +{ + return mInputStream->Available(_retval); +} + +NS_IMETHODIMP +EmbedStream::Read(char * aBuf, PRUint32 aCount, PRUint32 *_retval) +{ + return mInputStream->Read(aBuf, aCount, _retval); +} + +NS_IMETHODIMP EmbedStream::Close(void) +{ + return mInputStream->Close(); +} + +NS_IMETHODIMP +EmbedStream::ReadSegments(nsWriteSegmentFun aWriter, void * aClosure, + PRUint32 aCount, PRUint32 *_retval) +{ + char *readBuf = (char *)nsMemory::Alloc(aCount); + PRUint32 nBytes; + + if (!readBuf) + return NS_ERROR_OUT_OF_MEMORY; + + nsresult rv = mInputStream->Read(readBuf, aCount, &nBytes); + + *_retval = 0; + + if (NS_SUCCEEDED(rv)) { + PRUint32 writeCount = 0; + rv = aWriter(this, aClosure, readBuf, 0, nBytes, &writeCount); + + // XXX writeCount may be less than nBytes!! This is the wrong + // way to synthesize ReadSegments. + NS_ASSERTION(writeCount == nBytes, "data loss"); + + // errors returned from the writer end here! + rv = NS_OK; + } + + nsMemory::Free(readBuf); + + return rv; +} + +NS_IMETHODIMP +EmbedStream::IsNonBlocking(PRBool *aNonBlocking) +{ + return mInputStream->IsNonBlocking(aNonBlocking); +} diff --git a/embed/xulrunner/src/EmbedStream.h b/embed/xulrunner/src/EmbedStream.h new file mode 100644 index 000000000..bf734e134 --- /dev/null +++ b/embed/xulrunner/src/EmbedStream.h @@ -0,0 +1,79 @@ +/* + * Copyright © Christopher Blizzard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * --------------------------------------------------------------------------- + * Derived from Mozilla.org code, which had the following attributions: + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Christopher Blizzard. Portions created by Christopher Blizzard are Copyright © Christopher Blizzard. All Rights Reserved. + * Portions created by the Initial Developer are Copyright © 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Christopher Blizzard <blizzard@mozilla.org> + * --------------------------------------------------------------------------- + * + * $Id$ + */ + +#include <nsISupports.h> +#include <nsCOMPtr.h> +#include <nsIOutputStream.h> +#include <nsIInputStream.h> +#include <nsILoadGroup.h> +#include <nsIChannel.h> +#include <nsIStreamListener.h> + +class EmbedPrivate; + +class EmbedStream : public nsIInputStream +{ + public: + + EmbedStream(); + virtual ~EmbedStream(); + + void InitOwner (EmbedPrivate *aOwner); + NS_METHOD Init (void); + + NS_METHOD OpenStream (const char *aBaseURI, const char *aContentType); + NS_METHOD AppendToStream (const char *aData, PRInt32 aLen); + NS_METHOD CloseStream (void); + + NS_METHOD Append (const char *aData, PRUint32 aLen); + + // nsISupports + NS_DECL_ISUPPORTS + // nsIInputStream + NS_DECL_NSIINPUTSTREAM + + private: + nsCOMPtr<nsIOutputStream> mOutputStream; + nsCOMPtr<nsIInputStream> mInputStream; + + nsCOMPtr<nsILoadGroup> mLoadGroup; + nsCOMPtr<nsIChannel> mChannel; + nsCOMPtr<nsIStreamListener> mStreamListener; + + PRUint32 mOffset; + PRBool mDoingStream; + + EmbedPrivate *mOwner; + +}; diff --git a/embed/xulrunner/src/EmbedWindow.cpp b/embed/xulrunner/src/EmbedWindow.cpp new file mode 100644 index 000000000..15c098f28 --- /dev/null +++ b/embed/xulrunner/src/EmbedWindow.cpp @@ -0,0 +1,467 @@ +/* + * Copyright © Christopher Blizzard + * Copyright © 2006 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * --------------------------------------------------------------------------- + * Derived from Mozilla.org code, which had the following attributions: + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Christopher Blizzard. Portions created by Christopher Blizzard are Copyright © Christopher Blizzard. All Rights Reserved. + * Portions created by the Initial Developer are Copyright © 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Christopher Blizzard <blizzard@mozilla.org> + * --------------------------------------------------------------------------- + * + * $Id$ + */ + +#include <mozilla-config.h> +#include <config.h> + +#include <nsCWebBrowser.h> +#include <nsIComponentManager.h> +#include <nsComponentManagerUtils.h> +#include <nsIDocShellTreeItem.h> +#include "nsIWidget.h" + +#include "EmbedWindow.h" +#include "GeckoBrowser.h" + +#include "gecko-embed-signals.h" + +GtkWidget *EmbedWindow::sTipWindow = nsnull; + +EmbedWindow::EmbedWindow(void) +{ + mOwner = nsnull; + mVisibility = PR_FALSE; + mIsModal = PR_FALSE; +} + +EmbedWindow::~EmbedWindow(void) +{ + ExitModalEventLoop(PR_FALSE); +} + +nsresult +EmbedWindow::Init(GeckoBrowser *aOwner) +{ + // save our owner for later + mOwner = aOwner; + + // create our nsIWebBrowser object and set up some basic defaults. + mWebBrowser = do_CreateInstance(NS_WEBBROWSER_CONTRACTID); + if (!mWebBrowser) + return NS_ERROR_FAILURE; + + mWebBrowser->SetContainerWindow(static_cast<nsIWebBrowserChrome *>(this)); + + nsCOMPtr<nsIDocShellTreeItem> item = do_QueryInterface(mWebBrowser); + item->SetItemType(nsIDocShellTreeItem::typeContentWrapper); + + return NS_OK; +} + +nsresult +EmbedWindow::CreateWindow(void) +{ + nsresult rv; + GtkWidget *ownerAsWidget = GTK_WIDGET(mOwner->mOwningWidget); + + // Get the base window interface for the web browser object and + // create the window. + mBaseWindow = do_QueryInterface(mWebBrowser); + rv = mBaseWindow->InitWindow(GTK_WIDGET(mOwner->mOwningWidget), + nsnull, + 0, 0, + ownerAsWidget->allocation.width, + ownerAsWidget->allocation.height); + if (NS_FAILED(rv)) + return rv; + + rv = mBaseWindow->Create(); + if (NS_FAILED(rv)) + return rv; + + return NS_OK; +} + +void +EmbedWindow::ReleaseChildren(void) +{ + ExitModalEventLoop(PR_FALSE); + + mBaseWindow->Destroy(); + mBaseWindow = 0; + mWebBrowser = 0; +} + +// nsISupports + +NS_IMPL_ADDREF(EmbedWindow) +NS_IMPL_RELEASE(EmbedWindow) + +NS_INTERFACE_MAP_BEGIN(EmbedWindow) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWebBrowserChrome) + NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChrome) + NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChromeFocus) + NS_INTERFACE_MAP_ENTRY(nsIEmbeddingSiteWindow) + NS_INTERFACE_MAP_ENTRY(nsITooltipListener) + NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor) +NS_INTERFACE_MAP_END + +// nsIWebBrowserChrome + +NS_IMETHODIMP +EmbedWindow::SetStatus(PRUint32 aStatusType, const PRUnichar *aStatus) +{ + switch (aStatusType) { + case STATUS_SCRIPT: + { + mJSStatus = aStatus; + g_signal_emit (mOwner->mOwningWidget, gecko_embed_signals[JS_STATUS], 0); + } + break; + case STATUS_SCRIPT_DEFAULT: + // Gee, that's nice. + break; + case STATUS_LINK: + { + mLinkMessage = aStatus; + g_signal_emit (mOwner->mOwningWidget, gecko_embed_signals[LINK_MESSAGE], 0); + } + break; + } + return NS_OK; +} + +NS_IMETHODIMP +EmbedWindow::GetWebBrowser(nsIWebBrowser **aWebBrowser) +{ + *aWebBrowser = mWebBrowser; + NS_IF_ADDREF(*aWebBrowser); + return NS_OK; +} + +NS_IMETHODIMP +EmbedWindow::SetWebBrowser(nsIWebBrowser *aWebBrowser) +{ + mWebBrowser = aWebBrowser; + return NS_OK; +} + +NS_IMETHODIMP +EmbedWindow::GetChromeFlags(PRUint32 *aChromeFlags) +{ + *aChromeFlags = mOwner->mChromeMask; + return NS_OK; +} + +NS_IMETHODIMP +EmbedWindow::SetChromeFlags(PRUint32 aChromeFlags) +{ + mOwner->SetChromeMask(aChromeFlags); + return NS_OK; +} + +NS_IMETHODIMP +EmbedWindow::DestroyBrowserWindow(void) +{ + // mark the owner as destroyed so it won't emit events anymore. + mOwner->mIsDestroyed = PR_TRUE; + + g_signal_emit (mOwner->mOwningWidget, gecko_embed_signals[DESTROY_BROWSER], 0); + return NS_OK; +} + +NS_IMETHODIMP +EmbedWindow::SizeBrowserTo(PRInt32 aCX, PRInt32 aCY) +{ + g_signal_emit (mOwner->mOwningWidget, gecko_embed_signals[SIZE_TO], 0, aCX, aCY); + + return NS_OK; +} + +NS_IMETHODIMP +EmbedWindow::ShowAsModal(void) +{ + mIsModal = PR_TRUE; + GtkWidget *toplevel; + toplevel = gtk_widget_get_toplevel(GTK_WIDGET(mOwner->mOwningWidget)); + gtk_grab_add(toplevel); + gtk_main(); + return NS_OK; +} + +NS_IMETHODIMP +EmbedWindow::IsWindowModal(PRBool *_retval) +{ + *_retval = mIsModal; + return NS_OK; +} + +NS_IMETHODIMP +EmbedWindow::ExitModalEventLoop(nsresult aStatus) +{ + if (mIsModal) { + GtkWidget *toplevel; + toplevel = gtk_widget_get_toplevel(GTK_WIDGET(mOwner->mOwningWidget)); + gtk_grab_remove(toplevel); + mIsModal = PR_FALSE; + gtk_main_quit(); + } + return NS_OK; +} + +// nsIWebBrowserChromeFocus + +NS_IMETHODIMP +EmbedWindow::FocusNextElement() +{ + GtkWidget *toplevel; + toplevel = gtk_widget_get_toplevel(GTK_WIDGET(mOwner->mOwningWidget)); + if (!GTK_WIDGET_TOPLEVEL(toplevel)) + return NS_OK; + + g_signal_emit_by_name (toplevel, "move_focus", GTK_DIR_TAB_FORWARD); + + return NS_OK; +} + +NS_IMETHODIMP +EmbedWindow::FocusPrevElement() +{ + GtkWidget *toplevel; + toplevel = gtk_widget_get_toplevel(GTK_WIDGET(mOwner->mOwningWidget)); + if (!GTK_WIDGET_TOPLEVEL(toplevel)) + return NS_OK; + + g_signal_emit_by_name (toplevel, "move_focus", GTK_DIR_TAB_BACKWARD); + + return NS_OK; +} + +// nsIEmbeddingSiteWindow + +NS_IMETHODIMP +EmbedWindow::SetDimensions(PRUint32 aFlags, PRInt32 aX, PRInt32 aY, + PRInt32 aCX, PRInt32 aCY) +{ + if (aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION && + (aFlags & (nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_INNER | + nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER))) { + return mBaseWindow->SetPositionAndSize(aX, aY, aCX, aCY, PR_TRUE); + } + else if (aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION) { + return mBaseWindow->SetPosition(aX, aY); + } + else if (aFlags & (nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_INNER | + nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER)) { + return mBaseWindow->SetSize(aCX, aCY, PR_TRUE); + } + return NS_ERROR_INVALID_ARG; +} + +NS_IMETHODIMP +EmbedWindow::GetDimensions(PRUint32 aFlags, PRInt32 *aX, + PRInt32 *aY, PRInt32 *aCX, PRInt32 *aCY) +{ + if (aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION && + (aFlags & (nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_INNER | + nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER))) { + return mBaseWindow->GetPositionAndSize(aX, aY, aCX, aCY); + } + else if (aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION) { + return mBaseWindow->GetPosition(aX, aY); + } + else if (aFlags & (nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_INNER | + nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER)) { + return mBaseWindow->GetSize(aCX, aCY); + } + return NS_ERROR_INVALID_ARG; +} + +NS_IMETHODIMP +EmbedWindow::SetFocus(void) +{ + // XXX might have to do more here. + return mBaseWindow->SetFocus(); +} + +NS_IMETHODIMP +EmbedWindow::GetTitle(PRUnichar **aTitle) +{ + *aTitle = NS_StringCloneData(mTitle); + return NS_OK; +} + +NS_IMETHODIMP +EmbedWindow::SetTitle(const PRUnichar *aTitle) +{ + mTitle = aTitle; + g_signal_emit (mOwner->mOwningWidget, gecko_embed_signals[TITLE], 0); + + return NS_OK; +} + +NS_IMETHODIMP +EmbedWindow::GetSiteWindow(void **aSiteWindow) +{ + GtkWidget *ownerAsWidget (GTK_WIDGET(mOwner->mOwningWidget)); + *aSiteWindow = static_cast<void *>(ownerAsWidget); + return NS_OK; +} + +NS_IMETHODIMP +EmbedWindow::GetVisibility(PRBool *aVisibility) +{ + // Work around the problem that sometimes the window + // is already visible even though mVisibility isn't true + // yet. + *aVisibility = mVisibility || + (!mOwner->mIsChrome && + mOwner->mOwningWidget && + GTK_WIDGET_MAPPED(mOwner->mOwningWidget)); + return NS_OK; +} + +NS_IMETHODIMP +EmbedWindow::SetVisibility(PRBool aVisibility) +{ + // We always set the visibility so that if it's chrome and we finish + // the load we know that we have to show the window. + mVisibility = aVisibility; + + // if this is a chrome window and the chrome hasn't finished loading + // yet then don't show the window yet. + if (mOwner->mIsChrome && !mOwner->mChromeLoaded) + return NS_OK; + + g_signal_emit (mOwner->mOwningWidget, gecko_embed_signals[VISIBILITY], 0, + aVisibility); + return NS_OK; +} + +// nsITooltipListener + +static gboolean +tooltips_paint_window (GtkWidget *window) +{ + // draw tooltip style border around the text + gtk_paint_flat_box (window->style, window->window, + GTK_STATE_NORMAL, GTK_SHADOW_OUT, + NULL, window, "tooltip", + 0, 0, + window->allocation.width, window->allocation.height); + + return FALSE; +} + +NS_IMETHODIMP +EmbedWindow::OnShowTooltip(PRInt32 aXCoords, PRInt32 aYCoords, + const PRUnichar *aTipText) +{ + nsEmbedCString tipText; + + NS_UTF16ToCString(nsEmbedString(aTipText), + NS_CSTRING_ENCODING_UTF8, tipText); + + if (sTipWindow) + gtk_widget_destroy(sTipWindow); + + // get the root origin for this content window + nsCOMPtr<nsIWidget> mainWidget; + mBaseWindow->GetMainWidget(getter_AddRefs(mainWidget)); + GdkWindow *window; + window = static_cast<GdkWindow *> + (mainWidget->GetNativeData(NS_NATIVE_WINDOW)); + gint root_x, root_y; + gdk_window_get_origin(window, &root_x, &root_y); + + // XXX work around until I can get pink to figure out why + // tooltips vanish if they show up right at the origin of the + // cursor. + root_y += 10; + + sTipWindow = gtk_window_new(GTK_WINDOW_POPUP); + gtk_widget_set_app_paintable(sTipWindow, TRUE); + gtk_window_set_policy(GTK_WINDOW(sTipWindow), FALSE, FALSE, TRUE); + // needed to get colors + fonts etc correctly + gtk_widget_set_name(sTipWindow, "gtk-tooltips"); + + // set up the popup window as a transient of the widget. + GtkWidget *toplevel_window; + toplevel_window = gtk_widget_get_toplevel(GTK_WIDGET(mOwner->mOwningWidget)); + if (!GTK_WINDOW(toplevel_window)) { + NS_ERROR("no gtk window in hierarchy!\n"); + return NS_ERROR_FAILURE; + } + gtk_window_set_transient_for(GTK_WINDOW(sTipWindow), + GTK_WINDOW(toplevel_window)); + + // realize the widget + gtk_widget_realize(sTipWindow); + + g_signal_connect (G_OBJECT(sTipWindow), "expose-event", + G_CALLBACK(tooltips_paint_window), NULL); + + // set up the label for the tooltip + GtkWidget *label = gtk_label_new(tipText.get()); + // wrap automatically + gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); + gtk_container_add(GTK_CONTAINER(sTipWindow), label); + gtk_container_set_border_width(GTK_CONTAINER(sTipWindow), 4); + // set the coords for the widget + gtk_widget_set_uposition(sTipWindow, aXCoords + root_x, + aYCoords + root_y); + + // and show it. + gtk_widget_show_all(sTipWindow); + + return NS_OK; +} + +NS_IMETHODIMP +EmbedWindow::OnHideTooltip(void) +{ + if (sTipWindow) + gtk_widget_destroy(sTipWindow); + sTipWindow = NULL; + return NS_OK; +} + +// nsIInterfaceRequestor + +NS_IMETHODIMP +EmbedWindow::GetInterface(const nsIID &aIID, void** aInstancePtr) +{ + nsresult rv; + + rv = QueryInterface(aIID, aInstancePtr); + + // pass it up to the web browser object + if (NS_FAILED(rv) || !*aInstancePtr) { + nsCOMPtr<nsIInterfaceRequestor> ir = do_QueryInterface(mWebBrowser); + return ir->GetInterface(aIID, aInstancePtr); + } + + return rv; +} diff --git a/embed/xulrunner/src/EmbedWindow.h b/embed/xulrunner/src/EmbedWindow.h new file mode 100644 index 000000000..e03164d7e --- /dev/null +++ b/embed/xulrunner/src/EmbedWindow.h @@ -0,0 +1,97 @@ +/* + * Copyright © Christopher Blizzard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * --------------------------------------------------------------------------- + * Derived from Mozilla.org code, which had the following attributions: + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Christopher Blizzard. Portions created by Christopher Blizzard are Copyright © Christopher Blizzard. All Rights Reserved. + * Portions created by the Initial Developer are Copyright © 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Christopher Blizzard <blizzard@mozilla.org> + * --------------------------------------------------------------------------- + * + * $Id$ + */ + +#ifndef __EmbedWindow_h +#define __EmbedWindow_h + +#include <nsEmbedString.h> +#include <nsIWebBrowserChrome.h> +#include <nsIWebBrowserChromeFocus.h> +#include <nsIEmbeddingSiteWindow.h> +#include <nsITooltipListener.h> +#include <nsISupports.h> +#include <nsIWebBrowser.h> +#include <nsIBaseWindow.h> +#include <nsIInterfaceRequestor.h> +#include <nsCOMPtr.h> + +#include <gtk/gtk.h> + +class GeckoBrowser; + +class EmbedWindow : public nsIWebBrowserChrome, + public nsIWebBrowserChromeFocus, + public nsIEmbeddingSiteWindow, + public nsITooltipListener, + public nsIInterfaceRequestor +{ + + public: + + EmbedWindow(); + virtual ~EmbedWindow(); + + nsresult Init (GeckoBrowser *aOwner); + nsresult CreateWindow (void); + void ReleaseChildren (void); + + NS_DECL_ISUPPORTS + + NS_DECL_NSIWEBBROWSERCHROME + + NS_DECL_NSIWEBBROWSERCHROMEFOCUS + + NS_DECL_NSIEMBEDDINGSITEWINDOW + + NS_DECL_NSITOOLTIPLISTENER + + NS_DECL_NSIINTERFACEREQUESTOR + + nsEmbedString mTitle; + nsEmbedString mJSStatus; + nsEmbedString mLinkMessage; + + nsCOMPtr<nsIBaseWindow> mBaseWindow; // [OWNER] + +private: + + GeckoBrowser *mOwner; + nsCOMPtr<nsIWebBrowser> mWebBrowser; // [OWNER] + static GtkWidget *sTipWindow; + PRBool mVisibility; + PRBool mIsModal; + +}; + +#endif /* __EmbedWindow_h */ diff --git a/embed/xulrunner/src/EmbedWindowCreator.cpp b/embed/xulrunner/src/EmbedWindowCreator.cpp new file mode 100644 index 000000000..1c05add95 --- /dev/null +++ b/embed/xulrunner/src/EmbedWindowCreator.cpp @@ -0,0 +1,108 @@ +/* + * Copyright © Christopher Blizzard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * --------------------------------------------------------------------------- + * Derived from Mozilla.org code, which had the following attributions: + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Christopher Blizzard. Portions created by Christopher Blizzard are Copyright © Christopher Blizzard. All Rights Reserved. + * Portions created by the Initial Developer are Copyright © 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Christopher Blizzard <blizzard@mozilla.org> + * --------------------------------------------------------------------------- + * + * $Id$ + */ + +#include <mozilla-config.h> +#include "config.h" + +#include "EmbedWindowCreator.h" +#include "GeckoBrowser.h" +#include "GeckoSingle.h" +#include "EmbedWindow.h" + +#include "gecko-embed-private.h" +#include "gecko-embed-single-private.h" +#include "gecko-embed-signals.h" + +EmbedWindowCreator::EmbedWindowCreator(void) +{ +} + +EmbedWindowCreator::~EmbedWindowCreator() +{ +} + +NS_IMPL_ISUPPORTS1(EmbedWindowCreator, nsIWindowCreator) + +NS_IMETHODIMP +EmbedWindowCreator::CreateChromeWindow(nsIWebBrowserChrome *aParent, + PRUint32 aChromeFlags, + nsIWebBrowserChrome **_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + + GeckoEmbed *newEmbed = nsnull; + + // No parent? Ask via the singleton object instead. + if (!aParent) { + gecko_embed_single_create_window(&newEmbed, + (guint)aChromeFlags); + } + else { + // Find the GeckoBrowser object for this web browser chrome object. + GeckoBrowser *browser = GeckoSingle::FindPrivateForBrowser(aParent); + + if (!browser) + return NS_ERROR_FAILURE; + + g_signal_emit (browser->mOwningWidget, gecko_embed_signals[NEW_WINDOW], 0, + &newEmbed, (guint) aChromeFlags); + + } + + // check to make sure that we made a new window + if (!newEmbed) + return NS_ERROR_FAILURE; + + // The window _must_ be realized before we pass it back to the + // function that created it. Functions that create new windows + // will do things like GetDocShell() and the widget has to be + // realized before that can happen. + gtk_widget_realize(GTK_WIDGET(newEmbed)); + + GeckoBrowser *newGeckoBrowser = gecko_embed_get_GeckoBrowser (newEmbed); + + // set the chrome flag on the new window if it's a chrome open + if (aChromeFlags & nsIWebBrowserChrome::CHROME_OPENAS_CHROME) + newGeckoBrowser->mIsChrome = PR_TRUE; + + *_retval = static_cast<nsIWebBrowserChrome *> + ((newGeckoBrowser->mWindow)); + + if (*_retval) { + NS_ADDREF(*_retval); + return NS_OK; + } + + return NS_ERROR_FAILURE; +} diff --git a/embed/xulrunner/src/EmbedWindowCreator.h b/embed/xulrunner/src/EmbedWindowCreator.h new file mode 100644 index 000000000..9c4e9daa5 --- /dev/null +++ b/embed/xulrunner/src/EmbedWindowCreator.h @@ -0,0 +1,51 @@ +/* + * Copyright © Christopher Blizzard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * --------------------------------------------------------------------------- + * Derived from Mozilla.org code, which had the following attributions: + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Christopher Blizzard. Portions created by Christopher Blizzard are Copyright © Christopher Blizzard. All Rights Reserved. + * Portions created by the Initial Developer are Copyright © 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Christopher Blizzard <blizzard@mozilla.org> + * --------------------------------------------------------------------------- + * + * $Id$ + */ + +#ifndef __EmbedWindowCreator_h +#define __EmbedWindowCreator_h + +#include <nsIWindowCreator.h> + +class EmbedWindowCreator : public nsIWindowCreator +{ + public: + EmbedWindowCreator(); + virtual ~EmbedWindowCreator(); + + NS_DECL_ISUPPORTS + NS_DECL_NSIWINDOWCREATOR + +}; + +#endif /* __EmbedWindowCreator_h */ diff --git a/embed/xulrunner/src/GeckoBrowser.cpp b/embed/xulrunner/src/GeckoBrowser.cpp new file mode 100644 index 000000000..5a91a98bf --- /dev/null +++ b/embed/xulrunner/src/GeckoBrowser.cpp @@ -0,0 +1,676 @@ +/* + * Copyright © Christopher Blizzard + * Copyright © 2006 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * --------------------------------------------------------------------------- + * Derived from Mozilla.org code, which had the following attributions: + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Christopher Blizzard. Portions created by Christopher Blizzard are Copyright © Christopher Blizzard. All Rights Reserved. + * Portions created by the Initial Developer are Copyright © 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Christopher Blizzard <blizzard@mozilla.org> + * --------------------------------------------------------------------------- + * + * $Id$ + */ + +#include <mozilla-config.h> +#include "config.h" + +#include "nsIDocShell.h" +#include "nsIWebProgress.h" +#include "nsIWebBrowserStream.h" +#include "nsIWebBrowserFocus.h" +#include "nsIWidget.h" +#include <stdlib.h> + +// for NS_APPSHELL_CID +#include "nsWidgetsCID.h" + +// for do_GetInterface +#include "nsIInterfaceRequestor.h" +// for do_CreateInstance +#include "nsIComponentManager.h" + +// for initializing our window watcher service +#include "nsIWindowWatcher.h" + +#include "nsILocalFile.h" +#include "nsEmbedAPI.h" + +// all of the crap that we need for event listeners +// and when chrome windows finish loading +#include "nsIDOMWindow.h" +#include "nsPIDOMWindow.h" +#include "nsIDOMWindowInternal.h" + +// For seting scrollbar visibilty +#include <nsIDOMBarProp.h> + +// for the focus hacking we need to do +#include "nsIFocusController.h" + +// for profiles +#define STANDALONE_PROFILEDIRSERVICE +#include "nsProfileDirServiceProvider.h" + +// app component registration +#include "nsIGenericFactory.h" +#include "nsIComponentRegistrar.h" + +// all of our local includes +#include "GeckoBrowser.h" +#include "EmbedWindow.h" +#include "EmbedProgress.h" +#include "EmbedContentListener.h" +#include "EmbedEventListener.h" +#include "EmbedWindowCreator.h" + +#ifdef MOZ_ACCESSIBILITY_ATK +#include "nsIAccessibilityService.h" +#include "nsIAccessible.h" +#include "nsIDOMDocument.h" +#endif + +#include "GeckoSingle.h" + +GeckoBrowser::GeckoBrowser(void) + : mOwningWidget(nsnull) + , mWindow(nsnull) + , mProgress(nsnull) + , mContentListener(nsnull) + , mEventListener(nsnull) + , mChromeMask(nsIWebBrowserChrome::CHROME_ALL) + , mIsChrome(PR_FALSE) + , mChromeLoaded(PR_FALSE) + , mListenersAttached(PR_FALSE) + , mMozWindowWidget(nsnull) + , mIsDestroyed(PR_FALSE) +{ + GeckoSingle::AddBrowser(this); +} + +GeckoBrowser::~GeckoBrowser() +{ + GeckoSingle::RemoveBrowser(this); +} + +nsresult +GeckoBrowser::Init(GeckoEmbed *aOwningWidget) +{ + // are we being re-initialized? + if (mOwningWidget) + return NS_OK; + + // hang on with a reference to the owning widget + mOwningWidget = aOwningWidget; + + // Create our embed window, and create an owning reference to it and + // initialize it. It is assumed that this window will be destroyed + // when we go out of scope. + mWindow = new EmbedWindow(); + mWindowGuard = static_cast<nsIWebBrowserChrome *>(mWindow); + mWindow->Init(this); + + // Create our progress listener object, make an owning reference, + // and initialize it. It is assumed that this progress listener + // will be destroyed when we go out of scope. + mProgress = new EmbedProgress(); + mProgressGuard = static_cast<nsIWebProgressListener *> + (mProgress); + mProgress->Init(this); + + // Create our content listener object, initialize it and attach it. + // It is assumed that this will be destroyed when we go out of + // scope. + mContentListener = new EmbedContentListener(); + mContentListenerGuard = static_cast<nsISupports*>(static_cast<nsIURIContentListener*>(mContentListener)); + mContentListener->Init(this); + + // Create our key listener object and initialize it. It is assumed + // that this will be destroyed before we go out of scope. + mEventListener = new EmbedEventListener(this); + mEventListenerGuard = + static_cast<nsISupports *>(static_cast<nsIDOMKeyListener *> + (mEventListener)); + + return NS_OK; +} + +nsresult +GeckoBrowser::Realize(PRBool *aAlreadyRealized) +{ + + *aAlreadyRealized = PR_FALSE; + + // Have we ever been initialized before? If so then just reparent + // from the offscreen window. + if (mMozWindowWidget) { + gtk_widget_reparent(mMozWindowWidget, GTK_WIDGET(mOwningWidget)); + *aAlreadyRealized = PR_TRUE; + return NS_OK; + } + + // Get the nsIWebBrowser object for our embedded window. + nsCOMPtr<nsIWebBrowser> webBrowser; + mWindow->GetWebBrowser(getter_AddRefs(webBrowser)); + + // get a handle on the navigation object + mNavigation = do_QueryInterface(webBrowser); + + // Create our session history object and tell the navigation object + // to use it. We need to do this before we create the web browser + // window. + mSessionHistory = do_CreateInstance(NS_SHISTORY_CONTRACTID); + mNavigation->SetSessionHistory(mSessionHistory); + + // create the window + mWindow->CreateWindow(); + + // bind the progress listener to the browser object + nsCOMPtr<nsISupportsWeakReference> supportsWeak; + supportsWeak = do_QueryInterface(mProgressGuard); + nsCOMPtr<nsIWeakReference> weakRef; + supportsWeak->GetWeakReference(getter_AddRefs(weakRef)); + webBrowser->AddWebBrowserListener(weakRef, + NS_GET_IID (nsIWebProgressListener)); + + // set ourselves as the parent uri content listener + nsCOMPtr<nsIURIContentListener> uriListener; + uriListener = do_QueryInterface(mContentListenerGuard); + webBrowser->SetParentURIContentListener(uriListener); + + // save the window id of the newly created window + nsCOMPtr<nsIWidget> mozWidget; + mWindow->mBaseWindow->GetMainWidget(getter_AddRefs(mozWidget)); + // get the native drawing area + GdkWindow *tmp_window = + static_cast<GdkWindow *> + (mozWidget->GetNativeData(NS_NATIVE_WINDOW)); + // and, thanks to superwin we actually need the parent of that. + // FIXME is this true on gtk2 widget? + tmp_window = gdk_window_get_parent(tmp_window); + // save the widget ID - it should be the mozarea of the window. + gpointer data = nsnull; + gdk_window_get_user_data(tmp_window, &data); + mMozWindowWidget = static_cast<GtkWidget *>(data); + + // Apply the current chrome mask + ApplyChromeMask(); + + return NS_OK; +} + +void +GeckoBrowser::Unrealize(void) +{ + // reparent to our offscreen window + GeckoSingle::ReparentToOffscreen(mMozWindowWidget); +} + +void +GeckoBrowser::Show(void) +{ + // Get the nsIWebBrowser object for our embedded window. + nsCOMPtr<nsIWebBrowser> webBrowser; + mWindow->GetWebBrowser (getter_AddRefs (webBrowser)); + + // and set the visibility on the thing + nsCOMPtr<nsIBaseWindow> baseWindow (do_QueryInterface (webBrowser)); + baseWindow->SetVisibility(PR_TRUE); +} + +void +GeckoBrowser::Hide(void) +{ + // Get the nsIWebBrowser object for our embedded window. + nsCOMPtr<nsIWebBrowser> webBrowser; + mWindow->GetWebBrowser (getter_AddRefs (webBrowser)); + + // and set the visibility on the thing + nsCOMPtr<nsIBaseWindow> baseWindow (do_QueryInterface (webBrowser)); + baseWindow->SetVisibility (PR_FALSE); +} + +void +GeckoBrowser::Resize(PRUint32 aWidth, PRUint32 aHeight) +{ + mWindow->SetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION | + nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_INNER, + 0, 0, aWidth, aHeight); +} + +void +GeckoBrowser::Destroy(void) +{ + // This flag might have been set from + // EmbedWindow::DestroyBrowserWindow() as well if someone used a + // window.close() or something or some other script action to close + // the window. No harm setting it again. + mIsDestroyed = PR_TRUE; + + // Get the nsIWebBrowser object for our embedded window. + nsCOMPtr<nsIWebBrowser> webBrowser; + mWindow->GetWebBrowser(getter_AddRefs(webBrowser)); + + // Release our progress listener + nsCOMPtr<nsISupportsWeakReference> supportsWeak + (do_QueryInterface(mProgressGuard)); + nsCOMPtr<nsIWeakReference> weakRef; + supportsWeak->GetWeakReference(getter_AddRefs(weakRef)); + webBrowser->RemoveWebBrowserListener(weakRef, + NS_GET_IID (nsIWebProgressListener)); + weakRef = nsnull; + supportsWeak = nsnull; + + // Release our content listener + webBrowser->SetParentURIContentListener(nsnull); + mContentListenerGuard = nsnull; + mContentListener = nsnull; + + // Now that we have removed the listener, release our progress + // object + mProgressGuard = nsnull; + mProgress = nsnull; + + // detach our event listeners and release the event receiver + DetachListeners(); + + mEventTarget = nsnull; + + // destroy our child window + mWindow->ReleaseChildren(); + + // release navigation + mNavigation = nsnull; + + // release session history + mSessionHistory = nsnull; + + mOwningWidget = nsnull; + + mMozWindowWidget = 0; +} + +void +GeckoBrowser::Reload(PRUint32 reloadFlags) +{ + /* Use the session history if it is available, this + * allows framesets to reload correctly */ + nsCOMPtr<nsIWebNavigation> wn (do_QueryInterface(mSessionHistory)); + + if (!wn) + wn = mNavigation; + + NS_ENSURE_TRUE (wn, ); + + wn->Reload(reloadFlags); +} + +void +GeckoBrowser::ApplyChromeMask() +{ + if (mWindow) { + nsCOMPtr<nsIWebBrowser> webBrowser; + mWindow->GetWebBrowser(getter_AddRefs(webBrowser)); + + nsCOMPtr<nsIDOMWindow> domWindow; + webBrowser->GetContentDOMWindow(getter_AddRefs(domWindow)); + if (domWindow) { + + nsCOMPtr<nsIDOMBarProp> scrollbars; + domWindow->GetScrollbars(getter_AddRefs(scrollbars)); + if (scrollbars) { + + scrollbars->SetVisible + (mChromeMask & nsIWebBrowserChrome::CHROME_SCROLLBARS ? + PR_TRUE : PR_FALSE); + } + } + } +} + + +void +GeckoBrowser::SetChromeMask(PRUint32 aChromeMask) +{ + mChromeMask = aChromeMask; + + ApplyChromeMask(); +} + +void +GeckoBrowser::SetURI(const char *aURI) +{ + mURI = aURI; +} + +void +GeckoBrowser::LoadCurrentURI(void) +{ + if (mURI.Length()) { + nsCOMPtr<nsPIDOMWindow> piWin; + GetPIDOMWindow(getter_AddRefs(piWin)); + nsAutoPopupStatePusher popupStatePusher(piWin, openAllowed); + + nsEmbedString uri; + NS_CStringToUTF16(mURI, NS_CSTRING_ENCODING_UTF8, uri); + mNavigation->LoadURI(uri.get(), // URI string + nsIWebNavigation::LOAD_FLAGS_NONE, // Load flags + nsnull, // Referring URI + nsnull, // Post data + nsnull); // extra headers + } +} + +#if 0 +nsresult +GeckoBrowser::OpenStream(const char *aBaseURI, const char *aContentType) +{ + nsCOMPtr<nsIWebBrowser> webBrowser; + mWindow->GetWebBrowser(getter_AddRefs(webBrowser)); + + nsCOMPtr<nsIWebBrowserStream> wbStream = do_QueryInterface(webBrowser); + if (!wbStream) return NS_ERROR_FAILURE; + + return wbStream->OpenStream(aBaseURI, aContentType); +} + +nsresult +GeckoBrowser::AppendToStream(const char *aData, PRInt32 aLen) +{ + // Attach listeners to this document since in some cases we don't + // get updates for content added this way. + ContentStateChange(); + + nsCOMPtr<nsIWebBrowser> webBrowser; + mWindow->GetWebBrowser(getter_AddRefs(webBrowser)); + + nsCOMPtr<nsIWebBrowserStream> wbStream = do_QueryInterface(webBrowser); + if (!wbStream) return NS_ERROR_FAILURE; + + return wbStream->AppendToStream(aData, aLen); +} + +nsresult +GeckoBrowser::CloseStream(void) +{ + nsCOMPtr<nsIWebBrowser> webBrowser; + mWindow->GetWebBrowser(getter_AddRefs(webBrowser)); + + nsCOMPtr<nsIWebBrowserStream> wbStream = do_QueryInterface(webBrowser); + if (!wbStream) return NS_ERROR_FAILURE; + + return wbStream->CloseStream(); +} +#endif + +void +GeckoBrowser::ContentStateChange(void) +{ + + // we don't attach listeners to chrome + if (mListenersAttached && !mIsChrome) + return; + + GetListener(); + + if (!mEventTarget) + return; + + AttachListeners(); + +} + +void +GeckoBrowser::ContentFinishedLoading(void) +{ + if (mIsChrome) { + // We're done loading. + mChromeLoaded = PR_TRUE; + + // get the web browser + nsCOMPtr<nsIWebBrowser> webBrowser; + mWindow->GetWebBrowser(getter_AddRefs(webBrowser)); + + // get the content DOM window for that web browser + nsCOMPtr<nsIDOMWindow> domWindow; + webBrowser->GetContentDOMWindow(getter_AddRefs(domWindow)); + if (!domWindow) { + NS_WARNING("no dom window in content finished loading\n"); + return; + } + + // resize the content + domWindow->SizeToContent(); + + // and since we're done loading show the window, assuming that the + // visibility flag has been set. + PRBool visibility; + mWindow->GetVisibility(&visibility); + if (visibility) + mWindow->SetVisibility(PR_TRUE); + } +} + +void +GeckoBrowser::ChildFocusIn(void) +{ + if (mIsDestroyed) + return; + + nsresult rv; + nsCOMPtr<nsIWebBrowser> webBrowser; + rv = mWindow->GetWebBrowser(getter_AddRefs(webBrowser)); + if (NS_FAILED(rv)) + return; + + nsCOMPtr<nsIWebBrowserFocus> webBrowserFocus(do_QueryInterface(webBrowser)); + if (!webBrowserFocus) + return; + + webBrowserFocus->Activate(); +} + +void +GeckoBrowser::ChildFocusOut(void) +{ + if (mIsDestroyed) + return; + + nsresult rv; + nsCOMPtr<nsIWebBrowser> webBrowser; + rv = mWindow->GetWebBrowser(getter_AddRefs(webBrowser)); + if (NS_FAILED(rv)) + return; + + nsCOMPtr<nsIWebBrowserFocus> webBrowserFocus(do_QueryInterface(webBrowser)); + if (!webBrowserFocus) + return; + + webBrowserFocus->Deactivate(); +} + +// Get the event listener for the chrome event handler. + +void +GeckoBrowser::GetListener(void) +{ + if (mEventTarget) + return; + + nsCOMPtr<nsPIDOMWindow> piWin; + GetPIDOMWindow(getter_AddRefs(piWin)); + + if (!piWin) + return; + + mEventTarget = do_QueryInterface(piWin->GetChromeEventHandler()); +} + +// attach key and mouse event listeners + +void +GeckoBrowser::AttachListeners(void) +{ + if (!mEventTarget || mListenersAttached) + return; + + nsIDOMEventListener *eventListener = + static_cast<nsIDOMEventListener *> + (static_cast<nsIDOMKeyListener *>(mEventListener)); + + // add the key listener + nsresult rv; + rv = mEventTarget->AddEventListenerByIID(eventListener, + NS_GET_IID(nsIDOMKeyListener)); + if (NS_FAILED(rv)) { + NS_WARNING("Failed to add key listener\n"); + return; + } + + rv = mEventTarget->AddEventListenerByIID(eventListener, + NS_GET_IID(nsIDOMMouseListener)); + if (NS_FAILED(rv)) { + NS_WARNING("Failed to add mouse listener\n"); + return; + } + + rv = mEventTarget->AddEventListenerByIID(eventListener, + NS_GET_IID(nsIDOMUIListener)); + if (NS_FAILED(rv)) { + NS_WARNING("Failed to add UI listener\n"); + return; + } + + rv = mEventTarget->AddEventListenerByIID(eventListener, + NS_GET_IID(nsIDOMContextMenuListener)); + if (NS_FAILED(rv)) { + NS_WARNING("Failed to add context menu listener\n"); + return; + } + + // ok, all set. + mListenersAttached = PR_TRUE; +} + +void +GeckoBrowser::DetachListeners(void) +{ + if (!mListenersAttached || !mEventTarget) + return; + + nsIDOMEventListener *eventListener = + static_cast<nsIDOMEventListener *> + (static_cast<nsIDOMKeyListener *>(mEventListener)); + + nsresult rv; + rv = mEventTarget->RemoveEventListenerByIID(eventListener, + NS_GET_IID(nsIDOMKeyListener)); + if (NS_FAILED(rv)) { + NS_WARNING("Failed to remove key listener\n"); + return; + } + + rv = + mEventTarget->RemoveEventListenerByIID(eventListener, + NS_GET_IID(nsIDOMMouseListener)); + if (NS_FAILED(rv)) { + NS_WARNING("Failed to remove mouse listener\n"); + return; + } + + rv = mEventTarget->RemoveEventListenerByIID(eventListener, + NS_GET_IID(nsIDOMUIListener)); + if (NS_FAILED(rv)) { + NS_WARNING("Failed to remove UI listener\n"); + return; + } + + rv = mEventTarget->RemoveEventListenerByIID(eventListener, + NS_GET_IID(nsIDOMContextMenuListener)); + if (NS_FAILED(rv)) { + NS_WARNING("Failed to remove context menu listener\n"); + return; + } + + mListenersAttached = PR_FALSE; +} + +nsresult +GeckoBrowser::GetPIDOMWindow(nsPIDOMWindow **aPIWin) +{ + *aPIWin = nsnull; + + // get the web browser + nsCOMPtr<nsIWebBrowser> webBrowser; + mWindow->GetWebBrowser(getter_AddRefs(webBrowser)); + + // get the content DOM window for that web browser + nsCOMPtr<nsIDOMWindow> domWindow; + webBrowser->GetContentDOMWindow(getter_AddRefs(domWindow)); + if (!domWindow) + return NS_ERROR_FAILURE; + + // get the private DOM window + nsCOMPtr<nsPIDOMWindow> domWindowPrivate = do_QueryInterface(domWindow); + // and the root window for that DOM window + *aPIWin = domWindowPrivate->GetPrivateRoot(); + + if (*aPIWin) { + NS_ADDREF(*aPIWin); + return NS_OK; + } + + return NS_ERROR_FAILURE; +} + +#ifdef MOZ_ACCESSIBILITY_ATK +// FIXME does this REALLY work with frames? +void * +GeckoBrowser::GetAtkObjectForCurrentDocument() +{ + if (!mNavigation) + return nsnull; + + nsCOMPtr<nsIAccessibilityService> accService = + do_GetService("@mozilla.org/accessibilityService;1"); + if (accService) { + //get current document + nsCOMPtr<nsIDOMDocument> domDoc; + mNavigation->GetDocument(getter_AddRefs(domDoc)); + NS_ENSURE_TRUE(domDoc, nsnull); + + nsCOMPtr<nsIDOMNode> domNode(do_QueryInterface(domDoc)); + NS_ENSURE_TRUE(domNode, nsnull); + + nsCOMPtr<nsIAccessible> acc; + accService->GetAccessibleFor(domNode, getter_AddRefs(acc)); + NS_ENSURE_TRUE(acc, nsnull); + + void *atkObj = nsnull; + if (NS_SUCCEEDED(acc->GetNativeInterface(&atkObj))) + return atkObj; + } + return nsnull; +} +#endif /* MOZ_ACCESSIBILITY_ATK */ diff --git a/embed/xulrunner/src/GeckoBrowser.h b/embed/xulrunner/src/GeckoBrowser.h new file mode 100644 index 000000000..0d7a86af3 --- /dev/null +++ b/embed/xulrunner/src/GeckoBrowser.h @@ -0,0 +1,159 @@ +/* + * Copyright © Christopher Blizzard + * Copyright © 2006 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * --------------------------------------------------------------------------- + * Derived from Mozilla.org code, which had the following attributions: + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Christopher Blizzard. Portions created by Christopher Blizzard are Copyright © Christopher Blizzard. All Rights Reserved. + * Portions created by the Initial Developer are Copyright © 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Christopher Blizzard <blizzard@mozilla.org> + * --------------------------------------------------------------------------- + * + * $Id$ + */ + +#ifndef __GeckoBrowser_h +#define __GeckoBrowser_h + +#include <nsCOMPtr.h> +#include <nsEmbedString.h> +#include <nsIWebNavigation.h> +#include <nsISHistory.h> +// for our one function that gets the GeckoBrowser via the chrome +// object. +#include <nsIWebBrowserChrome.h> +#include <nsIAppShell.h> +#include <nsPIDOMEventTarget.h> +// app component registration +#include <nsIGenericFactory.h> +#include <nsIComponentRegistrar.h> + +#include "gecko-embed.h" + +class EmbedProfile; +class EmbedProgress; +class EmbedWindow; +class EmbedContentListener; +class EmbedEventListener; + +class nsPIDOMWindow; +class nsIDirectoryServiceProvider; +class nsProfileDirServiceProvider; + +class GeckoBrowser { + + public: + + GeckoBrowser(); + ~GeckoBrowser(); + + nsresult Init (GeckoEmbed *aOwningWidget); + nsresult Realize (PRBool *aAlreadRealized); + void Unrealize (void); + void Show (void); + void Hide (void); + void Resize (PRUint32 aWidth, PRUint32 aHeight); + void Destroy (void); + void SetURI (const char *aURI); + void LoadCurrentURI (void); + void Reload (PRUint32 reloadFlags); + + void SetChromeMask (PRUint32 chromeMask); + void ApplyChromeMask (); + + nsresult OpenStream (const char *aBaseURI, const char *aContentType); + nsresult AppendToStream (const char *aData, PRInt32 aLen); + nsresult CloseStream (void); + + // This is an upcall that will come from the progress listener + // whenever there is a content state change. We need this so we can + // attach event listeners. + void ContentStateChange (void); + + // This is an upcall from the progress listener when content is + // finished loading. We have this so that if it's chrome content + // that we can size to content properly and show ourselves if + // visibility is set. + void ContentFinishedLoading(void); + + // these let the widget code know when the toplevel window gets and + // looses focus. + void TopLevelFocusIn (void); + void TopLevelFocusOut(void); + + // these are when the widget itself gets focus in and focus out + // events + void ChildFocusIn (void); + void ChildFocusOut(void); + +#ifdef MOZ_ACCESSIBILITY_ATK + void *GetAtkObjectForCurrentDocument(); +#endif + + GeckoEmbed *mOwningWidget; + + // all of the objects that we own + EmbedWindow *mWindow; + nsCOMPtr<nsISupports> mWindowGuard; + EmbedProgress *mProgress; + nsCOMPtr<nsISupports> mProgressGuard; + EmbedContentListener *mContentListener; + nsCOMPtr<nsISupports> mContentListenerGuard; + EmbedEventListener *mEventListener; + nsCOMPtr<nsISupports> mEventListenerGuard; + + nsCOMPtr<nsIWebNavigation> mNavigation; + nsCOMPtr<nsISHistory> mSessionHistory; + + // our event receiver + nsCOMPtr<nsPIDOMEventTarget> mEventTarget; + + // the currently loaded uri + nsEmbedCString mURI; + + // chrome mask + PRUint32 mChromeMask; + // is this a chrome window? + PRBool mIsChrome; + // has the chrome finished loading? + PRBool mChromeLoaded; + // saved window ID for reparenting later + GtkWidget *mMozWindowWidget; + // has someone called Destroy() on us? + PRBool mIsDestroyed; + + private: + + // is the chrome listener attached yet? + PRBool mListenersAttached; + + void GetListener (void); + void AttachListeners (void); + void DetachListeners (void); + + // this will get the PIDOMWindow for this widget + nsresult GetPIDOMWindow (nsPIDOMWindow **aPIWin); +}; + +#endif /* __GeckoBrowser_h */ diff --git a/embed/xulrunner/src/GeckoPromptService.cpp b/embed/xulrunner/src/GeckoPromptService.cpp new file mode 100644 index 000000000..c9c5b03c2 --- /dev/null +++ b/embed/xulrunner/src/GeckoPromptService.cpp @@ -0,0 +1,891 @@ +/* + * Copyright © 2005, 2006 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id$ + */ + +#include <mozilla-config.h> +#include "config.h" + +#include <glib.h> +#include <glib-object.h> +#include <glib/gi18n.h> +#include <gtk/gtk.h> + +#include <nsStringAPI.h> + +#include <nsCOMPtr.h> +#include <nsIDOMWindow.h> +#include <nsServiceManagerUtils.h> + +#include "gecko-embed.h" +#include "gecko-embed-single.h" + +#include "AutoJSContextStack.h" +#include "AutoWindowModalState.h" +#include "GeckoUtils.h" + +#include "GeckoPromptService.h" + +#define TIMEOUT 1000 /* ms */ +#define TIMEOUT_DATA_KEY "timeout" + +#define MAX_MESSAGE_LENGTH 512 +#define MAX_TITLE_LENGTH 256 +#define MAX_BUTTON_TEXT_LENGTH 128 + +enum +{ + RESPONSE_ABORT_SCRIPT = 42 +}; + +class Prompter +{ +public: + Prompter (const char*, nsIDOMWindow*, const PRUnichar*, const PRUnichar*); + ~Prompter(); + + void AddStockButton (const char*, int); + void AddButtonWithFlags (PRInt32, PRUint32, const PRUnichar*, PRUint32); + void AddButtonsWithFlags (PRUint32, const PRUnichar*, const PRUnichar*, const PRUnichar*); + void AddCheckbox (const PRUnichar*, PRBool*); + void GetCheckboxState (PRBool *); + void AddEntry (const char *, const PRUnichar *, PRBool); + void GetText (PRUint32, PRUnichar **); + void AddSelect (PRUint32, const PRUnichar **, PRInt32); + void GetSelected (PRInt32*); + + PRInt32 Run (PRBool * = nsnull); + void Show (); + + PRBool IsCalledFromScript (); + void PerformScriptAbortion (); + + char *ConvertAndTruncateString (const PRUnichar *, PRInt32 = -1); + char* ConvertAndEscapeButtonText (const PRUnichar *, PRInt32 = -1); + +private: + nsCOMPtr<nsIDOMWindow> mWindow; + GtkDialog *mDialog; + GtkWidget *mVBox; + GtkWidget *mCheck; + GtkSizeGroup *mSizeGroup; + GtkWidget *mEntries[2]; + GtkWidget *mCombo; + PRInt32 mNumButtons; + PRInt32 mNumEntries; + PRInt32 mDefaultResponse; + PRInt32 mUnaffirmativeResponse; + PRInt32 mResponse; + PRBool mSuccess; + PRBool mDelay; +}; + +Prompter::Prompter (const char *aStock, + nsIDOMWindow *aParent, + const PRUnichar *aTitle, + const PRUnichar *aText) + : mWindow (aParent) + , mDialog(nsnull) + , mVBox(nsnull) + , mCheck(nsnull) + , mSizeGroup(nsnull) + , mCombo(nsnull) + , mNumButtons(0) + , mNumEntries(0) + , mDefaultResponse(GTK_RESPONSE_ACCEPT) + , mUnaffirmativeResponse(0) + , mResponse(GTK_RESPONSE_CANCEL) + , mSuccess(PR_FALSE) + , mDelay(PR_FALSE) +{ + GtkWidget *parent, *hbox, *label, *image; + + gecko_embed_single_push_startup (); + + mEntries[0] = mEntries[1] = nsnull; + + mDialog = GTK_DIALOG (gtk_dialog_new ()); + g_object_ref (mDialog); + gtk_object_sink (GTK_OBJECT (mDialog)); + + char *title = NULL; + if (aTitle) + { + title = ConvertAndTruncateString (aTitle, MAX_TITLE_LENGTH); + } + + gtk_window_set_title (GTK_WINDOW (mDialog), title ? title : ""); + g_free (title); + + gtk_window_set_modal (GTK_WINDOW (mDialog), TRUE); + + parent = GeckoUtils::GetGtkWindowForDOMWindow (aParent); + if (GTK_IS_WINDOW (parent)) + { + gtk_window_set_transient_for (GTK_WINDOW (mDialog), + GTK_WINDOW (parent)); + +#if !GTK_CHECK_VERSION (2,9,0) + if (GTK_WINDOW (parent)->group) + { + gtk_window_group_add_window (GTK_WINDOW (parent)->group, + GTK_WINDOW (mDialog)); + } +#endif + } + + gtk_dialog_set_has_separator (mDialog, FALSE); + gtk_window_set_resizable (GTK_WINDOW (mDialog), FALSE); + gtk_container_set_border_width (GTK_CONTAINER (mDialog), 5); + gtk_box_set_spacing (GTK_BOX (mDialog->vbox), 14); /* 2 * 5 + 14 = 24 */ + + hbox = gtk_hbox_new (FALSE, 12); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); + gtk_container_add (GTK_CONTAINER (GTK_DIALOG (mDialog)->vbox), hbox); + + image = gtk_image_new_from_stock (aStock, GTK_ICON_SIZE_DIALOG); + gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0.0); + gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0); + + mVBox = gtk_vbox_new (FALSE, 12); + gtk_box_pack_start (GTK_BOX (hbox), mVBox, TRUE, TRUE, 0); + + char *text = NULL; + if (aText) + { + text = ConvertAndTruncateString (aText, MAX_MESSAGE_LENGTH); + } + + label = gtk_label_new (text); + g_free (text); + + gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); + /* Guard against overlong nonbreakable text (exploit) */ + gtk_label_set_line_wrap_mode (GTK_LABEL (label), PANGO_WRAP_WORD_CHAR); + gtk_label_set_selectable (GTK_LABEL (label), TRUE); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.0); + + gtk_box_pack_start (GTK_BOX (mVBox), label, FALSE, FALSE, 0); + gtk_widget_show (label); + + if (IsCalledFromScript ()) + { + gtk_dialog_add_button (GTK_DIALOG (mDialog), + _("_Abort Script"), + RESPONSE_ABORT_SCRIPT); + } + + gtk_widget_show (image); + gtk_widget_show (mVBox); + gtk_widget_show (hbox); +} + +Prompter::~Prompter () +{ + if (mSizeGroup) + { + g_object_unref (mSizeGroup); + } + + gtk_widget_destroy (GTK_WIDGET (mDialog)); + g_object_unref (mDialog); + + gecko_embed_single_pop_startup (); +} + +void +Prompter::AddStockButton (const char *aStock, + int aResponse) +{ + gtk_dialog_add_button (GTK_DIALOG (mDialog), + aStock, aResponse); + ++mNumButtons; +} + +void +Prompter::AddButtonWithFlags (PRInt32 aNum, + PRUint32 aFlags, + const PRUnichar *aText, + PRUint32 aDefault) +{ + if (aFlags == 0) return; + + const char *label = NULL; + char *freeme = NULL; + gboolean isAffirmative = FALSE; + switch (aFlags) + { + case nsIPromptService::BUTTON_TITLE_OK: + label = GTK_STOCK_OK; + isAffirmative = TRUE; + break; + + case nsIPromptService::BUTTON_TITLE_CANCEL: + label = GTK_STOCK_CANCEL; + break; + + case nsIPromptService::BUTTON_TITLE_YES: + label = GTK_STOCK_YES; + isAffirmative = TRUE; + break; + + case nsIPromptService::BUTTON_TITLE_NO: + label = GTK_STOCK_NO; + break; + + case nsIPromptService::BUTTON_TITLE_SAVE: + label = GTK_STOCK_SAVE; + isAffirmative = TRUE; + break; + + case nsIPromptService::BUTTON_TITLE_DONT_SAVE: + label = _("Don't Save"); + break; + + case nsIPromptService::BUTTON_TITLE_REVERT: + label = GTK_STOCK_REVERT_TO_SAVED; + break; + + case nsIPromptService::BUTTON_TITLE_IS_STRING: + default: + label = freeme = ConvertAndEscapeButtonText (aText, MAX_BUTTON_TEXT_LENGTH); + /* We can't tell, so assume it's affirmative */ + isAffirmative = TRUE; + break; + } + + if (label == NULL) return; + + gtk_dialog_add_button (mDialog, label, aNum); + ++mNumButtons; + + if (isAffirmative && mDelay) + { + gtk_dialog_set_response_sensitive (mDialog, aNum, FALSE); + } + + if (!isAffirmative) + { + mUnaffirmativeResponse = aNum; + } + + if (aDefault) + { + mDefaultResponse = aNum; + } + + g_free (freeme); +} + +void +Prompter::AddButtonsWithFlags (PRUint32 aFlags, + const PRUnichar *aText0, + const PRUnichar *aText1, + const PRUnichar *aText2) +{ + mDelay = (aFlags & nsIPromptService::BUTTON_DELAY_ENABLE) != 0; + mDefaultResponse = -1; + + /* Reverse the order, on the assumption that what we passed is the + * 'windows' button order, and we want HIG order. + */ + AddButtonWithFlags (2, ((aFlags / nsIPromptService::BUTTON_POS_2) & 0xff), aText2, + aFlags & nsIPromptService::BUTTON_POS_2_DEFAULT); + AddButtonWithFlags (1, ((aFlags / nsIPromptService::BUTTON_POS_1) & 0xff), aText1, + aFlags & nsIPromptService::BUTTON_POS_1_DEFAULT); + AddButtonWithFlags (0, ((aFlags / nsIPromptService::BUTTON_POS_0) & 0xff), aText0, + aFlags & nsIPromptService::BUTTON_POS_0_DEFAULT); + + /* If no default was set, use the 'rightmost' unaffirmative response. + * This happens with the suite's password manager prompt. + */ + if (mDefaultResponse == -1) + { + mDefaultResponse = mUnaffirmativeResponse; + } +} + +void +Prompter::AddCheckbox (const PRUnichar *aText, + PRBool *aState) +{ + if (!aState || !aText) return; + + char *label = ConvertAndEscapeButtonText (aText, 2 * MAX_BUTTON_TEXT_LENGTH); + mCheck = gtk_check_button_new_with_mnemonic (label); + g_free (label); + + gtk_label_set_line_wrap (GTK_LABEL (GTK_BIN (mCheck)->child), TRUE); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mCheck), *aState); + gtk_box_pack_start (GTK_BOX (mVBox), mCheck, FALSE, FALSE, 0); + gtk_widget_show (mCheck); +} + +void +Prompter::GetCheckboxState (PRBool *aState) +{ + if (!aState || !mCheck) return; + + *aState = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (mCheck)); +} + +void +Prompter::AddEntry (const char *aLabel, + const PRUnichar *aValue, + PRBool aIsPassword) +{ + if (!mSizeGroup) + { + mSizeGroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); + } + + GtkWidget *hbox = gtk_hbox_new (FALSE, 12); + gtk_box_pack_start (GTK_BOX (mVBox), hbox, FALSE, FALSE, 0); + + GtkWidget *label = nsnull; + if (aLabel) + { + label = gtk_label_new_with_mnemonic (aLabel); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); + gtk_size_group_add_widget (mSizeGroup, label); + } + + GtkWidget *entry = mEntries[mNumEntries++] = gtk_entry_new (); + gtk_entry_set_visibility (GTK_ENTRY (entry), !aIsPassword); + gtk_entry_set_activates_default(GTK_ENTRY (entry), TRUE); + + if (aValue) + { + nsCString cValue; + NS_UTF16ToCString (nsDependentString(aValue), + NS_CSTRING_ENCODING_UTF8, cValue); + + gtk_entry_set_text (GTK_ENTRY (entry), cValue.get()); + } + + if (label) + { + gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry); + } + + gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0); + gtk_widget_show_all (hbox); +} + +void +Prompter::GetText (PRUint32 aNum, + PRUnichar **aValue) +{ + if (!aValue || !mEntries[aNum]) return; + + const char *text = gtk_entry_get_text (GTK_ENTRY (mEntries[aNum])); + if (!text) return; + + nsString value; + NS_CStringToUTF16 (nsDependentCString (text), + NS_CSTRING_ENCODING_UTF8, value); + + *aValue = NS_StringCloneData (value); +} + +void +Prompter::AddSelect (PRUint32 aCount, + const PRUnichar **aList, + PRInt32 aDefault) +{ + mCombo = gtk_combo_box_new_text (); + + for (PRUint32 i = 0; i < aCount; i++) + { + /* FIXME: use "" instead in this case? */ + if (!aList[i] || !aList[i][0]) continue; + + nsCString cData; + NS_UTF16ToCString (nsDependentString(aList[i]), NS_CSTRING_ENCODING_UTF8, cData); + + gtk_combo_box_append_text (GTK_COMBO_BOX (mCombo), cData.get()); + } + + gtk_combo_box_set_active (GTK_COMBO_BOX (mCombo), aDefault); + + gtk_box_pack_start (GTK_BOX (mVBox), mCombo, FALSE, FALSE, 0); + gtk_widget_show (mCombo); +} + +void +Prompter::GetSelected (PRInt32 *aSelected) +{ + if (!aSelected || !mCombo) return; + + *aSelected = gtk_combo_box_get_active (GTK_COMBO_BOX (mCombo)); +} + +static gboolean +EnableResponse (GtkDialog *aDialog) +{ + g_object_steal_data (G_OBJECT (aDialog), TIMEOUT_DATA_KEY); + + gtk_dialog_set_response_sensitive (aDialog, 0, TRUE); + gtk_dialog_set_response_sensitive (aDialog, 1, TRUE); + gtk_dialog_set_response_sensitive (aDialog, 2, TRUE); + + return FALSE; +} + +static void +RemoveTimeout (gpointer idptr) +{ + guint timeout = GPOINTER_TO_UINT (idptr); + + g_return_if_fail (timeout != 0); + + g_source_remove (timeout); +} + +PRInt32 +Prompter::Run (PRBool *aSuccess) +{ +#if 0 + AutoEventQueue queue; + if (NS_FAILED (queue.Init())) + { + if (aSuccess) + { + *aSuccess = PR_FALSE; + } + mSuccess = PR_FALSE; + + return GTK_RESPONSE_CANCEL; + } +#endif + + nsresult rv; + AutoJSContextStack stack; + rv = stack.Init (); + if (NS_FAILED (rv)) return rv; + + AutoWindowModalState modalState (mWindow); + + if (mDelay) + { + guint timeout = g_timeout_add (TIMEOUT, + (GSourceFunc) EnableResponse, + mDialog); + g_object_set_data_full (G_OBJECT (mDialog), TIMEOUT_DATA_KEY, + GUINT_TO_POINTER (timeout), + (GDestroyNotify) RemoveTimeout); + } + + gtk_dialog_set_default_response (GTK_DIALOG (mDialog), mDefaultResponse); + + GtkWidget *widget = GTK_WIDGET (mDialog); + gtk_widget_show (widget); + mResponse = gtk_dialog_run (mDialog); + gtk_widget_hide (widget); + + g_object_set_data (G_OBJECT (mDialog), TIMEOUT_DATA_KEY, NULL); + + mSuccess = (GTK_RESPONSE_ACCEPT == mResponse); + if (aSuccess) + { + *aSuccess = mSuccess; + } + + if (mResponse == RESPONSE_ABORT_SCRIPT) + { + PerformScriptAbortion (); + } + + return mResponse; +} + +static void +DeletePrompter (gpointer aPromptPtr, + GObject *aZombie) +{ + Prompter *prompt = static_cast<Prompter*>(aPromptPtr); + + delete prompt; +} + +void +Prompter::Show () +{ + /* We don't need it anymore */ + mWindow = nsnull; + + gtk_window_set_modal (GTK_WINDOW (mDialog), FALSE); + + g_signal_connect (mDialog, "response", + G_CALLBACK (gtk_widget_destroy), NULL); + g_object_weak_ref (G_OBJECT (mDialog), + (GWeakNotify) DeletePrompter, + static_cast<gpointer>(this)); + + gtk_widget_show (GTK_WIDGET (mDialog)); +} + +PRBool +Prompter::IsCalledFromScript() +{ +#if 0 + nsCOMPtr<nsIXPConnect> xpconnect (do_GetService (nsIXPConnect::GetCID())); + NS_ENSURE_TRUE (xpconnect, PR_FALSE); + + nsresult rv; + nsCOMPtr<nsIXPCNativeCallContext> ncc; + rv = xpconnect->GetCurrentNativeCallContext (getter_AddRefs (ncc)); + NS_ENSURE_SUCCESS (rv, PR_FALSE); + + if (!ncc) return PR_FALSE; + + JSContext *cx = nsnull; + rv = ncc->GetJSContext (&cx); + g_print ("GetJSContext rv=%x, cx=%p\n", rv, cx); + + NS_ENSURE_SUCCESS (rv, PR_FALSE); + + return cx != nsnull; +#endif + return PR_FALSE; +} + +void +Prompter::PerformScriptAbortion() +{ +#if 0 + /* FIXME: can we only stop the calling script, not all scripts in the context? */ + + nsCOMPtr<nsIXPConnect> xpconnect (do_GetService (nsIXPConnect::GetCID())); + NS_ENSURE_TRUE (xpconnect, ); + + nsresult rv; + nsCOMPtr<nsIXPCNativeCallContext> ncc; + rv = xpconnect->GetCurrentNativeCallContext (getter_AddRefs (ncc)); + NS_ENSURE_SUCCESS (rv, ); + NS_ENSURE_TRUE (ncc, ); + + JSContext *cx = nsnull; + rv = ncc->GetJSContext (&cx); + g_print ("GetJSContext rv=%x, cx=%p\n", rv, cx); + NS_ENSURE_SUCCESS (rv, ); + NS_ENSURE_TRUE (cx, ); + + g_print ("Would now disable scripts\n"); +// MozillaPrivate::SetScriptsEnabled (cx, PR_FALSE, PR_FALSE); +#endif +} + +char * +Prompter::ConvertAndTruncateString (const PRUnichar *aText, + PRInt32 aMaxLength) +{ + if (aText == nsnull) return NULL; + + /* This depends on the assumption that + * typeof(PRUnichar) == typeof (gunichar2) == uint16, + * which should be pretty safe. + */ + glong n_read = 0, n_written = 0; + char *converted = g_utf16_to_utf8 ((gunichar2*) aText, aMaxLength, + &n_read, &n_written, NULL); + /* FIXME loop from the end while !g_unichar_isspace (char)? */ + + return converted; +} + +char * +Prompter::ConvertAndEscapeButtonText(const PRUnichar *aText, + PRInt32 aMaxLength) +{ + char *converted = ConvertAndTruncateString (aText, aMaxLength); + if (converted == NULL) return NULL; + + char *escaped = (char*) g_malloc (strlen (converted) + 1); + char *q = escaped; + for (const char *p = converted; *p; ++p, ++q) + { + if (*p == '&') + { + if (*(p+1) == '&') + { + *q = '&'; + ++p; + } + else + { + *q = '_'; + } + } + else + { + *q = *p; + } + } + + /* Null termination */ + *q = '\0'; + + g_free (converted); + + return escaped; +} + +/* FIXME: needs THREADSAFE? */ +#if HAVE_NSINONBLOCKINGALERTSERVICE_H +NS_IMPL_ISUPPORTS2 (GeckoPromptService, + nsIPromptService, + nsINonBlockingAlertService) +#else +NS_IMPL_ISUPPORTS1 (GeckoPromptService, + nsIPromptService) +#endif + +GeckoPromptService::GeckoPromptService() +{ +} + +GeckoPromptService::~GeckoPromptService() +{ +} + +/* nsIPromptService implementation */ + +/* void alert (in nsIDOMWindow aParent, in wstring aDialogTitle, in wstring aText); */ +NS_IMETHODIMP +GeckoPromptService::Alert (nsIDOMWindow *aParent, + const PRUnichar *aDialogTitle, + const PRUnichar *aText) +{ + Prompter prompt (GTK_STOCK_DIALOG_INFO, aParent, aDialogTitle, aText); + prompt.AddStockButton (GTK_STOCK_OK, GTK_RESPONSE_ACCEPT); + prompt.Run (); + + return NS_OK; +} + +/* void alertCheck (in nsIDOMWindow aParent, in wstring aDialogTitle, in wstring aText, in wstring aCheckMsg, inout boolean aCheckState); */ +NS_IMETHODIMP +GeckoPromptService::AlertCheck (nsIDOMWindow *aParent, + const PRUnichar *aDialogTitle, + const PRUnichar *aText, + const PRUnichar *aCheckMsg, + PRBool *aCheckState) +{ + Prompter prompt (GTK_STOCK_DIALOG_INFO, aParent, aDialogTitle, aText); + prompt.AddStockButton (GTK_STOCK_OK, GTK_RESPONSE_ACCEPT); + prompt.AddCheckbox (aCheckMsg, aCheckState); + + prompt.Run (); + prompt.GetCheckboxState (aCheckState); + + return NS_OK; +} + +/* boolean confirm (in nsIDOMWindow aParent, in wstring aDialogTitle, in wstring aText); */ +NS_IMETHODIMP +GeckoPromptService::Confirm (nsIDOMWindow *aParent, + const PRUnichar *aDialogTitle, + const PRUnichar *aText, + PRBool *_retval) +{ + NS_ENSURE_ARG_POINTER (_retval); + + Prompter prompt (GTK_STOCK_DIALOG_QUESTION, aParent, aDialogTitle, aText); + prompt.AddStockButton (GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); + prompt.AddStockButton (GTK_STOCK_OK, GTK_RESPONSE_ACCEPT); + prompt.Run (_retval); + + return NS_OK; +} + +/* boolean confirmCheck (in nsIDOMWindow aParent, in wstring aDialogTitle, in wstring aText, in wstring aCheckMsg, inout boolean aCheckState); */ +NS_IMETHODIMP +GeckoPromptService::ConfirmCheck (nsIDOMWindow *aParent, + const PRUnichar *aDialogTitle, + const PRUnichar *aText, + const PRUnichar *aCheckMsg, + PRBool *aCheckState, + PRBool *_retval) +{ + NS_ENSURE_ARG_POINTER (_retval); + + Prompter prompt (GTK_STOCK_DIALOG_QUESTION, aParent, aDialogTitle, aText); + prompt.AddStockButton (GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); + prompt.AddStockButton (GTK_STOCK_OK, GTK_RESPONSE_ACCEPT); + prompt.AddCheckbox (aCheckMsg, aCheckState); + + prompt.Run (_retval); + prompt.GetCheckboxState (aCheckState); + + return NS_OK; +} + +/* PRInt32 confirmEx (in nsIDOMWindow aParent, in wstring aDialogTitle, in wstring aText, in unsigned long aButtonFlags, in wstring aButton0Title, in wstring aButton1Title, in wstring aButton2Title, in wstring aCheckMsg, inout boolean aCheckState); */ +NS_IMETHODIMP +GeckoPromptService::ConfirmEx (nsIDOMWindow *aParent, + const PRUnichar *aDialogTitle, + const PRUnichar *aText, + PRUint32 aButtonFlags, + const PRUnichar *aButton0Title, + const PRUnichar *aButton1Title, + const PRUnichar *aButton2Title, + const PRUnichar *aCheckMsg, + PRBool *aCheckState, + PRInt32 *_retval) +{ + NS_ENSURE_ARG_POINTER (_retval); + + Prompter prompt (GTK_STOCK_DIALOG_QUESTION, aParent, aDialogTitle, aText); + prompt.AddButtonsWithFlags (aButtonFlags, aButton0Title, + aButton1Title, aButton2Title); + prompt.AddCheckbox (aCheckMsg, aCheckState); + + *_retval = prompt.Run (nsnull); + prompt.GetCheckboxState (aCheckState); + + return NS_OK; +} + +/* boolean prompt (in nsIDOMWindow aParent, in wstring aDialogTitle, in wstring aText, inout wstring aValue, in wstring aCheckMsg, inout boolean aCheckState); */ +NS_IMETHODIMP +GeckoPromptService::Prompt (nsIDOMWindow *aParent, + const PRUnichar *aDialogTitle, + const PRUnichar *aText, + PRUnichar **aValue, + const PRUnichar *aCheckMsg, + PRBool *aCheckState, + PRBool *_retval) +{ + NS_ENSURE_ARG_POINTER (_retval); + NS_ENSURE_ARG_POINTER (aValue); + + Prompter prompt (GTK_STOCK_DIALOG_QUESTION, aParent, aDialogTitle, aText); + prompt.AddStockButton (GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); + prompt.AddStockButton (GTK_STOCK_OK, GTK_RESPONSE_ACCEPT); + prompt.AddEntry (nsnull, *aValue, PR_FALSE); + prompt.AddCheckbox (aCheckMsg, aCheckState); + + prompt.Run (_retval); + prompt.GetText (0, aValue); + prompt.GetCheckboxState (aCheckState); + + return NS_OK; +} + +/* boolean promptUsernameAndPassword (in nsIDOMWindow aParent, in wstring aDialogTitle, in wstring aText, inout wstring aUsername, inout wstring aPassword, in wstring aCheckMsg, inout boolean aCheckState); */ +NS_IMETHODIMP +GeckoPromptService::PromptUsernameAndPassword (nsIDOMWindow *aParent, + const PRUnichar *aDialogTitle, + const PRUnichar *aText, + PRUnichar **aUsername, + PRUnichar **aPassword, + const PRUnichar *aCheckMsg, + PRBool *aCheckState, + PRBool *_retval) +{ + NS_ENSURE_ARG_POINTER (_retval); + NS_ENSURE_ARG_POINTER (aUsername); + NS_ENSURE_ARG_POINTER (aPassword); + + Prompter prompt (GTK_STOCK_DIALOG_AUTHENTICATION, aParent, aDialogTitle, aText); + prompt.AddStockButton (GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); + prompt.AddStockButton (GTK_STOCK_OK, GTK_RESPONSE_ACCEPT); + prompt.AddEntry (_("_Username:"), *aUsername, PR_FALSE); + prompt.AddEntry (_("_Password:"), *aPassword, PR_TRUE); + prompt.AddCheckbox (aCheckMsg, aCheckState); + + prompt.Run (_retval); + prompt.GetText (0, aUsername); + prompt.GetText (1, aPassword); + prompt.GetCheckboxState (aCheckState); + + return NS_OK; +} + +/* boolean promptPassword (in nsIDOMWindow aParent, in wstring aDialogTitle, in wstring aText, inout wstring aPassword, in wstring aCheckMsg, inout boolean aCheckState); */ +NS_IMETHODIMP +GeckoPromptService::PromptPassword (nsIDOMWindow *aParent, + const PRUnichar *aDialogTitle, + const PRUnichar *aText, + PRUnichar **aPassword, + const PRUnichar *aCheckMsg, + PRBool *aCheckState, + PRBool *_retval) +{ + NS_ENSURE_ARG_POINTER (_retval); + NS_ENSURE_ARG_POINTER (aPassword); + + Prompter prompt (GTK_STOCK_DIALOG_AUTHENTICATION, aParent, aDialogTitle, aText); + prompt.AddStockButton (GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); + prompt.AddStockButton (GTK_STOCK_OK, GTK_RESPONSE_ACCEPT); + prompt.AddEntry (_("_Password:"), *aPassword, PR_TRUE); + prompt.AddCheckbox (aCheckMsg, aCheckState); + + // FIXME: Add a CAPSLOCK indicator? + + prompt.Run (_retval); + prompt.GetText (0, aPassword); + prompt.GetCheckboxState (aCheckState); + + return NS_OK; +} + +/* boolean select (in nsIDOMWindow aParent, in wstring aDialogTitle, in wstring aText, in PRUint32 aCount, [array, size_is (aCount)] in wstring aSelectList, out long aOutSelection); */ +NS_IMETHODIMP +GeckoPromptService::Select (nsIDOMWindow *aParent, + const PRUnichar *aDialogTitle, + const PRUnichar *aText, + PRUint32 aCount, + const PRUnichar **aSelectList, + PRInt32 *aOutSelection, + PRBool *_retval) +{ + NS_ENSURE_ARG_POINTER (_retval); + NS_ENSURE_ARG_POINTER (aOutSelection); + + Prompter prompt (GTK_STOCK_DIALOG_QUESTION, aParent, aDialogTitle, aText); + prompt.AddStockButton (GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); + prompt.AddStockButton (GTK_STOCK_OK, GTK_RESPONSE_ACCEPT); + prompt.AddSelect (aCount, aSelectList, *aOutSelection); + + prompt.Run (_retval); + prompt.GetSelected (aOutSelection); + + return NS_OK; +} + +#if HAVE_NSINONBLOCKINGALERTSERVICE_H + +/* showNonBlockingAlert (in nsIDOMWindow aParent, in wstring aDialogTitle, in wstring aText); */ +NS_IMETHODIMP +GeckoPromptService::ShowNonBlockingAlert (nsIDOMWindow *aParent, + const PRUnichar *aDialogTitle, + const PRUnichar *aText) +{ + Prompter *prompt = new Prompter (GTK_STOCK_DIALOG_INFO, aParent, aDialogTitle, aText); + if (!prompt) return NS_ERROR_OUT_OF_MEMORY; + + prompt->AddStockButton (GTK_STOCK_OK, GTK_RESPONSE_ACCEPT); + prompt->Show (); + + return NS_OK; +} + +#endif /* HAVE_NSINONBLOCKINGALERTSERVICE_H */ diff --git a/embed/xulrunner/src/GeckoPromptService.h b/embed/xulrunner/src/GeckoPromptService.h new file mode 100644 index 000000000..b2ef610b8 --- /dev/null +++ b/embed/xulrunner/src/GeckoPromptService.h @@ -0,0 +1,53 @@ +/* + * Copyright © 2005, 2006 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id$ + */ + +#ifndef GECKO_PROMPT_SERVICE_H +#define GECKO_PROMPT_SERVICE_H + +#include <nsIPromptService.h> + +#if HAVE_NSINONBLOCKINGALERTSERVICE_H +#include <nsINonBlockingAlertService.h> +#endif + +#define GECKO_PROMPT_SERVICE_CID \ +{ /* cadc6035-7c53-4039-823b-004a289d5eb2 */ \ + 0xcadc6035, 0x7c53, 0x4039, \ + { 0x82, 0x3b, 0x00, 0x4a, 0x28, 0x9d, 0x5e, 0xb2 } } + +#define GECKO_PROMPT_SERVICE_CLASSNAME "Gecko Prompt Service" + +class GeckoPromptService : public nsIPromptService +#if HAVE_NSINONBLOCKINGALERTSERVICE_H + , public nsINonBlockingAlertService +#endif +{ + public: + NS_DECL_ISUPPORTS + NS_DECL_NSIPROMPTSERVICE +#if HAVE_NSINONBLOCKINGALERTSERVICE_H + NS_DECL_NSINONBLOCKINGALERTSERVICE +#endif + + GeckoPromptService(); + virtual ~GeckoPromptService(); +}; + +#endif /* GECKO_PROMPT_SERVICE_H */ diff --git a/embed/xulrunner/src/GeckoSingle.cpp b/embed/xulrunner/src/GeckoSingle.cpp new file mode 100644 index 000000000..4b5d8e467 --- /dev/null +++ b/embed/xulrunner/src/GeckoSingle.cpp @@ -0,0 +1,122 @@ +/* + * Copyright © Christopher Blizzard + * Copyright © 2006 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * --------------------------------------------------------------------------- + * Derived from Mozilla.org code, which had the following attributions: + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Christopher Blizzard. Portions created by Christopher Blizzard are Copyright © Christopher Blizzard. All Rights Reserved. + * Portions created by the Initial Developer are Copyright © 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Christopher Blizzard <blizzard@mozilla.org> + * --------------------------------------------------------------------------- + * + * $Id$ + */ + +#include <mozilla-config.h> +#include <config.h> + +#include <stdlib.h> +#include "nsIDocShell.h" +#include "nsIWebProgress.h" +#include "nsIWebBrowserStream.h" +#include "nsIWidget.h" + +// all of our local includes +#include "GeckoSingle.h" +#include "EmbedWindow.h" +#include "gecko-init.h" +#include "gecko-init-private.h" + +GSList *GeckoSingle::sWindowList = nsnull; +PRUint32 GeckoSingle::sWidgetCount = 0; + +GeckoSingle::GeckoSingle() +{ +} + +GeckoSingle::~GeckoSingle() +{ +} + +/* static */ +GeckoBrowser * +GeckoSingle::FindPrivateForBrowser(nsIWebBrowserChrome *aBrowser) +{ + // This function doesn't get called very often at all ( only when + // creating a new window ) so it's OK to walk the list of open + // windows. + for (GSList *l = sWindowList; l != NULL; l = l->next) { + GeckoBrowser *tmpPrivate = static_cast<GeckoBrowser *>(l->data); + // get the browser object for that window + nsIWebBrowserChrome *chrome = static_cast<nsIWebBrowserChrome *> + (tmpPrivate->mWindow); + if (chrome == aBrowser) + return tmpPrivate; + } + + return nsnull; +} + +/* static */ +void +GeckoSingle::ReparentToOffscreen (GtkWidget* aWidget) +{ + gecko_reparent_to_offscreen (aWidget); +} + +/* static */ +void +GeckoSingle::AddBrowser(GeckoBrowser *aBrowser) +{ + PushStartup(); + sWindowList = g_slist_prepend (sWindowList, aBrowser); +} + +/* static */ +void +GeckoSingle::RemoveBrowser(GeckoBrowser *aBrowser) +{ + sWindowList = g_slist_remove (sWindowList, aBrowser); + PopStartup(); +} + +/* static */ +void +GeckoSingle::PushStartup() +{ + GeckoSingle::sWidgetCount++; +} + +/* static */ +void +GeckoSingle::PopStartup() +{ + GeckoSingle::sWidgetCount--; + if (GeckoSingle::sWidgetCount == 0) { + gecko_shutdown(); +#ifdef XPCOM_GLUE + XPCOMGlueShutdown(); +#endif + } +} diff --git a/embed/xulrunner/src/GeckoSingle.h b/embed/xulrunner/src/GeckoSingle.h new file mode 100644 index 000000000..7654d9a9d --- /dev/null +++ b/embed/xulrunner/src/GeckoSingle.h @@ -0,0 +1,97 @@ +/* + * Copyright © Christopher Blizzard + * Copyright © 2006 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * --------------------------------------------------------------------------- + * Derived from Mozilla.org code, which had the following attributions: + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Christopher Blizzard. Portions created by Christopher Blizzard are Copyright © Christopher Blizzard. All Rights Reserved. + * Portions created by the Initial Developer are Copyright © 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Christopher Blizzard <blizzard@mozilla.org> + * --------------------------------------------------------------------------- + * + * $Id$ + */ + +#ifndef __GeckoSingle_h +#define __GeckoSingle_h + +#include <nsCOMPtr.h> +#include <nsEmbedString.h> +#include <nsIWebNavigation.h> +#include <nsISHistory.h> +// for our one function that gets the GeckoSingle via the chrome +// object. +#include <nsIWebBrowserChrome.h> +#include <nsIAppShell.h> +// app component registration +#include <nsIGenericFactory.h> +#include <nsIComponentRegistrar.h> + +#include "gecko-embed-single.h" +#include "gecko-embed.h" + +#include "GeckoBrowser.h" + +class EmbedProfile; +class EmbedProgress; +class EmbedWindow; +class EmbedContentListener; +class EmbedEventListener; + +class nsPIDOMWindow; +class nsIDirectoryServiceProvider; +class nsProfileDirServiceProvider; + +class GeckoSingle +{ + friend class GeckoBrowser; + + public: + + GeckoSingle(); + ~GeckoSingle(); + + static void PushStartup (); + static void PopStartup (); + + // static GeckoSingle* GetInstance(); + + // This function will find the specific GeckoBrowser object for a + // given nsIWebBrowserChrome. + static GeckoBrowser *FindPrivateForBrowser(nsIWebBrowserChrome *aBrowser); + + // the number of widgets that have been created + static PRUint32 sWidgetCount; + // the list of application-specific components to register + static const nsModuleComponentInfo *sAppComps; + static int sNumAppComps; + // the list of all open windows + static GSList *sWindowList; + + static void ReparentToOffscreen (GtkWidget *aWidget); + static void AddBrowser (GeckoBrowser *aBrowser); + static void RemoveBrowser (GeckoBrowser *aBrowser); +}; + +#endif /* __GeckoSingle_h */ diff --git a/embed/xulrunner/src/GeckoUtils.cpp b/embed/xulrunner/src/GeckoUtils.cpp new file mode 100644 index 000000000..b9d6e3f53 --- /dev/null +++ b/embed/xulrunner/src/GeckoUtils.cpp @@ -0,0 +1,87 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright © 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brian Ryner <bryner@brianryner.com> + * + * $Id$ + */ + +#include <mozilla-config.h> +#include "config.h" + +#include "GeckoUtils.h" + +#include "gecko-embed.h" + +#include <nsCOMPtr.h> +#include <nsIDOMWindow.h> +#include <nsIWindowWatcher.h> +#include <nsIWebBrowserChrome.h> +#include <nsIEmbeddingSiteWindow.h> +#include <nsIServiceManager.h> +#include <nsServiceManagerUtils.h> + +GtkWidget * +GeckoUtils::GetGeckoEmbedForDOMWindow (nsIDOMWindow * aDOMWindow) +{ + if (!aDOMWindow) + return NULL; + + /* Get the toplevel DOM window, in case this window is a frame */ + nsCOMPtr<nsIDOMWindow> domWin; + aDOMWindow->GetTop (getter_AddRefs (domWin)); + if (!domWin) + return NULL; + + nsCOMPtr< nsIWindowWatcher> wwatch + (do_GetService ("@mozilla.org/embedcomp/window-watcher;1")); + NS_ENSURE_TRUE (wwatch, NULL); + + nsCOMPtr<nsIWebBrowserChrome> chrome; + wwatch->GetChromeForWindow (domWin, getter_AddRefs (chrome)); + + nsCOMPtr <nsIEmbeddingSiteWindow> siteWindow (do_QueryInterface (chrome)); + if (!siteWindow) + return NULL; + + GtkWidget *widget; + siteWindow->GetSiteWindow ((void **) &widget); + if (!widget || !GECKO_IS_EMBED (widget)) + return NULL; + + return widget; +} + +GtkWidget * +GeckoUtils::GetGtkWindowForDOMWindow (nsIDOMWindow * aDOMWindow) +{ + GtkWidget *embed = GeckoUtils::GetGeckoEmbedForDOMWindow (aDOMWindow); + if (!embed) + return NULL; + + GtkWidget *gtkWin = gtk_widget_get_toplevel (embed); + if (!GTK_WIDGET_TOPLEVEL (gtkWin)) + return NULL; + + return gtkWin; +} diff --git a/embed/xulrunner/src/GeckoUtils.h b/embed/xulrunner/src/GeckoUtils.h new file mode 100644 index 000000000..05012e6b2 --- /dev/null +++ b/embed/xulrunner/src/GeckoUtils.h @@ -0,0 +1,34 @@ +/* + * Copyright © 2006 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id$ + */ + +#ifndef GECKO_UTILS_H +#define GECKO_UTILS_H + +#include <gtk/gtkwidget.h> + +class nsIDOMWindow; + +namespace GeckoUtils +{ + GtkWidget* GetGeckoEmbedForDOMWindow (nsIDOMWindow*); + GtkWidget* GetGtkWindowForDOMWindow (nsIDOMWindow*); +} + +#endif diff --git a/embed/xulrunner/src/Makefile.am b/embed/xulrunner/src/Makefile.am new file mode 100644 index 000000000..a3afed257 --- /dev/null +++ b/embed/xulrunner/src/Makefile.am @@ -0,0 +1,167 @@ +NULL = + +required = \ + . \ + accessibility \ + content \ + embedcomponents \ + docshell \ + dom \ + embed_base \ + gfx \ + intl \ + js \ + layout \ + necko \ + profdirserviceprovider \ + shistory \ + string \ + uriloader \ + webbrwsr \ + webshell \ + widget \ + windowwatcher \ + xpcom \ + xpconnect \ + xulapp \ + $(NULL) + +MARSHALERS = gecko-embed-marshal.h gecko-embed-marshal.cpp +TYPES_SOURCES = gecko-embed-type-builtins.h gecko-embed-type-builtins.cpp + +BUILT_SOURCES= $(MARSHALERS) $(TYPES_SOURCES) + +gecko-embed-marshal.cpp: gecko-embed-marshal.list + $(GLIB_GENMARSHAL) --prefix=gecko_embed_marshal $< --header --body > $@ + +gecko-embed-marshal.h: gecko-embed-marshal.list + $(GLIB_GENMARSHAL) --prefix=gecko_embed_marshal $< --header > $@ + +TYPES_H_FILES = \ + gecko-embed-types.h \ + $(NULL) + +stamp_files = \ + stamp-gecko-embed-type-builtins.cpp \ + stamp-gecko-embed-type-builtins.h \ + $(NULL) + +gecko-embed-type-builtins.cpp: stamp-gecko-embed-type-builtins.cpp Makefile + @true +stamp-gecko-embed-type-builtins.cpp: Makefile $(TYPES_H_FILES) + $(GLIB_MKENUMS) \ + --fhead "#include \"gecko-embed-type-builtins.h\"\n\n" \ + --fprod "\n/* enumerations from \"@filename@\" */" \ + --fprod "\n#include \"@filename@\"" \ + --vhead "GType\n@enum_name@_get_type (void)\n{\n" \ + --vhead " static GType type = 0;\n\n" \ + --vhead " if (G_UNLIKELY (type == 0))\n {\n" \ + --vhead " static const G@Type@Value _@enum_name@_values[] = {" \ + --vprod " { @VALUENAME@, \"@VALUENAME@\", \"@valuenick@\" }," \ + --vtail " { 0, NULL, NULL }\n };\n\n" \ + --vtail " type = g_@type@_register_static (\"@EnumName@\", _@enum_name@_values);\n }\n\n" \ + --vtail " return type;\n}\n\n" \ + $(filter-out $<,$^) > xgen-$(@F) \ + && ( cmp -s xgen-$(@F) $(@F:stamp-%=%) || cp xgen-$(@F) $(@F:stamp-%=%) ) \ + && rm -f xgen-$(@F) \ + && echo timestamp > $(@F) + +gecko-embed-type-builtins.h: stamp-gecko-embed-type-builtins.h Makefile + @true +stamp-gecko-embed-type-builtins.h: Makefile $(TYPES_H_FILES) + $(GLIB_MKENUMS) \ + --fhead "#ifndef GECKO_TYPE_BUILTINS_H\n" \ + --fhead "#define GECKO_TYPE_BUILTINS_H 1\n\n" \ + --fhead "#include <glib-object.h>\n\n" \ + --fhead "G_BEGIN_DECLS\n\n" \ + --ftail "G_END_DECLS\n\n" \ + --ftail "#endif /* GECKO_TYPE_BUILTINS_H */\n" \ + --fprod "\n/* --- @filename@ --- */" \ + --eprod "#define GECKO_TYPE_@ENUMSHORT@ @enum_name@_get_type()\n" \ + --eprod "GType @enum_name@_get_type (void);\n" \ + $(filter-out $<,$^) > xgen-$(@F) \ + && ( cmp -s xgen-$(@F) $(@F:stamp-%=%) || cp xgen-$(@F) $(@F:stamp-%=%) ) \ + && rm -f xgen-$(@F) \ + && echo timestamp > $(@F) + +lib_LTLIBRARIES = libgnomegeckoembed-0.0.la + +libgnomegeckoembed_0_0_la_SOURCES = \ + $(MARSHALERS) \ + $(TYPES_SOURCES) \ + gecko-dom-event.cpp \ + gecko-dom-event.h \ + gecko-dom-event-internal.h \ + gecko-dom-event-private.h \ + gecko-embed.cpp \ + gecko-embed.h \ + gecko-embed-private.h \ + gecko-embed-signals.h \ + gecko-embed-single.cpp \ + gecko-embed-single.h \ + gecko-embed-single-private.h \ + gecko-embed-types.h \ + gecko-init.cpp \ + gecko-init.h \ + gecko-init-internal.h \ + gecko-init-private.h \ + AutoJSContextStack.cpp \ + AutoJSContextStack.h \ + AutoWindowModalState.cpp \ + AutoWindowModalState.h \ + EmbedContentListener.cpp \ + EmbedContentListener.h \ + EmbedEventListener.cpp \ + EmbedEventListener.h \ + EmbedProgress.cpp \ + EmbedProgress.h \ + EmbedWindow.cpp \ + EmbedWindowCreator.cpp \ + EmbedWindowCreator.h \ + EmbedWindow.h \ + GeckoBrowser.cpp \ + GeckoBrowser.h \ + GeckoPromptService.cpp \ + GeckoPromptService.h \ + GeckoSingle.cpp \ + GeckoSingle.h \ + GeckoUtils.cpp \ + GeckoUtils.h \ + $(NULL) + +libgnomegeckoembed_0_0_la_CPPFLAGS = \ + $(addprefix -I$(GECKO_INCLUDE_ROOT)/,$(required)) \ + $(AM_CPPFLAGS) + +# -DDEBUG \ +# -DXPCOM_GLUE +#-DMOZILLA_STRICT_API + +libgnomegeckoembed_0_0_la_CXXFLAGS = \ + $(GGE_DEPENDENCY_CFLAGS) \ + $(GECKO_CFLAGS) \ + $(AM_CXXFLAGS) + +libgnomegeckoembed_0_0_la_LIBADD = \ + $(GGE_DEPENDENCY_LIBS) \ + $(GECKO_LIBS) \ + $(GECKO_EXTRA_LIBS) \ + $(GECKO_GLUE_LIBS) + +libgnomegeckoembed_0_0_la_LDFLAGS = \ + $(AM_LDFLAGS) + +gnomegeckoembedincludedir = $(includedir)/gnome-gecko-embed-0.0 +gnomegeckoembedinclude_HEADERS = + +gnomegeckoembedsubincludedir = $(includedir)/gnome-gecko-embed-0.0/gecko-embed +gnomegeckoembedsubinclude_HEADERS = + +CLEANFILES = \ + $(stamp_files) \ + $(BUILT_SOURCES) \ + $(NULL) + +EXTRA_DIST = \ + gecko-embed-marshal.list \ + $(NULL) diff --git a/embed/xulrunner/src/gecko-dom-event-internal.h b/embed/xulrunner/src/gecko-dom-event-internal.h new file mode 100644 index 000000000..2d0309bd9 --- /dev/null +++ b/embed/xulrunner/src/gecko-dom-event-internal.h @@ -0,0 +1,28 @@ +/* + * Copyright © 2006 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id$ + */ + +#ifndef GECKO_DOM_EVENT_INTERNAL_H +#define GECKO_DOM_EVENT_INTERNAL_H + +class nsIDOMEvent; + +nsIDOMEvent * gecko_dom_event_get_I (GeckoDOMEvent *); + +#endif diff --git a/embed/xulrunner/src/gecko-dom-event-private.h b/embed/xulrunner/src/gecko-dom-event-private.h new file mode 100644 index 000000000..995f8cec0 --- /dev/null +++ b/embed/xulrunner/src/gecko-dom-event-private.h @@ -0,0 +1,38 @@ +/* + * Copyright © 2006 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id$ + */ + +#ifndef GECKO_DOM_EVENT_PRIVATE_H +#define GECKO_DOM_EVENT_PRIVATE_H + +struct _GeckoDOMEvent { + nsIDOMEvent *mEvent; +}; + +class nsIDOMEvent; + +#define GECKO_DOM_EVENT_STATIC_INIT(aEvent,aDOMEvent) \ +{ aEvent.mEvent = aDOMEvent; } + +#define GECKO_DOM_EVENT_STATIC_DEINIT(aEvent) \ +{ } + +GeckoDOMEvent *gecko_dom_event_new (nsIDOMEvent *); + +#endif diff --git a/embed/xulrunner/src/gecko-dom-event.cpp b/embed/xulrunner/src/gecko-dom-event.cpp new file mode 100644 index 000000000..2acdac583 --- /dev/null +++ b/embed/xulrunner/src/gecko-dom-event.cpp @@ -0,0 +1,78 @@ +/* + * Copyright © 2006 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id$ + */ + +#include <mozilla-config.h> +#include "config.h" + +#include "gecko-dom-event.h" +#include "gecko-dom-event-internal.h" +#include "gecko-dom-event-private.h" + +#include <nsIDOMEvent.h> + +/* GType implementation */ + +GType +gecko_dom_event_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + type = g_boxed_type_register_static + ("GeckoDOMEvent", + (GBoxedCopyFunc) gecko_dom_event_copy, + (GBoxedFreeFunc) gecko_dom_event_free); + } + + return type; +} + +/* Public API */ + +GeckoDOMEvent * +gecko_dom_event_new (nsIDOMEvent *aEvent) +{ + /* FIXME use slice alloc */ + GeckoDOMEvent *event = g_new (GeckoDOMEvent, 1); + + NS_ADDREF (event->mEvent = aEvent); + + return event; +} + +GeckoDOMEvent * +gecko_dom_event_copy (GeckoDOMEvent *aEvent) +{ + return gecko_dom_event_new (aEvent->mEvent); +} + +void +gecko_dom_event_free (GeckoDOMEvent *aEvent) +{ + NS_RELEASE (aEvent->mEvent); + /* FIXME slice alloc */ + g_free (aEvent); +} + +nsIDOMEvent * +gecko_dom_event_get_I (GeckoDOMEvent *aEvent) +{ + return aEvent->mEvent; +} diff --git a/embed/xulrunner/src/gecko-dom-event.h b/embed/xulrunner/src/gecko-dom-event.h new file mode 100644 index 000000000..ee1a40768 --- /dev/null +++ b/embed/xulrunner/src/gecko-dom-event.h @@ -0,0 +1,40 @@ +/* + * Copyright © 2006 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id$ + */ + +#ifndef GECKO_DOM_EVENT_H +#define GECKO_DOM_EVENT_H + +#include <glib-object.h> + +G_BEGIN_DECLS + +#define GECKO_TYPE_DOM_EVENT (gecko_dom_event_get_type ()) + +typedef struct _GeckoDOMEvent GeckoDOMEvent; + +GType gecko_dom_event_get_type (void); + +GeckoDOMEvent * gecko_dom_event_copy (GeckoDOMEvent *); + +void gecko_dom_event_free (GeckoDOMEvent *); + +G_END_DECLS + +#endif diff --git a/embed/xulrunner/src/gecko-embed-marshal.list b/embed/xulrunner/src/gecko-embed-marshal.list new file mode 100644 index 000000000..f32b027a6 --- /dev/null +++ b/embed/xulrunner/src/gecko-embed-marshal.list @@ -0,0 +1,10 @@ +BOOLEAN:BOXED +BOOLEAN:POINTER +BOOLEAN:STRING +VOID:INT,INT +VOID:INT,UINT +VOID:OBJECT,UINT +VOID:POINTER,INT,POINTER +VOID:POINTER,UINT +VOID:STRING,INT,INT +VOID:STRING,INT,UINT diff --git a/embed/xulrunner/src/gecko-embed-private.h b/embed/xulrunner/src/gecko-embed-private.h new file mode 100644 index 000000000..8f3fcae09 --- /dev/null +++ b/embed/xulrunner/src/gecko-embed-private.h @@ -0,0 +1,54 @@ +/* + * Copyright © Christopher Blizzard + * Copyright © 2006 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * --------------------------------------------------------------------------- + * Derived from Mozilla.org code, which had the following attributions: + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Christopher Blizzard. Portions created by Christopher Blizzard are Copyright © Christopher Blizzard. All Rights Reserved. + * Portions created by the Initial Developer are Copyright © 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Christopher Blizzard <blizzard@mozilla.org> + * --------------------------------------------------------------------------- + * + * $Id$ + */ + +#ifndef gecko_embed_private_h +#define gecko_embed_private_h + +#include "gecko-embed.h" + +class nsIWebBrowser; +class GeckoBrowser; + +G_BEGIN_DECLS + +extern void gecko_embed_get_nsIWebBrowser (GeckoEmbed *embed, + nsIWebBrowser **retval); + +extern GeckoBrowser* gecko_embed_get_GeckoBrowser (GeckoEmbed *embed); + + +G_END_DECLS + +#endif /* gecko_embed_private_h */ diff --git a/embed/xulrunner/src/gecko-embed-signals.h b/embed/xulrunner/src/gecko-embed-signals.h new file mode 100644 index 000000000..d5d67b351 --- /dev/null +++ b/embed/xulrunner/src/gecko-embed-signals.h @@ -0,0 +1,82 @@ +/* + * Copyright © Christopher Blizzard + * Copyright © 2006 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * --------------------------------------------------------------------------- + * Derived from Mozilla.org code, which had the following attributions: + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Christopher Blizzard. Portions created by Christopher Blizzard are Copyright © Christopher Blizzard. All Rights Reserved. + * Portions created by the Initial Developer are Copyright © 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Christopher Blizzard <blizzard@mozilla.org> + * --------------------------------------------------------------------------- + * + * $Id$ + */ + +#ifndef gecko_embed_signals_h +#define gecko_embed_signals_h + +#include <glib.h> + +G_BEGIN_DECLS + +typedef enum { + DOM_KEY_DOWN, + DOM_KEY_PRESS, + DOM_KEY_UP, + DOM_MOUSE_DOWN, + DOM_MOUSE_UP, + DOM_MOUSE_CLICK, + DOM_MOUSE_DOUBLE_CLICK, + DOM_MOUSE_OVER, + DOM_MOUSE_OUT, + DOM_ACTIVATE, + DOM_FOCUS_IN, + DOM_FOCUS_OUT, + DOM_CONTEXT_MENU, + + LINK_MESSAGE, + JS_STATUS, + LOCATION, + TITLE, + PROGRESS, + PROGRESS_ALL, + NET_STATE, + NET_STATE_ALL, + NET_START, + NET_STOP, + NEW_WINDOW, + VISIBILITY, + DESTROY_BROWSER, + OPEN_URI, + SIZE_TO, + SECURITY_CHANGE, + STATUS_CHANGE, + LAST_EMBED_SIGNAL +} GeckoEmbedSignals; + +extern guint gecko_embed_signals[LAST_EMBED_SIGNAL]; + +G_END_DECLS + +#endif /* gecko_embed_signals_h */ diff --git a/embed/xulrunner/src/gecko-embed-single-private.h b/embed/xulrunner/src/gecko-embed-single-private.h new file mode 100644 index 000000000..df2202da3 --- /dev/null +++ b/embed/xulrunner/src/gecko-embed-single-private.h @@ -0,0 +1,59 @@ +/* + * Copyright © Christopher Blizzard + * Copyright © 2006 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * --------------------------------------------------------------------------- + * Derived from Mozilla.org code, which had the following attributions: + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Christopher Blizzard. Portions created by Christopher Blizzard are Copyright © Christopher Blizzard. All Rights Reserved. + * Portions created by the Initial Developer are Copyright © 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Christopher Blizzard <blizzard@mozilla.org> + * --------------------------------------------------------------------------- + * + * $Id$ + */ + +#ifndef gecko_embed_single_private_h +#define gecko_embed_single_private_h + +#include "gecko-embed-single.h" + +class GeckoSingle; +class nsIDirectoryServiceProvider; +struct nsModuleComponentInfo; + +G_BEGIN_DECLS + +extern GeckoSingle* gecko_embed_single_get_GeckoSingle (void); + +extern void gecko_embed_single_set_directory_service_provider (nsIDirectoryServiceProvider *aProvider); + +extern void gecko_embed_single_set_app_components (const nsModuleComponentInfo *aComps, + int aNumComps); + +extern void gecko_embed_single_create_window (GeckoEmbed **aNewEmbed, + guint aChromeFlags); + +G_END_DECLS + +#endif /* gecko_embed_single_private_h */ diff --git a/embed/xulrunner/src/gecko-embed-single.cpp b/embed/xulrunner/src/gecko-embed-single.cpp new file mode 100644 index 000000000..dd147e512 --- /dev/null +++ b/embed/xulrunner/src/gecko-embed-single.cpp @@ -0,0 +1,182 @@ +/* + * Copyright © Christopher Blizzard + * Copyright © Ramiro Estrugo + * Copyright © 2006 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * --------------------------------------------------------------------------- + * Derived from Mozilla.org code, which had the following attributions: + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Christopher Blizzard. Portions created by Christopher Blizzard are Copyright © Christopher Blizzard. All Rights Reserved. + * Portions created by the Initial Developer are Copyright © 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Christopher Blizzard <blizzard@mozilla.org> + * Ramiro Estrugo <ramiro@eazel.com> + * --------------------------------------------------------------------------- + * + * $Id$ + */ + +#include <mozilla-config.h> +#include "config.h" + +#include "gecko-embed-single.h" +#include "gecko-embed-private.h" +#include "gecko-embed-signals.h" +#include "gecko-embed-marshal.h" + +#include "GeckoSingle.h" + +#define GECKO_EMBED_SINGLE_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), GECKO_TYPE_EMBED_SINGLE, GeckoEmbedSinglePrivate)) + +struct _GeckoEmbedSinglePrivate +{ + GeckoSingle *single; +}; + +enum +{ + NEW_WINDOW_ORPHAN, + LAST_SINGLE_SIGNAL +}; + +static guint gecko_embed_single_signals[LAST_SINGLE_SIGNAL] = { 0 }; + +static void gecko_embed_single_class_init (GeckoEmbedSingleClass *klass); +static void gecko_embed_single_init (GeckoEmbedSingle *embed); + +static GObjectClass *parent_class = NULL; + +GType +gecko_embed_single_get_type(void) +{ + static GType type = 0; + + if (!type) + { + const GTypeInfo info = + { + sizeof (GeckoEmbedSingleClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) gecko_embed_single_class_init, + NULL, + NULL, /* class_data */ + sizeof (GeckoEmbedSingle), + 0, /* n_preallocs */ + (GInstanceInitFunc) gecko_embed_single_init + }; + + type = g_type_register_static (G_TYPE_OBJECT, "GeckoEmbedSingle", + &info, (GTypeFlags) 0); + } + + return type; +} + +GeckoEmbedSingle * +gecko_embed_single_get (void) +{ + static GeckoEmbedSingle *single = NULL; + + if (!single) + { + single = GECKO_EMBED_SINGLE (g_object_new (GECKO_TYPE_EMBED_SINGLE, NULL)); + + g_object_add_weak_pointer (G_OBJECT (single), (gpointer *) &single); + } + + return single; +} + +extern "C" void +gecko_embed_single_create_window (GeckoEmbed **aNewEmbed, + guint aChromeFlags) +{ + GeckoEmbedSingle *single = gecko_embed_single_get (); + + *aNewEmbed = nsnull; + + if (!single) + return; + + g_signal_emit (single, gecko_embed_single_signals[NEW_WINDOW_ORPHAN], 0, + (void **) aNewEmbed, aChromeFlags); +} + +void +gecko_embed_single_push_startup(void) +{ + GeckoEmbedSingle *single = gecko_embed_single_get (); + + single->priv->single->PushStartup(); +} + +void +gecko_embed_single_pop_startup(void) +{ + GeckoEmbedSingle *single = gecko_embed_single_get (); + + single->priv->single->PopStartup(); +} + +static void +gecko_embed_single_init(GeckoEmbedSingle *embed) +{ + embed->priv = GECKO_EMBED_SINGLE_GET_PRIVATE (embed); + + embed->priv->single = new GeckoSingle (); +} + +static void +gecko_embed_single_finalize (GObject *object) +{ + GeckoEmbedSingle *single = GECKO_EMBED_SINGLE (object); + + delete single->priv->single; + single->priv->single = nsnull; + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gecko_embed_single_class_init (GeckoEmbedSingleClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = (GObjectClass *) g_type_class_peek_parent (klass); + + object_class->finalize = gecko_embed_single_finalize; + + gecko_embed_single_signals[NEW_WINDOW] = + g_signal_new ("new_window_orphan", + GECKO_TYPE_EMBED_SINGLE, + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GeckoEmbedSingleClass, new_window_orphan), + NULL, NULL, + gecko_embed_marshal_VOID__OBJECT_UINT, + G_TYPE_NONE, + 2, + G_TYPE_OBJECT, + G_TYPE_UINT); + + g_type_class_add_private (object_class, sizeof (GeckoEmbedSinglePrivate)); +} diff --git a/embed/xulrunner/src/gecko-embed-single.h b/embed/xulrunner/src/gecko-embed-single.h new file mode 100644 index 000000000..66554f68b --- /dev/null +++ b/embed/xulrunner/src/gecko-embed-single.h @@ -0,0 +1,88 @@ +/* + * Copyright © Christopher Blizzard + * Copyright © Ramiro Estrugo + * Copyright © 2006 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * --------------------------------------------------------------------------- + * Derived from Mozilla.org code, which had the following attributions: + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Christopher Blizzard. Portions created by Christopher Blizzard are Copyright © Christopher Blizzard. All Rights Reserved. + * Portions created by the Initial Developer are Copyright © 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Christopher Blizzard <blizzard@mozilla.org> + * Ramiro Estrugo <ramiro@eazel.com> + * --------------------------------------------------------------------------- + * + * $Id$ + */ + +#ifndef gecko_embed_single_h +#define gecko_embed_single_h + +#include "gecko-embed-type-builtins.h" +#include <glib-object.h> + +G_BEGIN_DECLS + +#define GECKO_TYPE_EMBED_SINGLE (gecko_embed_single_get_type()) +#define GECKO_EMBED_SINGLE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GECKO_TYPE_EMBED_SINGLE, GeckoEmbedSingle)) +#define GECKO_EMBED_SINGLE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GECKO_TYPE_EMBED_SINGLE, GeckoEmbedSingleClass)) +#define GECKO_IS_EMBED_SINGLE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GECKO_TYPE_EMBED_SINGLE)) +#define GECKO_IS_EMBED_SINGLE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GECKO_TYPE_EMBED_SINGLE)) +#define GECKO_EMBED_SINGLE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GECKO_TYPE_EMBED_SINGLE, GeckoEmbedSingleClass)) + +typedef struct _GeckoEmbedSingle GeckoEmbedSingle; +typedef struct _GeckoEmbedSinglePrivate GeckoEmbedSinglePrivate; +typedef struct _GeckoEmbedSingleClass GeckoEmbedSingleClass; + +/* circular dependency */ +#include "gecko-embed.h" + +struct _GeckoEmbedSingle +{ + GObject parent_instance; + + /*< private >*/ + GeckoEmbedSinglePrivate *priv; +}; + +struct _GeckoEmbedSingleClass +{ + GObjectClass parent_class; + + void (* new_window_orphan) (GeckoEmbedSingle *single, + GeckoEmbed **newEmbed, + guint chromemask); +}; + +GType gecko_embed_single_get_type (void); + +GeckoEmbedSingle *gecko_embed_single_get (void); + +void gecko_embed_single_push_startup (void); + +void gecko_embed_single_pop_startup (void); + + +G_END_DECLS + +#endif /* gecko_embed_single_h */ diff --git a/embed/xulrunner/src/gecko-embed-types.h b/embed/xulrunner/src/gecko-embed-types.h new file mode 100644 index 000000000..c0cb1b71e --- /dev/null +++ b/embed/xulrunner/src/gecko-embed-types.h @@ -0,0 +1,118 @@ +/* + * Copyright © Christopher Blizzard + * Copyright © 2006 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * --------------------------------------------------------------------------- + * Derived from Mozilla.org code, which had the following attributions: + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Christopher Blizzard. Portions created by Christopher Blizzard are Copyright © Christopher Blizzard. All Rights Reserved. + * Portions created by the Initial Developer are Copyright © 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Christopher Blizzard <blizzard@mozilla.org> + * Ramiro Estrugo <ramiro@eazel.com> + * --------------------------------------------------------------------------- + * + * $Id$ + */ + +#ifndef __GECKO_EMBED_TYPES_H__ +#define __GECKO_EMBED_TYPES_H__ + +#include <glib-object.h> +#include "gecko-embed-type-builtins.h" + +G_BEGIN_DECLS + +/* These are straight out of nsIWebProgressListener.h */ + +typedef enum +{ + GECKO_EMBED_FLAG_START = 1U << 0, + GECKO_EMBED_FLAG_REDIRECTING = 1U << 1, + GECKO_EMBED_FLAG_TRANSFERRING = 1U << 2, + GECKO_EMBED_FLAG_NEGOTIATING = 1U << 3, + GECKO_EMBED_FLAG_STOP = 1U << 4, + + GECKO_EMBED_FLAG_IS_REQUEST = 1U << 16, + GECKO_EMBED_FLAG_IS_DOCUMENT = 1U << 17, + GECKO_EMBED_FLAG_IS_NETWORK = 1U << 18, + GECKO_EMBED_FLAG_IS_WINDOW = 1U << 19, + + GECKO_EMBED_FLAG_RESTORING = 1U << 24, +} GeckoEmbedProgressFlags; + +/* These are from various networking headers */ + +typedef enum +{ + /* NS_ERROR_UNKNOWN_HOST */ + GECKO_EMBED_STATUS_FAILED_DNS = 2152398878U, + /* NS_ERROR_CONNECTION_REFUSED */ + GECKO_EMBED_STATUS_FAILED_CONNECT = 2152398861U, + /* NS_ERROR_NET_TIMEOUT */ + GECKO_EMBED_STATUS_FAILED_TIMEOUT = 2152398862U, + /* NS_BINDING_ABORTED */ + GECKO_EMBED_STATUS_FAILED_USERCANCELED = 2152398850U +} GeckoEmbedStatusEnum; + +/* These used to be straight out of nsIWebNavigation.h until the API + changed. Now there's a mapping table that maps these values to the + internal values. */ + +typedef enum +{ + GECKO_EMBED_FLAG_RELOADNORMAL = 0, + GECKO_EMBED_FLAG_RELOADBYPASSCACHE = 1, + GECKO_EMBED_FLAG_RELOADBYPASSPROXY = 2, + GECKO_EMBED_FLAG_RELOADBYPASSPROXYANDCACHE = 3, + GECKO_EMBED_FLAG_RELOADCHARSETCHANGE = 4 +} GeckoEmbedReloadFlags; + +/* These are straight out of nsIWebBrowserChrome.h */ + +typedef enum +{ + GECKO_EMBED_FLAG_DEFAULTCHROME = 1U << 0, + GECKO_EMBED_FLAG_WINDOWBORDERSON = 1U << 1, + GECKO_EMBED_FLAG_WINDOWCLOSEON = 1U << 2, + GECKO_EMBED_FLAG_WINDOWRESIZEON = 1U << 3, + GECKO_EMBED_FLAG_MENUBARON = 1U << 4, + GECKO_EMBED_FLAG_TOOLBARON = 1U << 5, + GECKO_EMBED_FLAG_LOCATIONBARON = 1U << 6, + GECKO_EMBED_FLAG_STATUSBARON = 1U << 7, + GECKO_EMBED_FLAG_PERSONALTOOLBARON = 1U << 8, + GECKO_EMBED_FLAG_SCROLLBARSON = 1U << 9, + GECKO_EMBED_FLAG_TITLEBARON = 1U << 10, + GECKO_EMBED_FLAG_EXTRACHROMEON = 1U << 11, + GECKO_EMBED_FLAG_ALLCHROME = 1U << 12, + GECKO_EMBED_FLAG_WINDOWRAISED = 1U << 25, + GECKO_EMBED_FLAG_WINDOWLOWERED = 1U << 26, + GECKO_EMBED_FLAG_CENTERSCREEN = 1U << 27, + GECKO_EMBED_FLAG_DEPENDENT = 1U << 28, + GECKO_EMBED_FLAG_MODAL = 1U << 29, + GECKO_EMBED_FLAG_OPENASDIALOG = 1U << 30, + GECKO_EMBED_FLAG_OPENASCHROME = 1U << 31, +} GeckoEmbedChromeFlags; + +G_END_DECLS + +#endif /* !__GECKO_EMBED_TYPES_H__ */ diff --git a/embed/xulrunner/src/gecko-embed.cpp b/embed/xulrunner/src/gecko-embed.cpp new file mode 100644 index 000000000..1db324c44 --- /dev/null +++ b/embed/xulrunner/src/gecko-embed.cpp @@ -0,0 +1,1029 @@ +/* + * Copyright © Christopher Blizzard + * Copyright © Ramiro Estrugo + * Copyright © 2006 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * --------------------------------------------------------------------------- + * Derived from Mozilla.org code, which had the following attributions: + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Christopher Blizzard. Portions created by Christopher Blizzard are Copyright © Christopher Blizzard. All Rights Reserved. + * Portions created by the Initial Developer are Copyright © 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Christopher Blizzard <blizzard@mozilla.org> + * Ramiro Estrugo <ramiro@eazel.com> + * --------------------------------------------------------------------------- + * + * $Id$ + */ + +#include <mozilla-config.h> +#include "config.h" + +#include "gecko-embed.h" +#include "gecko-embed-private.h" +#include "gecko-embed-signals.h" +#include "gecko-embed-marshal.h" +#include "gecko-embed-single.h" +#include "gecko-embed-types.h" + +#include "gecko-dom-event.h" + +#include "GeckoBrowser.h" +#include "EmbedWindow.h" + +#ifdef XPCOM_GLUE +#include "nsXPCOMGlue.h" +#endif + +// so we can do our get_nsIWebBrowser later... +#include <nsIWebBrowser.h> + +#include <stdio.h> + +#define GET_OBJECT_CLASS_TYPE(x) G_OBJECT_CLASS_TYPE(x) + +class nsIDirectoryServiceProvider; + +// class and instance initialization + +static void gecko_embed_class_init (GeckoEmbedClass *klass); +static void gecko_embed_init (GeckoEmbed *embed); + +// GtkObject methods + +static void gecko_embed_destroy(GtkObject *object); + +// GtkWidget methods + +static void gecko_embed_realize(GtkWidget *widget); + +static void gecko_embed_unrealize(GtkWidget *widget); + +static void gecko_embed_size_allocate(GtkWidget *widget, GtkAllocation *allocation); + +static void gecko_embed_map(GtkWidget *widget); + +static void gecko_embed_unmap(GtkWidget *widget); + +#ifdef MOZ_ACCESSIBILITY_ATK +static AtkObject* gecko_embed_get_accessible (GtkWidget *widget); +#endif + +static gint handle_child_focus_in(GtkWidget *aWidget, + GdkEventFocus *aGdkFocusEvent, + GeckoEmbed *aEmbed); + +static gint handle_child_focus_out(GtkWidget *aWidget, + GdkEventFocus *aGdkFocusEvent, + GeckoEmbed *aEmbed); + +static PRInt32 sWidgetCount; + +// globals for this type of widget + +static GtkBinClass *parent_class; + +guint gecko_embed_signals[LAST_EMBED_SIGNAL] = { 0 }; + +// GtkObject + class-related functions + +#define GECKO_EMBED_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), GECKO_TYPE_EMBED, GeckoEmbedPrivate)) + +struct _GeckoEmbedPrivate +{ + GeckoBrowser *browser; +}; + +GType +gecko_embed_get_type(void) +{ + static GType type = 0; + + if (!type) + { + const GTypeInfo info = + { + sizeof (GeckoEmbedClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) gecko_embed_class_init, + NULL, + NULL, /* class_data */ + sizeof (GeckoEmbed), + 0, /* n_preallocs */ + (GInstanceInitFunc) gecko_embed_init + }; + + type = g_type_register_static (GTK_TYPE_BIN, "GeckoEmbed", + &info, (GTypeFlags) 0); + } + + return type; +} + + +/* GObject methods */ + +#define GET_BROWSER(x) (((GeckoEmbed *) x)->priv->browser) + +// FIXME split in dispose and finalize +static void +gecko_embed_destroy(GtkObject *object) +{ + GeckoEmbed *embed = GECKO_EMBED (object); + GeckoBrowser *browser = GET_BROWSER (object); + + if (browser) { + + // Destroy the widget only if it's been Init()ed. + if(browser->mMozWindowWidget != 0) { + browser->Destroy(); + } + + delete browser; + embed->priv->browser = NULL; + } + + gecko_embed_single_pop_startup(); +} + +// GtkWidget methods + +static void +gecko_embed_realize(GtkWidget *widget) +{ + GeckoEmbed *embed = GECKO_EMBED (widget); + GeckoEmbedPrivate *priv = embed->priv; + GeckoBrowser *browser = GET_BROWSER (widget); + GtkWidget *toplevel = gtk_widget_get_toplevel (widget); + GdkWindowAttr attributes; + int attributes_mask; + + GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED); + + attributes.window_type = GDK_WINDOW_CHILD; + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK; + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + + widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), + &attributes, attributes_mask); + gdk_window_set_user_data (widget->window, embed); + + widget->style = gtk_style_attach (widget->style, widget->window); + gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL); + + // initialize the window + nsresult rv; + rv = browser->Init(embed); + g_return_if_fail(NS_SUCCEEDED(rv)); + + PRBool alreadyRealized = PR_FALSE; + rv = browser->Realize(&alreadyRealized); + g_return_if_fail(NS_SUCCEEDED(rv)); + + // if we're already realized we don't need to hook up to anything below + if (alreadyRealized) + return; + + browser->LoadCurrentURI(); + + GtkWidget *child_widget = GTK_BIN (widget)->child; + g_signal_connect_object (child_widget, "focus_in_event", + G_CALLBACK (handle_child_focus_in), embed, + (GConnectFlags) 0); + g_signal_connect_object (child_widget, "focus_out_event", + G_CALLBACK (handle_child_focus_out), embed, + (GConnectFlags) 0); +#if 0 + // connect to the focus out event for the child + gtk_signal_connect_while_alive(GTK_OBJECT(child_widget), + "focus_out_event", + GTK_SIGNAL_FUNC(handle_child_focus_out), + embed, + GTK_OBJECT(child_widget)); + gtk_signal_connect_while_alive(GTK_OBJECT(child_widget), + "focus_in_event", + GTK_SIGNAL_FUNC(handle_child_focus_in), + embed, + GTK_OBJECT(child_widget)); +#endif +} + +static void +gecko_embed_unrealize(GtkWidget *widget) +{ + GeckoEmbed *embed = GECKO_EMBED (widget); + GeckoEmbedPrivate *priv = embed->priv; + GeckoBrowser *browser = GET_BROWSER (widget); + GtkWidget *toplevel = gtk_widget_get_toplevel (widget); + + if (browser) { + browser->Unrealize(); + } + + if (GTK_WIDGET_CLASS(parent_class)->unrealize) + GTK_WIDGET_CLASS(parent_class)->unrealize (widget); +} + +static void +gecko_embed_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GeckoEmbed *embed = GECKO_EMBED (widget); + GeckoBrowser *browser = GET_BROWSER (widget); + + widget->allocation = *allocation; + + if (GTK_WIDGET_REALIZED(widget)) + { + gdk_window_move_resize(widget->window, + allocation->x, allocation->y, + allocation->width, allocation->height); + + browser->Resize(allocation->width, allocation->height); + } +} + +static void +gecko_embed_map (GtkWidget *widget) +{ + GeckoEmbed *embed = GECKO_EMBED (widget); + GeckoBrowser *browser = GET_BROWSER (widget); + + GTK_WIDGET_SET_FLAGS(widget, GTK_MAPPED); + + browser->Show(); + + gdk_window_show(widget->window); + +} + +static void +gecko_embed_unmap (GtkWidget *widget) +{ + GeckoEmbed *embed = GECKO_EMBED (widget); + GeckoBrowser *browser = GET_BROWSER (widget); + + GTK_WIDGET_UNSET_FLAGS(widget, GTK_MAPPED); + + gdk_window_hide(widget->window); + + browser->Hide(); +} + +#ifdef MOZ_ACCESSIBILITY_ATK +static AtkObject* +gecko_embed_get_accessible (GtkWidget *widget) +{ + GeckoEmbed *embed = GECKO_EMBED (widget); + GeckoBrowser *browser = GET_BROWSER (widget); + + return static_cast<AtkObject *> + (browser->GetAtkObjectForCurrentDocument()); +} +#endif /* MOZ_ACCESSIBILITY_ATK */ + +static gint +handle_child_focus_in (GtkWidget *aWidget, + GdkEventFocus *aGdkFocusEvent, + GeckoEmbed *aEmbed) +{ + GeckoBrowser *browser = GET_BROWSER (aEmbed); + + browser->ChildFocusIn(); + + return FALSE; +} + +static gint +handle_child_focus_out (GtkWidget *aWidget, + GdkEventFocus *aGdkFocusEvent, + GeckoEmbed *aEmbed) +{ + GeckoBrowser *browser = GET_BROWSER (aEmbed); + + browser->ChildFocusOut(); + + return FALSE; +} + +// Widget methods + +void +gecko_embed_load_url (GeckoEmbed *embed, + const char *url) +{ + GeckoBrowser *browser; + + g_return_if_fail(embed != NULL); + g_return_if_fail(GECKO_IS_EMBED(embed)); + + browser = GET_BROWSER (embed); + + browser->SetURI(url); + + // If the widget is realized, load the URI. If it isn't then we + // will load it later. + if (GTK_WIDGET_REALIZED(embed)) + browser->LoadCurrentURI(); +} + +void +gecko_embed_stop_load (GeckoEmbed *embed) +{ + GeckoBrowser *browser; + + g_return_if_fail(GECKO_IS_EMBED(embed)); + + browser = GET_BROWSER (embed); + + if (browser->mNavigation) + browser->mNavigation->Stop(nsIWebNavigation::STOP_ALL); +} + +gboolean +gecko_embed_can_go_back (GeckoEmbed *embed) +{ + PRBool retval = PR_FALSE; + GeckoBrowser *browser; + + g_return_val_if_fail (GECKO_IS_EMBED(embed), FALSE); + + browser = GET_BROWSER (embed); + + if (browser->mNavigation) + browser->mNavigation->GetCanGoBack(&retval); + return retval; +} + +gboolean +gecko_embed_can_go_forward (GeckoEmbed *embed) +{ + PRBool retval = PR_FALSE; + GeckoBrowser *browser; + + g_return_val_if_fail (GECKO_IS_EMBED(embed), FALSE); + + browser = GET_BROWSER (embed); + + if (browser->mNavigation) + browser->mNavigation->GetCanGoForward(&retval); + return retval; +} + +void +gecko_embed_go_back (GeckoEmbed *embed) +{ + GeckoBrowser *browser; + + g_return_if_fail (GECKO_IS_EMBED(embed)); + + browser = GET_BROWSER (embed); + + if (browser->mNavigation) + browser->mNavigation->GoBack(); +} + +void +gecko_embed_go_forward (GeckoEmbed *embed) +{ + GeckoBrowser *browser; + + g_return_if_fail (GECKO_IS_EMBED(embed)); + + browser = GET_BROWSER (embed); + + if (browser->mNavigation) + browser->mNavigation->GoForward(); +} + +void +gecko_embed_render_data (GeckoEmbed *embed, const char *data, + guint32 len, const char *base_uri, + const char *mime_type) +{ + GeckoBrowser *browser; + + g_return_if_fail (GECKO_IS_EMBED(embed)); + + browser = GET_BROWSER (embed); + +#if 0 + browser->OpenStream(base_uri, mime_type); + browser->AppendToStream(data, len); + browser->CloseStream(); +#endif +} + +void +gecko_embed_open_stream (GeckoEmbed *embed, const char *base_uri, + const char *mime_type) +{ + GeckoBrowser *browser; + + g_return_if_fail (GECKO_IS_EMBED(embed)); + g_return_if_fail (GTK_WIDGET_REALIZED(GTK_WIDGET(embed))); + + browser = GET_BROWSER (embed); + +#if 0 + browser->OpenStream(base_uri, mime_type); +#endif +} + +void gecko_embed_append_data (GeckoEmbed *embed, const char *data, + guint32 len) +{ + GeckoBrowser *browser; + + g_return_if_fail (GECKO_IS_EMBED(embed)); + g_return_if_fail (GTK_WIDGET_REALIZED(GTK_WIDGET(embed))); + + browser = GET_BROWSER (embed); +#if 0 + browser->AppendToStream(data, len); +#endif +} + +void +gecko_embed_close_stream (GeckoEmbed *embed) +{ + GeckoBrowser *browser; + + g_return_if_fail (GECKO_IS_EMBED(embed)); + g_return_if_fail (GTK_WIDGET_REALIZED(GTK_WIDGET(embed))); + + browser = GET_BROWSER (embed); +#if 0 + browser->CloseStream(); +#endif +} + +char * +gecko_embed_get_link_message (GeckoEmbed *embed) +{ + char *retval = nsnull; + GeckoBrowser *browser; + nsEmbedCString tmpCString; + + g_return_val_if_fail (GECKO_IS_EMBED(embed), (char *)NULL); + + browser = GET_BROWSER (embed); + + if (browser->mWindow) { + NS_UTF16ToCString(browser->mWindow->mLinkMessage, + NS_CSTRING_ENCODING_UTF8, tmpCString); + retval = g_strdup(tmpCString.get()); + } + + return retval; +} + +char * +gecko_embed_get_js_status (GeckoEmbed *embed) +{ + char *retval = nsnull; + GeckoBrowser *browser; + nsEmbedCString tmpCString; + + g_return_val_if_fail (GECKO_IS_EMBED(embed), (char *)NULL); + + browser = GET_BROWSER (embed); + + if (browser->mWindow) { + NS_UTF16ToCString(browser->mWindow->mJSStatus, + NS_CSTRING_ENCODING_UTF8, tmpCString); + retval = g_strdup(tmpCString.get()); + } + + return retval; +} + +char * +gecko_embed_get_title (GeckoEmbed *embed) +{ + char *retval = nsnull; + GeckoBrowser *browser; + nsEmbedCString tmpCString; + + g_return_val_if_fail (GECKO_IS_EMBED(embed), (char *)NULL); + + browser = GET_BROWSER (embed); + + if (browser->mWindow) { + NS_UTF16ToCString(browser->mWindow->mTitle, + NS_CSTRING_ENCODING_UTF8, tmpCString); + retval = g_strdup(tmpCString.get()); + } + + return retval; +} + +char * +gecko_embed_get_location (GeckoEmbed *embed) +{ + char *retval = nsnull; + GeckoBrowser *browser; + + g_return_val_if_fail (GECKO_IS_EMBED(embed), (char *)NULL); + + browser = GET_BROWSER (embed); + + if (browser->mURI.Length()) { + retval = g_strdup(browser->mURI.get()); + } + + return retval; +} + +void +gecko_embed_reload (GeckoEmbed *embed, + gint32 flags) +{ + GeckoBrowser *browser; + + g_return_if_fail (GECKO_IS_EMBED(embed)); + + browser = GET_BROWSER (embed); + + PRUint32 reloadFlags = 0; + + // map the external API to the internal web navigation API. + switch (flags) { + case GECKO_EMBED_FLAG_RELOADNORMAL: + reloadFlags = 0; + break; + case GECKO_EMBED_FLAG_RELOADBYPASSCACHE: + reloadFlags = nsIWebNavigation::LOAD_FLAGS_BYPASS_CACHE; + break; + case GECKO_EMBED_FLAG_RELOADBYPASSPROXY: + reloadFlags = nsIWebNavigation::LOAD_FLAGS_BYPASS_PROXY; + break; + case GECKO_EMBED_FLAG_RELOADBYPASSPROXYANDCACHE: + reloadFlags = (nsIWebNavigation::LOAD_FLAGS_BYPASS_PROXY | + nsIWebNavigation::LOAD_FLAGS_BYPASS_CACHE); + break; + case GECKO_EMBED_FLAG_RELOADCHARSETCHANGE: + reloadFlags = nsIWebNavigation::LOAD_FLAGS_CHARSET_CHANGE; + break; + default: + reloadFlags = 0; + break; + } + + browser->Reload(reloadFlags); +} + +void +gecko_embed_set_chrome_mask (GeckoEmbed *embed, + guint32 flags) +{ + GeckoBrowser *browser; + + g_return_if_fail (GECKO_IS_EMBED(embed)); + + browser = GET_BROWSER (embed); + + browser->SetChromeMask(flags); +} + +guint32 +gecko_embed_get_chrome_mask (GeckoEmbed *embed) +{ + GeckoBrowser *browser; + + g_return_val_if_fail (GECKO_IS_EMBED(embed), 0); + + browser = GET_BROWSER (embed); + + return browser->mChromeMask; +} + +void +gecko_embed_get_nsIWebBrowser (GeckoEmbed *embed, + nsIWebBrowser **retval) +{ + GeckoBrowser *browser; + *retval = nsnull; + + g_return_if_fail (GECKO_IS_EMBED (embed)); + + browser = GET_BROWSER (embed); + + if (browser->mWindow) + browser->mWindow->GetWebBrowser(retval); +} + +GeckoBrowser * +gecko_embed_get_GeckoBrowser (GeckoEmbed *embed) +{ + g_return_val_if_fail (GECKO_IS_EMBED (embed), nsnull); + + return GET_BROWSER (embed); +} + +static void +gecko_embed_init (GeckoEmbed *embed) +{ + embed->priv = GECKO_EMBED_GET_PRIVATE (embed); + + embed->priv->browser = new GeckoBrowser(); + g_return_if_fail (embed->priv->browser); + + gtk_widget_set_name (GTK_WIDGET (embed), "gecko_embed"); + + GTK_WIDGET_UNSET_FLAGS(GTK_WIDGET(embed), GTK_NO_WINDOW); +} + +static void +gecko_embed_class_init (GeckoEmbedClass *klass) +{ + GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass); // FIXME GObject + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass); + + parent_class = (GtkBinClass *) g_type_class_peek_parent (klass); + + object_class->destroy = gecko_embed_destroy; + + widget_class->realize = gecko_embed_realize; + widget_class->unrealize = gecko_embed_unrealize; + widget_class->size_allocate = gecko_embed_size_allocate; + widget_class->map = gecko_embed_map; + widget_class->unmap = gecko_embed_unmap; + +#ifdef MOZ_ACCESSIBILITY_ATK + widget_class->get_accessible = gecko_embed_get_accessible; +#endif + + GType dom_param_types[1] = { GECKO_TYPE_DOM_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE }; + + gecko_embed_signals[DOM_KEY_DOWN] = + g_signal_newv ("dom-key-down", + GECKO_TYPE_EMBED, + (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST), + NULL, + g_signal_accumulator_true_handled, NULL, + gecko_embed_marshal_BOOLEAN__BOXED, + G_TYPE_BOOLEAN, + G_N_ELEMENTS (dom_param_types), + dom_param_types); + + gecko_embed_signals[DOM_KEY_PRESS] = + g_signal_newv ("dom-key-press", + GECKO_TYPE_EMBED, + (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST), + NULL, + g_signal_accumulator_true_handled, NULL, + gecko_embed_marshal_BOOLEAN__BOXED, + G_TYPE_BOOLEAN, + G_N_ELEMENTS (dom_param_types), + dom_param_types); + + gecko_embed_signals[DOM_KEY_UP] = + g_signal_newv ("dom-key-up", + GECKO_TYPE_EMBED, + (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST), + NULL, + g_signal_accumulator_true_handled, NULL, + gecko_embed_marshal_BOOLEAN__BOXED, + G_TYPE_BOOLEAN, + G_N_ELEMENTS (dom_param_types), + dom_param_types); + + gecko_embed_signals[DOM_MOUSE_DOWN] = + g_signal_newv ("dom-mouse-down", + GECKO_TYPE_EMBED, + (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST), + NULL, + g_signal_accumulator_true_handled, NULL, + gecko_embed_marshal_BOOLEAN__BOXED, + G_TYPE_BOOLEAN, + G_N_ELEMENTS (dom_param_types), + dom_param_types); + + gecko_embed_signals[DOM_MOUSE_UP] = + g_signal_newv ("dom-mouse-up", + GECKO_TYPE_EMBED, + (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST), + NULL, + g_signal_accumulator_true_handled, NULL, + gecko_embed_marshal_BOOLEAN__BOXED, + G_TYPE_BOOLEAN, + G_N_ELEMENTS (dom_param_types), + dom_param_types); + + gecko_embed_signals[DOM_MOUSE_CLICK] = + g_signal_newv ("dom-mouse-click", + GECKO_TYPE_EMBED, + (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST), + NULL, + g_signal_accumulator_true_handled, NULL, + gecko_embed_marshal_BOOLEAN__BOXED, + G_TYPE_BOOLEAN, + G_N_ELEMENTS (dom_param_types), + dom_param_types); + + gecko_embed_signals[DOM_MOUSE_DOUBLE_CLICK] = + g_signal_newv ("dom-mouse-dbl-click", + GECKO_TYPE_EMBED, + (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST), + NULL, + g_signal_accumulator_true_handled, NULL, + gecko_embed_marshal_BOOLEAN__BOXED, + G_TYPE_BOOLEAN, + G_N_ELEMENTS (dom_param_types), + dom_param_types); + + gecko_embed_signals[DOM_MOUSE_OVER] = + g_signal_newv ("dom-mouse-over", + GECKO_TYPE_EMBED, + (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST), + NULL, + g_signal_accumulator_true_handled, NULL, + gecko_embed_marshal_BOOLEAN__BOXED, + G_TYPE_BOOLEAN, + G_N_ELEMENTS (dom_param_types), + dom_param_types); + + gecko_embed_signals[DOM_MOUSE_OUT] = + g_signal_newv ("dom-mouse-out", + GECKO_TYPE_EMBED, + (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST), + NULL, + g_signal_accumulator_true_handled, NULL, + gecko_embed_marshal_BOOLEAN__BOXED, + G_TYPE_BOOLEAN, + G_N_ELEMENTS (dom_param_types), + dom_param_types); + + gecko_embed_signals[DOM_MOUSE_OUT] = + g_signal_newv ("dom-focus-in", + GECKO_TYPE_EMBED, + (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST), + NULL, + g_signal_accumulator_true_handled, NULL, + gecko_embed_marshal_BOOLEAN__BOXED, + G_TYPE_BOOLEAN, + G_N_ELEMENTS (dom_param_types), + dom_param_types); + + gecko_embed_signals[DOM_MOUSE_OUT] = + g_signal_newv ("dom-focus-out", + GECKO_TYPE_EMBED, + (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST), + NULL, + g_signal_accumulator_true_handled, NULL, + gecko_embed_marshal_BOOLEAN__BOXED, + G_TYPE_BOOLEAN, + G_N_ELEMENTS (dom_param_types), + dom_param_types); + + gecko_embed_signals[DOM_MOUSE_OUT] = + g_signal_newv ("dom-activate", + GECKO_TYPE_EMBED, + (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST), + NULL, + g_signal_accumulator_true_handled, NULL, + gecko_embed_marshal_BOOLEAN__BOXED, + G_TYPE_BOOLEAN, + G_N_ELEMENTS (dom_param_types), + dom_param_types); + + gecko_embed_signals[DOM_CONTEXT_MENU] = + g_signal_newv ("dom-context-menu", + GECKO_TYPE_EMBED, + (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST), + NULL, + g_signal_accumulator_true_handled, NULL, + gecko_embed_marshal_BOOLEAN__BOXED, + G_TYPE_BOOLEAN, + G_N_ELEMENTS (dom_param_types), + dom_param_types); + + gecko_embed_signals[OPEN_URI] = + g_signal_new ("open_uri", + GECKO_TYPE_EMBED, + (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST), + G_STRUCT_OFFSET (GeckoEmbedClass, open_uri), + g_signal_accumulator_true_handled, NULL, + gecko_embed_marshal_BOOLEAN__STRING, + G_TYPE_BOOLEAN, + 1, + G_TYPE_STRING); + + gecko_embed_signals[NET_START] = + g_signal_new ("net_start", + GECKO_TYPE_EMBED, + (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST), + G_STRUCT_OFFSET (GeckoEmbedClass, net_start), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + + gecko_embed_signals[NET_STOP] = + g_signal_new ("net_stop", + GECKO_TYPE_EMBED, + (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST), + G_STRUCT_OFFSET (GeckoEmbedClass, net_stop), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + + gecko_embed_signals[NET_STATE] = + g_signal_new ("net_state", + GECKO_TYPE_EMBED, + (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST), + G_STRUCT_OFFSET (GeckoEmbedClass, net_state), + NULL, NULL, + gecko_embed_marshal_VOID__INT_UINT, + G_TYPE_NONE, + 2, + G_TYPE_INT, + G_TYPE_UINT); + + gecko_embed_signals[NET_STATE_ALL] = + g_signal_new ("net_state_all", + GECKO_TYPE_EMBED, + (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST), + G_STRUCT_OFFSET (GeckoEmbedClass, net_state_all), + NULL, NULL, + gecko_embed_marshal_VOID__STRING_INT_UINT, + G_TYPE_NONE, + 3, + G_TYPE_STRING, + G_TYPE_INT, + G_TYPE_UINT); // static scope? to avoid string copy? or G_TYPE_POINTER as 1st? + + gecko_embed_signals[PROGRESS] = + g_signal_new ("progress", + GECKO_TYPE_EMBED, + (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST), + G_STRUCT_OFFSET (GeckoEmbedClass, progress), + NULL, NULL, + gecko_embed_marshal_VOID__INT_INT, + G_TYPE_NONE, + 2, + G_TYPE_INT, + G_TYPE_INT); + + gecko_embed_signals[PROGRESS_ALL] = + g_signal_new ("progress_all", + GECKO_TYPE_EMBED, + (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST), + G_STRUCT_OFFSET (GeckoEmbedClass, progress_all), + NULL, NULL, + gecko_embed_marshal_VOID__STRING_INT_INT, + G_TYPE_NONE, + 3, + G_TYPE_STRING, + G_TYPE_INT, + G_TYPE_INT); // static scope? + + gecko_embed_signals[SECURITY_CHANGE] = + g_signal_new ("security_change", + GECKO_TYPE_EMBED, + (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST), + G_STRUCT_OFFSET (GeckoEmbedClass, security_change), + NULL, NULL, + gecko_embed_marshal_VOID__POINTER_UINT, + G_TYPE_NONE, + 2, + G_TYPE_POINTER, + G_TYPE_UINT); + + gecko_embed_signals[STATUS_CHANGE] = + g_signal_new ("status_change", + GECKO_TYPE_EMBED, + (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST), + G_STRUCT_OFFSET (GeckoEmbedClass, status_change), + NULL, NULL, + gecko_embed_marshal_VOID__POINTER_INT_POINTER, + G_TYPE_NONE, + 3, + G_TYPE_POINTER, + G_TYPE_INT, + G_TYPE_POINTER); + + gecko_embed_signals[LINK_MESSAGE] = + g_signal_new ("link_message", + GECKO_TYPE_EMBED, + (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST), + G_STRUCT_OFFSET (GeckoEmbedClass, link_message), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + + gecko_embed_signals[JS_STATUS] = + g_signal_new ("js_status", + GECKO_TYPE_EMBED, + (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST), + G_STRUCT_OFFSET (GeckoEmbedClass, js_status_message), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + + gecko_embed_signals[LOCATION] = + g_signal_new ("location", + GECKO_TYPE_EMBED, + (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST), + G_STRUCT_OFFSET (GeckoEmbedClass, location), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + + gecko_embed_signals[TITLE] = + g_signal_new ("title", + GECKO_TYPE_EMBED, + (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST), + G_STRUCT_OFFSET (GeckoEmbedClass, title), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + + gecko_embed_signals[VISIBILITY] = + g_signal_new ("visibility", + GECKO_TYPE_EMBED, + (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST), + G_STRUCT_OFFSET (GeckoEmbedClass, visibility), + NULL, NULL, + g_cclosure_marshal_VOID__BOOLEAN, + G_TYPE_NONE, + 1, + G_TYPE_BOOLEAN); + + gecko_embed_signals[DESTROY_BROWSER] = + g_signal_new ("destroy_browser", + GECKO_TYPE_EMBED, + (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST), + G_STRUCT_OFFSET (GeckoEmbedClass, destroy_browser), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + + gecko_embed_signals[SIZE_TO] = + g_signal_new ("size_to", + GECKO_TYPE_EMBED, + (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST), + G_STRUCT_OFFSET (GeckoEmbedClass, size_to), + NULL, NULL, + gecko_embed_marshal_VOID__INT_INT, + G_TYPE_NONE, + 2, + G_TYPE_INT, + G_TYPE_INT); + + gecko_embed_signals[NEW_WINDOW] = + g_signal_new ("new_window", + GECKO_TYPE_EMBED, + (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST), + G_STRUCT_OFFSET (GeckoEmbedClass, new_window), + NULL, NULL, + gecko_embed_marshal_VOID__OBJECT_UINT, + G_TYPE_NONE, + 2, + G_TYPE_OBJECT, + G_TYPE_UINT); + + g_type_class_add_private (object_class, sizeof (GeckoEmbedPrivate)); +} + +GtkWidget * +gecko_embed_new (void) +{ + return GTK_WIDGET (g_object_new (GECKO_TYPE_EMBED, NULL)); +} diff --git a/embed/xulrunner/src/gecko-embed.h b/embed/xulrunner/src/gecko-embed.h new file mode 100644 index 000000000..8aec90bc2 --- /dev/null +++ b/embed/xulrunner/src/gecko-embed.h @@ -0,0 +1,151 @@ +/* + * Copyright © Christopher Blizzard + * Copyright © Ramiro Estrugo + * Copyright © 2006 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * --------------------------------------------------------------------------- + * Derived from Mozilla.org code, which had the following attributions: + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Christopher Blizzard. Portions created by Christopher Blizzard are Copyright © Christopher Blizzard. All Rights Reserved. + * Portions created by the Initial Developer are Copyright © 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Christopher Blizzard <blizzard@mozilla.org> + * Ramiro Estrugo <ramiro@eazel.com> + * --------------------------------------------------------------------------- + * + * $Id$ + */ + +#ifndef gecko_embed_h +#define gecko_embed_h + +#include <stddef.h> +#include <gtk/gtk.h> + +G_BEGIN_DECLS + +#define GECKO_TYPE_EMBED (gecko_embed_get_type()) +#define GECKO_EMBED(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GECKO_TYPE_EMBED, GeckoEmbed)) +#define GECKO_EMBED_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GECKO_TYPE_EMBED, GeckoEmbedClass)) +#define GECKO_IS_EMBED(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GECKO_TYPE_EMBED)) +#define GECKO_IS_EMBED_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GECKO_TYPE_EMBED)) +#define GECKO_EMBED_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GECKO_TYPE_EMBED, GeckoEmbedClass)) + +typedef struct _GeckoEmbed GeckoEmbed; +typedef struct _GeckoEmbedPrivate GeckoEmbedPrivate; +typedef struct _GeckoEmbedClass GeckoEmbedClass; + +struct _GeckoEmbed +{ + GtkBin parent_instance; + + /*< private >*/ + GeckoEmbedPrivate *priv; +}; + +struct _GeckoEmbedClass +{ + GtkBinClass parent_class; + + /* Signals */ + + /* Network */ + gboolean (* open_uri) (GeckoEmbed *embed, const char *aURI); + void (* net_start) (GeckoEmbed *embed); + void (* net_stop) (GeckoEmbed *embed); + void (* net_state) (GeckoEmbed *embed, int state, guint status); + void (* net_state_all) (GeckoEmbed *embed, const char *aURI, + int state, guint status); + void (* progress) (GeckoEmbed *embed, int curprogress, + int maxprogress); + void (* progress_all) (GeckoEmbed *embed, const char *aURI, + int curprogress, int maxprogress); + void (* security_change) (GeckoEmbed *embed, gpointer request, + guint state); + void (* status_change) (GeckoEmbed *embed, gpointer request, + int status, gpointer message); + + /* Document */ + void (* link_message) (GeckoEmbed *embed); + void (* js_status_message) (GeckoEmbed *embed); + void (* location) (GeckoEmbed *embed); + void (* title) (GeckoEmbed *embed); + void (* visibility) (GeckoEmbed *embed, gboolean visibility); + void (* destroy_browser) (GeckoEmbed *embed); + void (* size_to) (GeckoEmbed *embed, int width, int height); + + + /* misc. */ + void (* new_window) (GeckoEmbed *embed, GeckoEmbed **newEmbed, + guint chromemask); + + /* reserved for future use */ + void (* reserved_0) (void); + void (* reserved_1) (void); + void (* reserved_2) (void); + void (* reserved_3) (void); + void (* reserved_4) (void); + void (* reserved_5) (void); + void (* reserved_6) (void); + void (* reserved_7) (void); + void (* reserved_8) (void); + void (* reserved_9) (void); + void (* reserved_a) (void); + void (* reserved_b) (void); + void (* reserved_c) (void); + void (* reserved_d) (void); + void (* reserved_e) (void); + void (* reserved_f) (void); +}; + +GType gecko_embed_get_type (void); +GtkWidget *gecko_embed_new (void); +void gecko_embed_load_url (GeckoEmbed *embed, + const char *url); +void gecko_embed_stop_load (GeckoEmbed *embed); +gboolean gecko_embed_can_go_back (GeckoEmbed *embed); +gboolean gecko_embed_can_go_forward (GeckoEmbed *embed); +void gecko_embed_go_back (GeckoEmbed *embed); +void gecko_embed_go_forward (GeckoEmbed *embed); +void gecko_embed_render_data (GeckoEmbed *embed, + const char *data, + guint32 len, + const char *base_uri, + const char *mime_type); +void gecko_embed_open_stream (GeckoEmbed *embed, + const char *base_uri, + const char *mime_type); +void gecko_embed_append_data (GeckoEmbed *embed, + const char *data, guint32 len); +void gecko_embed_close_stream (GeckoEmbed *embed); +char *gecko_embed_get_link_message (GeckoEmbed *embed); +char *gecko_embed_get_js_status (GeckoEmbed *embed); +char *gecko_embed_get_title (GeckoEmbed *embed); +char *gecko_embed_get_location (GeckoEmbed *embed); +void gecko_embed_reload (GeckoEmbed *embed, gint32 flags); +void gecko_embed_set_chrome_mask (GeckoEmbed *embed, + guint32 flags); +guint32 gecko_embed_get_chrome_mask (GeckoEmbed *embed); + +G_END_DECLS + +#endif /* gecko_embed_h */ diff --git a/embed/xulrunner/src/gecko-init-internal.h b/embed/xulrunner/src/gecko-init-internal.h new file mode 100644 index 000000000..551b4bd45 --- /dev/null +++ b/embed/xulrunner/src/gecko-init-internal.h @@ -0,0 +1,30 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Copyright © 2006 Xan Lopez <xan@gnome.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + * $Id$ + * ***** END LICENSE BLOCK ***** */ + +#ifndef __gecko_init_internal_h +#define __gecko_init_internal_h + +#include <gtk/gtk.h> +#include "nsIDirectoryService.h" + +extern gboolean gecko_init_with_params (const char *, const char*, const char*, nsIDirectoryServiceProvider*); + +#endif diff --git a/embed/xulrunner/src/gecko-init-private.h b/embed/xulrunner/src/gecko-init-private.h new file mode 100644 index 000000000..b4cc34bfb --- /dev/null +++ b/embed/xulrunner/src/gecko-init-private.h @@ -0,0 +1,33 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Copyright © 2006 Xan Lopez <xan@gnome.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + * $Id$ + * ***** END LICENSE BLOCK ***** */ + +#ifndef __gecko_init_private_h +#define __gecko_init_private_h + +#include <gtk/gtk.h> + +G_BEGIN_DECLS + +void gecko_reparent_to_offscreen (GtkWidget*); + +G_END_DECLS + +#endif diff --git a/embed/xulrunner/src/gecko-init.cpp b/embed/xulrunner/src/gecko-init.cpp new file mode 100644 index 000000000..cbad02a67 --- /dev/null +++ b/embed/xulrunner/src/gecko-init.cpp @@ -0,0 +1,392 @@ +/* + * Copyright © Christopher Blizzard + * Copyright © 2006 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * --------------------------------------------------------------------------- + * Derived from Mozilla.org code, which had the following attributions: + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Christopher Blizzard. Portions created by Christopher Blizzard are Copyright © Christopher Blizzard. All Rights Reserved. + * Portions created by the Initial Developer are Copyright © 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Christopher Blizzard <blizzard@mozilla.org> + * --------------------------------------------------------------------------- + * + * $Id$ + */ + +#include <mozilla-config.h> +#include <config.h> + +#include <stdlib.h> + +#include "GeckoSingle.h" + +#include "nsIDocShell.h" +#include "nsIWebProgress.h" +#include "nsIWebBrowserStream.h" +#include "nsIWidget.h" +#include "nsIDirectoryService.h" +#include "nsAppDirectoryServiceDefs.h" + +// for NS_APPSHELL_CID +#include "nsWidgetsCID.h" + +// for do_GetInterface +#include "nsIInterfaceRequestor.h" +// for do_CreateInstance +#include "nsIComponentManager.h" + +// for initializing our window watcher service +#include "nsIWindowWatcher.h" + +#include "nsILocalFile.h" +#include "nsXULAppAPI.h" + +// all of the crap that we need for event listeners +// and when chrome windows finish loading +#include "nsIDOMWindow.h" +#include "nsPIDOMWindow.h" +#include "nsIDOMWindowInternal.h" + +// For seting scrollbar visibilty +#include <nsIDOMBarProp.h> + +// for the focus hacking we need to do +#include "nsIFocusController.h" + +// app component registration +#include "nsIGenericFactory.h" +#include "nsIComponentRegistrar.h" + +// all of our local includes +#include "gecko-init.h" +#include "GeckoSingle.h" +#include "EmbedWindow.h" +#include "EmbedProgress.h" +#include "EmbedContentListener.h" +#include "EmbedEventListener.h" +#include "EmbedWindowCreator.h" +#include "GeckoPromptService.h" + +#ifdef MOZ_ACCESSIBILITY_ATK +#include "nsIAccessibilityService.h" +#include "nsIAccessible.h" +#include "nsIDOMDocument.h" +#endif + +#include <nsServiceManagerUtils.h> +#include "nsXPCOMGlue.h" + +#include "gecko-init.h" +#include "gecko-init-private.h" +#include "gecko-init-internal.h" + +NS_GENERIC_FACTORY_CONSTRUCTOR(GeckoPromptService) + +static const nsModuleComponentInfo defaultAppComps[] = { + { + GECKO_PROMPT_SERVICE_CLASSNAME, + GECKO_PROMPT_SERVICE_CID, + "@mozilla.org/embedcomp/prompt-service;1", + GeckoPromptServiceConstructor + }, +#ifdef HAVE_NSINONBLOCKINGALERTSERVICE_H + { + GECKO_PROMPT_SERVICE_CLASSNAME, + GECKO_PROMPT_SERVICE_CID, + "@mozilla.org/embedcomp/nbalert-service;1", + GeckoPromptServiceConstructor + }, +#endif /* HAVE_NSINONBLOCKINGALERTSERVICE_H */ +}; + +GtkWidget *sOffscreenWindow = 0; +GtkWidget *sOffscreenFixed = 0; +const nsModuleComponentInfo *sAppComps = defaultAppComps; +int sNumAppComps = sizeof (defaultAppComps) / sizeof (nsModuleComponentInfo); +nsILocalFile *sProfileDir = nsnull; +nsISupports *sProfileLock = nsnull; +nsIDirectoryServiceProvider* sAppFileLocProvider; + +class GTKEmbedDirectoryProvider : public nsIDirectoryServiceProvider2 +{ + public: + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_NSIDIRECTORYSERVICEPROVIDER + NS_DECL_NSIDIRECTORYSERVICEPROVIDER2 +}; + +static const GTKEmbedDirectoryProvider kDirectoryProvider; + +NS_IMPL_QUERY_INTERFACE2(GTKEmbedDirectoryProvider, + nsIDirectoryServiceProvider, + nsIDirectoryServiceProvider2) + +NS_IMETHODIMP_(nsrefcnt) +GTKEmbedDirectoryProvider::AddRef() +{ + return 2; +} + +NS_IMETHODIMP_(nsrefcnt) +GTKEmbedDirectoryProvider::Release() +{ + return 1; +} + +NS_IMETHODIMP +GTKEmbedDirectoryProvider::GetFile(const char *aKey, PRBool *aPersist, + nsIFile* *aResult) +{ + if (sAppFileLocProvider) { + nsresult rv = sAppFileLocProvider->GetFile(aKey, aPersist, + aResult); + if (NS_SUCCEEDED(rv)) + return rv; + } + + if (sProfileDir && !strcmp(aKey, NS_APP_USER_PROFILE_50_DIR)) { + *aPersist = PR_TRUE; + return sProfileDir->Clone(aResult); + } + + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +GTKEmbedDirectoryProvider::GetFiles(const char *aKey, + nsISimpleEnumerator* *aResult) +{ + nsCOMPtr<nsIDirectoryServiceProvider2> + dp2(do_QueryInterface(sAppFileLocProvider)); + + if (!dp2) + return NS_ERROR_FAILURE; + + return dp2->GetFiles(aKey, aResult); +} + +/* static */ +nsresult +RegisterAppComponents(void) +{ + nsCOMPtr<nsIComponentRegistrar> cr; + nsresult rv = NS_GetComponentRegistrar(getter_AddRefs(cr)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIComponentManager> cm; + rv = NS_GetComponentManager (getter_AddRefs (cm)); + NS_ENSURE_SUCCESS (rv, rv); + + for (int i = 0; i < sNumAppComps; ++i) { + nsCOMPtr<nsIGenericFactory> componentFactory; + rv = NS_NewGenericFactory(getter_AddRefs(componentFactory), + &(sAppComps[i])); + if (NS_FAILED(rv)) { + NS_WARNING("Unable to create factory for component"); + continue; // don't abort registering other components + } + + rv = cr->RegisterFactory(sAppComps[i].mCID, sAppComps[i].mDescription, + sAppComps[i].mContractID, componentFactory); + NS_ASSERTION(NS_SUCCEEDED(rv), "Unable to register factory for component"); + + // Call the registration hook of the component, if any + if (sAppComps[i].mRegisterSelfProc) { + rv = sAppComps[i].mRegisterSelfProc(cm, nsnull, nsnull, nsnull, + &(sAppComps[i])); + NS_ASSERTION(NS_SUCCEEDED(rv), "Unable to self-register component"); + } + } + + return rv; +} + +/* static */ +nsresult +StartupProfile (const char* aProfileDir, const char* aProfileName) +{ + /* Running without profile */ + if (!aProfileDir || !aProfileName) + return NS_OK; + + if (sProfileDir && GeckoSingle::sWidgetCount != 0) { + NS_ERROR("Cannot change profile directory during run!"); + return NS_ERROR_ALREADY_INITIALIZED; + } + + nsresult rv; + nsCOMPtr<nsILocalFile> profileDir; + rv = NS_NewNativeLocalFile (nsDependentCString (aProfileDir), PR_TRUE, + &sProfileDir); + if (NS_FAILED (rv)) + return rv; + + if (aProfileName) { + rv = sProfileDir->AppendNative (nsDependentCString (aProfileName)); + if (NS_FAILED (rv)) + return rv; // FIXMEchpe release sProfileDir + } + + rv = XRE_LockProfileDirectory (sProfileDir, &sProfileLock); + if (NS_FAILED (rv)) + return rv; // FIXMEchpe release sProfileDir + + if (GeckoSingle::sWidgetCount) + XRE_NotifyProfile(); + + return NS_OK; +} + +gboolean +gecko_init () +{ + return gecko_init_with_params (nsnull, nsnull, nsnull, nsnull); +} + +gboolean +gecko_init_with_profile (const char *aGREPath, + const char* aProfileDir, + const char* aProfileName) +{ + return gecko_init_with_params (aGREPath, aProfileDir, aProfileName, nsnull); +} + +gboolean +gecko_init_with_params (const char *aGREPath, + const char* aProfileDir, + const char* aProfileName, + nsIDirectoryServiceProvider* aAppFileLocProvider) +{ + nsresult rv; + nsCOMPtr<nsILocalFile> binDir; + +#if 0 //def XPCOM_GLUE + const char* xpcomLocation = GRE_GetXPCOMPath(); + + // Startup the XPCOM Glue that links us up with XPCOM. + nsresult rv = XPCOMGlueStartup(xpcomLocation); + if (NS_FAILED(rv)) return; +#endif + + NS_IF_ADDREF (sAppFileLocProvider = aAppFileLocProvider); + + /* FIrst try to lock the profile */ + rv = StartupProfile (aProfileDir, aProfileName); + if (NS_FAILED (rv)) + return FALSE; + + const char* aCompPath = g_getenv("GECKO_HOME"); + + if (aCompPath) { + rv = NS_NewNativeLocalFile(nsEmbedCString(aCompPath), PR_TRUE, getter_AddRefs(binDir)); + NS_ENSURE_SUCCESS(rv,false); + } + + if (!aGREPath) + aGREPath = getenv("MOZILLA_FIVE_HOME"); + + if (!aGREPath) + return FALSE; + + nsCOMPtr<nsILocalFile> greDir; + rv = NS_NewNativeLocalFile (nsDependentCString (aGREPath), PR_TRUE, + getter_AddRefs (greDir)); + if (NS_FAILED(rv)) + return FALSE; + + rv = XRE_InitEmbedding(greDir, binDir, + const_cast<GTKEmbedDirectoryProvider*> (&kDirectoryProvider), + nsnull, nsnull); + if (NS_FAILED (rv)) + return FALSE; + + if (sProfileDir) + XRE_NotifyProfile(); + + rv = RegisterAppComponents(); + NS_ASSERTION(NS_SUCCEEDED(rv), "Warning: Failed to register app components.\n"); + + // create our local object + EmbedWindowCreator *creator = new EmbedWindowCreator(); + nsCOMPtr<nsIWindowCreator> windowCreator = + static_cast<nsIWindowCreator *>(creator); + + // Attach it via the watcher service + nsCOMPtr<nsIWindowWatcher> watcher (do_GetService(NS_WINDOWWATCHER_CONTRACTID)); + if (watcher) + watcher->SetWindowCreator(windowCreator); + + return true; +} + +/* static */ +void +EnsureOffscreenWindow(void) +{ + if (sOffscreenWindow) + return; + + sOffscreenWindow = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_widget_realize (sOffscreenWindow); + sOffscreenFixed = gtk_fixed_new(); + gtk_container_add (GTK_CONTAINER (sOffscreenWindow), sOffscreenFixed); + gtk_widget_realize (sOffscreenFixed); +} + +/* static */ +void +gecko_reparent_to_offscreen(GtkWidget *aWidget) +{ + EnsureOffscreenWindow(); + + gtk_widget_reparent(aWidget, sOffscreenFixed); +} + +/* static */ +void +DestroyOffscreenWindow(void) +{ + if (!sOffscreenWindow) + return; + gtk_widget_destroy(sOffscreenWindow); + sOffscreenWindow = nsnull; + sOffscreenFixed = nsnull; +} + +void +gecko_shutdown() +{ + // destroy the offscreen window + DestroyOffscreenWindow(); + + NS_IF_RELEASE (sProfileDir); + + // shut down XPCOM/Embedding + XRE_TermEmbedding(); + + // we no longer need a reference to the DirectoryServiceProvider + NS_IF_RELEASE (sAppFileLocProvider); + + /* FIXMchpe before or after TermEmbedding?? */ + NS_IF_RELEASE (sProfileLock); +} diff --git a/embed/xulrunner/src/gecko-init.h b/embed/xulrunner/src/gecko-init.h new file mode 100644 index 000000000..ee66f0ea4 --- /dev/null +++ b/embed/xulrunner/src/gecko-init.h @@ -0,0 +1,35 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Copyright © 2006 Xan Lopez <xan@gnome.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + * $Id$ + * ***** END LICENSE BLOCK ***** */ + +#ifndef __gecko_init_h +#define __gecko_init_h + +#include <gtk/gtk.h> + +G_BEGIN_DECLS + +gboolean gecko_init (); +gboolean gecko_init_with_profile (const char *, const char*, const char*); +void gecko_shutdown (); + +G_END_DECLS + +#endif diff --git a/embed/xulrunner/tests/Makefile.am b/embed/xulrunner/tests/Makefile.am new file mode 100644 index 000000000..22a2cf93a --- /dev/null +++ b/embed/xulrunner/tests/Makefile.am @@ -0,0 +1,35 @@ +required = \ + xpcom \ + string \ + dom + +bin_PROGRAMS = testgeckoembed + +testgeckoembed_SOURCES = \ + testgeckoembed.cpp + +testgeckoembed_CPPFLAGS = \ + -I$(top_srcdir) \ + -I$(top_srcdir)/embed/gecko/src \ + -I$(top_builddir)/embed/gecko/src \ + $(addprefix -I$(GECKO_INCLUDE_ROOT)/,$(required)) \ + -I$(GECKO_INCLUDE_ROOT) \ + -DGECKO_HOME=\"$(GECKO_HOME)\" \ + $(AM_CPPFLAGS) + +testgeckoembed_CXXFLAGS = \ + $(GGE_DEPENDENCY_CFLAGS) \ + $(GECKO_CFLAGS) \ + $(AM_CXXFLAGS) + +testgeckoembed_LDADD = \ + $(top_builddir)/embed/gecko/src/libgnomegeckoembed-0.0.la \ + $(GGE_DEPENDENCY_LIBS) \ + $(GECKO_LIBS) \ + $(GECKO_EXTRA_LIBS) \ + $(GECKO_GLUE_LIBS) \ + -lxpcomglue + +testgeckoembed_LDFLAGS = \ + -R$(GECKO_HOME) +# `$(MOZILLA_CONFIG) --libs $(required)` diff --git a/embed/xulrunner/tests/TestGtkEmbedNotebook.cpp b/embed/xulrunner/tests/TestGtkEmbedNotebook.cpp new file mode 100644 index 000000000..1891ca06b --- /dev/null +++ b/embed/xulrunner/tests/TestGtkEmbedNotebook.cpp @@ -0,0 +1,49 @@ +#include <gtk/gtk.h> +#include <gtkmozembed.h> +int main(int argc, char *argv[]) +{ + GtkWidget *window; + GtkWidget *label; + GtkWidget *mozembed; + GtkWidget *container; + char *url; + + gtk_init(&argc, &argv); + + window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + + container = gtk_notebook_new(); + mozembed = gtk_moz_embed_new(); + label = gtk_label_new("Can you see this message?\n" + "Once you switch to mozembed page " + "you never see this message."); + + gtk_signal_connect(GTK_OBJECT(mozembed), "destroy", + GTK_SIGNAL_FUNC(gtk_main_quit), +NULL); + + gtk_container_add(GTK_CONTAINER(window), container); + + gtk_notebook_append_page(GTK_NOTEBOOK(container), + label, + gtk_label_new("gtk label")); + + gtk_notebook_append_page(GTK_NOTEBOOK(container), + mozembed, + gtk_label_new("mozembed")); + + + + + gtk_widget_set_usize(window, 400, 300); + gtk_widget_show(mozembed); + gtk_widget_show(label); + gtk_widget_show_all(window); + + url = (argc > 1) ? argv[1] : (char *)"localhost"; + gtk_moz_embed_load_url(GTK_MOZ_EMBED(mozembed), url); + + gtk_main(); + + return 0; +} diff --git a/embed/xulrunner/tests/testgeckoembed.cpp b/embed/xulrunner/tests/testgeckoembed.cpp new file mode 100644 index 000000000..1b9a888b6 --- /dev/null +++ b/embed/xulrunner/tests/testgeckoembed.cpp @@ -0,0 +1,1145 @@ +/* + * Copyright © Christopher Blizzard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * --------------------------------------------------------------------------- + * Derived from Mozilla.org code, which had the following attributions: + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Christopher Blizzard. Portions created by Christopher Blizzard are Copyright © Christopher Blizzard. All Rights Reserved. + * Portions created by the Initial Developer are Copyright © 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Christopher Blizzard <blizzard@mozilla.org> + * --------------------------------------------------------------------------- + * + * $Id$ + */ + +#include <mozilla-config.h> +#include <config.h> + +#include "gecko-init.h" +#include "gecko-embed.h" +#include "gecko-embed-single.h" +#include "gecko-dom-event.h" +#include "gecko-dom-event-internal.h" +#include "gecko-embed-types.h" + +#include <gtk/gtk.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +// mozilla specific headers +#include "nsIDOMKeyEvent.h" +#include "nsIDOMMouseEvent.h" +#include "nsIDOMUIEvent.h" + +#include <nsStringAPI.h> +#include <nsCOMPtr.h> + +#define XPCOM_GLUE +#include <nsXPCOMGlue.h> + +typedef struct _TestGeckoBrowser { + GtkWidget *topLevelWindow; + GtkWidget *topLevelVBox; + GtkWidget *menuBar; + GtkWidget *fileMenuItem; + GtkWidget *fileMenu; + GtkWidget *fileOpenNewBrowser; + GtkWidget *fileStream; + GtkWidget *fileClose; + GtkWidget *fileQuit; + GtkWidget *toolbarHBox; + GtkWidget *toolbar; + GtkWidget *backButton; + GtkWidget *stopButton; + GtkWidget *forwardButton; + GtkWidget *reloadButton; + GtkWidget *urlEntry; + GtkWidget *mozEmbed; + GtkWidget *progressAreaHBox; + GtkWidget *progressBar; + GtkWidget *statusAlign; + GtkWidget *statusBar; + const char *statusMessage; + int loadPercent; + int bytesLoaded; + int maxBytesLoaded; + char *tempMessage; + gboolean menuBarOn; + gboolean toolBarOn; + gboolean locationBarOn; + gboolean statusBarOn; + +} TestGeckoBrowser; + +// the list of browser windows currently open +GList *browser_list = g_list_alloc(); + +static TestGeckoBrowser *new_gecko_browser (guint32 chromeMask); +static void set_browser_visibility (TestGeckoBrowser *browser, + gboolean visibility); + +static int num_browsers = 0; + +// callbacks from the UI +static void back_clicked_cb (GtkButton *button, + TestGeckoBrowser *browser); +static void stop_clicked_cb (GtkButton *button, + TestGeckoBrowser *browser); +static void forward_clicked_cb (GtkButton *button, + TestGeckoBrowser *browser); +static void reload_clicked_cb (GtkButton *button, + TestGeckoBrowser *browser); +static void url_activate_cb (GtkEditable *widget, + TestGeckoBrowser *browser); +static void menu_open_new_cb (GtkMenuItem *menuitem, + TestGeckoBrowser *browser); +static void menu_stream_cb (GtkMenuItem *menuitem, + TestGeckoBrowser *browser); +static void menu_close_cb (GtkMenuItem *menuitem, + TestGeckoBrowser *browser); +static void menu_quit_cb (GtkMenuItem *menuitem, + TestGeckoBrowser *browser); +static gboolean delete_cb (GtkWidget *widget, GdkEventAny *event, + TestGeckoBrowser *browser); +static void destroy_cb (GtkWidget *widget, + TestGeckoBrowser *browser); + +// callbacks from the widget +static void location_changed_cb (GeckoEmbed *embed, TestGeckoBrowser *browser); +static void title_changed_cb (GeckoEmbed *embed, TestGeckoBrowser *browser); +static void load_started_cb (GeckoEmbed *embed, TestGeckoBrowser *browser); +static void load_finished_cb (GeckoEmbed *embed, TestGeckoBrowser *browser); +static void net_state_change_cb (GeckoEmbed *embed, gint flags, + guint status, TestGeckoBrowser *browser); +static void net_state_change_all_cb (GeckoEmbed *embed, const char *uri, + gint flags, guint status, + TestGeckoBrowser *browser); +static void progress_change_cb (GeckoEmbed *embed, gint cur, gint max, + TestGeckoBrowser *browser); +static void progress_change_all_cb (GeckoEmbed *embed, const char *uri, + gint cur, gint max, + TestGeckoBrowser *browser); +static void link_message_cb (GeckoEmbed *embed, TestGeckoBrowser *browser); +static void js_status_cb (GeckoEmbed *embed, TestGeckoBrowser *browser); +static void new_window_cb (GeckoEmbed *embed, + GeckoEmbed **retval, guint chromemask, + TestGeckoBrowser *browser); +static void visibility_cb (GeckoEmbed *embed, + gboolean visibility, + TestGeckoBrowser *browser); +static void destroy_brsr_cb (GeckoEmbed *embed, TestGeckoBrowser *browser); +static gint open_uri_cb (GeckoEmbed *embed, const char *uri, + TestGeckoBrowser *browser); +static void size_to_cb (GeckoEmbed *embed, gint width, + gint height, TestGeckoBrowser *browser); +static gboolean dom_key_down_cb (GeckoEmbed *, GeckoDOMEvent *event, + TestGeckoBrowser *browser); +static gboolean dom_key_press_cb (GeckoEmbed *, GeckoDOMEvent *event, + TestGeckoBrowser *browser); +static gboolean dom_key_up_cb (GeckoEmbed *, GeckoDOMEvent *event, + TestGeckoBrowser *browser); +static gboolean dom_mouse_down_cb (GeckoEmbed *, GeckoDOMEvent *event, + TestGeckoBrowser *browser); +static gboolean dom_mouse_up_cb (GeckoEmbed *, GeckoDOMEvent *event, + TestGeckoBrowser *browser); +static gboolean dom_mouse_click_cb (GeckoEmbed *, GeckoDOMEvent *event, + TestGeckoBrowser *browser); +static gboolean dom_mouse_dbl_click_cb (GeckoEmbed *embed, + GeckoDOMEvent *event, + TestGeckoBrowser *browser); +static gboolean dom_mouse_over_cb (GeckoEmbed *, GeckoDOMEvent *event, + TestGeckoBrowser *browser); +static gboolean dom_mouse_out_cb (GeckoEmbed *, GeckoDOMEvent *event, + TestGeckoBrowser *browser); +static gboolean dom_activate_cb (GeckoEmbed *, GeckoDOMEvent *event, + TestGeckoBrowser *browser); +static gboolean dom_focus_in_cb (GeckoEmbed *, GeckoDOMEvent *event, + TestGeckoBrowser *browser); +static gboolean dom_focus_out_cb (GeckoEmbed *, GeckoDOMEvent *event, + TestGeckoBrowser *browser); +static gboolean dom_context_menu_cb (GeckoEmbed *, GeckoDOMEvent *event, + TestGeckoBrowser *browser); + +// callbacks from the singleton object +static void new_window_orphan_cb (GeckoEmbedSingle *embed, + GeckoEmbed **retval, guint chromemask, + gpointer data); + +// some utility functions +static void update_status_bar_text (TestGeckoBrowser *browser); +static void update_temp_message (TestGeckoBrowser *browser, + const char *message); +static void update_nav_buttons (TestGeckoBrowser *browser); + +int +main(int argc, char **argv) +{ + //g_setenv ("MOZILLA_FIVE_HOME", GECKO_HOME, FALSE); + + gtk_init(&argc, &argv); + + static const GREVersionRange greVersion = { + "1.9a", PR_TRUE, + "2", PR_TRUE + }; + + char xpcomPath[PATH_MAX]; + + nsresult rv = GRE_GetGREPathWithProperties(&greVersion, 1, nsnull, 0, + xpcomPath, sizeof(xpcomPath)); + if (NS_FAILED(rv)) { + fprintf(stderr, "Couldn't find a compatible GRE.\n"); + return 1; + } + + rv = XPCOMGlueStartup(xpcomPath); + if (NS_FAILED(rv)) { + fprintf(stderr, "Couldn't start XPCOM."); + return 1; + } + + char *lastSlash = strrchr(xpcomPath, '/'); + if (lastSlash) + *lastSlash = '\0'; + + + char *home_path; + char *full_path; + home_path = getenv("HOME"); + if (!home_path) { + fprintf(stderr, "Failed to get HOME\n"); + exit(1); + } + + + full_path = g_strdup_printf("%s/%s", home_path, ".TestGtkEmbed"); + + if (!gecko_init_with_profile (xpcomPath, full_path, "TestGtkEmbed")) { + fprintf(stderr, "Failed gecko_init_with_profile\n"); + exit(1); + } + + // get the singleton object and hook up to its new window callback + // so we can create orphaned windows. + + GeckoEmbedSingle *single; + + single = gecko_embed_single_get(); + if (!single) { + fprintf(stderr, "Failed to get singleton embed object!\n"); + exit(1); + } + + g_signal_connect (single, "new-window-orphan", + G_CALLBACK (new_window_orphan_cb), NULL); + + + TestGeckoBrowser *browser = new_gecko_browser(GECKO_EMBED_FLAG_DEFAULTCHROME); + + // set our minimum size + gtk_widget_set_usize(browser->mozEmbed, 400, 400); + + set_browser_visibility(browser, TRUE); + + if (argc > 1) + gecko_embed_load_url(GECKO_EMBED(browser->mozEmbed), argv[1]); + + gtk_main(); + + gecko_shutdown (); +} + +static TestGeckoBrowser * +new_gecko_browser(guint32 chromeMask) +{ + guint32 actualChromeMask = chromeMask; + TestGeckoBrowser *browser = 0; + + num_browsers++; + + browser = g_new0(TestGeckoBrowser, 1); + + browser_list = g_list_prepend(browser_list, browser); + + browser->menuBarOn = FALSE; + browser->toolBarOn = FALSE; + browser->locationBarOn = FALSE; + browser->statusBarOn = FALSE; + + g_print("new_gecko_browser\n"); + +// if (chromeMask == GECKO_EMBED_FLAG_DEFAULTCHROME) +// actualChromeMask = GECKO_EMBED_FLAG_ALLCHROME; + + /* FIXMEchpe find out WHY the chrome masks we get from gecko as so weird */ + actualChromeMask = 0xffffffff; + + if (actualChromeMask & GECKO_EMBED_FLAG_MENUBARON) + { + browser->menuBarOn = TRUE; + g_print("\tmenu bar\n"); + } + if (actualChromeMask & GECKO_EMBED_FLAG_TOOLBARON) + { + browser->toolBarOn = TRUE; + g_print("\ttool bar\n"); + } + if (actualChromeMask & GECKO_EMBED_FLAG_LOCATIONBARON) + { + browser->locationBarOn = TRUE; + g_print("\tlocation bar\n"); + } + if (actualChromeMask & GECKO_EMBED_FLAG_STATUSBARON) + { + browser->statusBarOn = TRUE; + g_print("\tstatus bar\n"); + } + + // create our new toplevel window + browser->topLevelWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL); + // new vbox + browser->topLevelVBox = gtk_vbox_new(FALSE, 0); + // add it to the toplevel window + gtk_container_add(GTK_CONTAINER(browser->topLevelWindow), + browser->topLevelVBox); + // create our menu bar + browser->menuBar = gtk_menu_bar_new(); + // create the file menu + browser->fileMenuItem = gtk_menu_item_new_with_label("File"); + browser->fileMenu = gtk_menu_new(); + gtk_menu_item_set_submenu (GTK_MENU_ITEM(browser->fileMenuItem), + browser->fileMenu); + + browser->fileOpenNewBrowser = + gtk_menu_item_new_with_label("Open New Browser"); + gtk_menu_append(GTK_MENU(browser->fileMenu), + browser->fileOpenNewBrowser); + + browser->fileStream = + gtk_menu_item_new_with_label("Test Stream"); + gtk_menu_append(GTK_MENU(browser->fileMenu), + browser->fileStream); + + browser->fileClose = + gtk_menu_item_new_with_label("Close"); + gtk_menu_append(GTK_MENU(browser->fileMenu), + browser->fileClose); + + browser->fileQuit = + gtk_menu_item_new_with_label("Quit"); + gtk_menu_append(GTK_MENU(browser->fileMenu), + browser->fileQuit); + + // append it + gtk_menu_bar_append(GTK_MENU_BAR(browser->menuBar), browser->fileMenuItem); + + // add it to the vbox + gtk_box_pack_start(GTK_BOX(browser->topLevelVBox), + browser->menuBar, + FALSE, // expand + FALSE, // fill + 0); // padding + // create the hbox that will contain the toolbar and the url text entry bar + browser->toolbarHBox = gtk_hbox_new(FALSE, 0); + // add that hbox to the vbox + gtk_box_pack_start(GTK_BOX(browser->topLevelVBox), + browser->toolbarHBox, + FALSE, // expand + FALSE, // fill + 0); // padding + // new horiz toolbar with buttons + icons + browser->toolbar = gtk_toolbar_new(); + gtk_toolbar_set_orientation(GTK_TOOLBAR(browser->toolbar), + GTK_ORIENTATION_HORIZONTAL); + gtk_toolbar_set_style(GTK_TOOLBAR(browser->toolbar), + GTK_TOOLBAR_BOTH); + + // add it to the hbox + gtk_box_pack_start(GTK_BOX(browser->toolbarHBox), browser->toolbar, + FALSE, // expand + FALSE, // fill + 0); // padding + // new back button + browser->backButton = + gtk_toolbar_append_item(GTK_TOOLBAR(browser->toolbar), + "Back", + "Go Back", + "Go Back", + 0, // XXX replace with icon + GTK_SIGNAL_FUNC(back_clicked_cb), + browser); + // new stop button + browser->stopButton = + gtk_toolbar_append_item(GTK_TOOLBAR(browser->toolbar), + "Stop", + "Stop", + "Stop", + 0, // XXX replace with icon + GTK_SIGNAL_FUNC(stop_clicked_cb), + browser); + // new forward button + browser->forwardButton = + gtk_toolbar_append_item(GTK_TOOLBAR(browser->toolbar), + "Forward", + "Forward", + "Forward", + 0, // XXX replace with icon + GTK_SIGNAL_FUNC(forward_clicked_cb), + browser); + // new reload button + browser->reloadButton = + gtk_toolbar_append_item(GTK_TOOLBAR(browser->toolbar), + "Reload", + "Reload", + "Reload", + 0, // XXX replace with icon + GTK_SIGNAL_FUNC(reload_clicked_cb), + browser); + // create the url text entry + browser->urlEntry = gtk_entry_new(); + // add it to the hbox + gtk_box_pack_start(GTK_BOX(browser->toolbarHBox), browser->urlEntry, + TRUE, // expand + TRUE, // fill + 0); // padding + // create our new gtk moz embed widget + browser->mozEmbed = gecko_embed_new(); + // add it to the toplevel vbox + gtk_box_pack_start(GTK_BOX(browser->topLevelVBox), browser->mozEmbed, + TRUE, // expand + TRUE, // fill + 0); // padding + // create the new hbox for the progress area + browser->progressAreaHBox = gtk_hbox_new(FALSE, 0); + // add it to the vbox + gtk_box_pack_start(GTK_BOX(browser->topLevelVBox), browser->progressAreaHBox, + FALSE, // expand + FALSE, // fill + 0); // padding + // create our new progress bar + browser->progressBar = gtk_progress_bar_new(); + // add it to the hbox + gtk_box_pack_start(GTK_BOX(browser->progressAreaHBox), browser->progressBar, + FALSE, // expand + FALSE, // fill + 0); // padding + + // create our status area and the alignment object that will keep it + // from expanding + browser->statusAlign = gtk_alignment_new(0, 0, 1, 1); + gtk_widget_set_usize(browser->statusAlign, 1, -1); + // create the status bar + browser->statusBar = gtk_statusbar_new(); + gtk_container_add(GTK_CONTAINER(browser->statusAlign), browser->statusBar); + // add it to the hbox + gtk_box_pack_start(GTK_BOX(browser->progressAreaHBox), browser->statusAlign, + TRUE, // expand + TRUE, // fill + 0); // padding + // by default none of the buttons are marked as sensitive. + gtk_widget_set_sensitive(browser->backButton, FALSE); + gtk_widget_set_sensitive(browser->stopButton, FALSE); + gtk_widget_set_sensitive(browser->forwardButton, FALSE); + gtk_widget_set_sensitive(browser->reloadButton, FALSE); + + // catch the destruction of the toplevel window + gtk_signal_connect(GTK_OBJECT(browser->topLevelWindow), "delete_event", + GTK_SIGNAL_FUNC(delete_cb), browser); + + // hook up the activate signal to the right callback + gtk_signal_connect(GTK_OBJECT(browser->urlEntry), "activate", + GTK_SIGNAL_FUNC(url_activate_cb), browser); + + // hook up to the open new browser activation + gtk_signal_connect(GTK_OBJECT(browser->fileOpenNewBrowser), "activate", + GTK_SIGNAL_FUNC(menu_open_new_cb), browser); + // hook up to the stream test + gtk_signal_connect(GTK_OBJECT(browser->fileStream), "activate", + GTK_SIGNAL_FUNC(menu_stream_cb), browser); + // close this window + gtk_signal_connect(GTK_OBJECT(browser->fileClose), "activate", + GTK_SIGNAL_FUNC(menu_close_cb), browser); + // quit the application + gtk_signal_connect(GTK_OBJECT(browser->fileQuit), "activate", + GTK_SIGNAL_FUNC(menu_quit_cb), browser); + + // hook up the location change to update the urlEntry + gtk_signal_connect(GTK_OBJECT(browser->mozEmbed), "location", + GTK_SIGNAL_FUNC(location_changed_cb), browser); + // hook up the title change to update the window title + gtk_signal_connect(GTK_OBJECT(browser->mozEmbed), "title", + GTK_SIGNAL_FUNC(title_changed_cb), browser); + // hook up the start and stop signals + gtk_signal_connect(GTK_OBJECT(browser->mozEmbed), "net_start", + GTK_SIGNAL_FUNC(load_started_cb), browser); + gtk_signal_connect(GTK_OBJECT(browser->mozEmbed), "net_stop", + GTK_SIGNAL_FUNC(load_finished_cb), browser); + // hook up to the change in network status + gtk_signal_connect(GTK_OBJECT(browser->mozEmbed), "net_state", + GTK_SIGNAL_FUNC(net_state_change_cb), browser); + gtk_signal_connect(GTK_OBJECT(browser->mozEmbed), "net_state_all", + GTK_SIGNAL_FUNC(net_state_change_all_cb), browser); + // hookup to changes in progress + gtk_signal_connect(GTK_OBJECT(browser->mozEmbed), "progress", + GTK_SIGNAL_FUNC(progress_change_cb), browser); + gtk_signal_connect(GTK_OBJECT(browser->mozEmbed), "progress_all", + GTK_SIGNAL_FUNC(progress_change_all_cb), browser); + // hookup to changes in over-link message + gtk_signal_connect(GTK_OBJECT(browser->mozEmbed), "link_message", + GTK_SIGNAL_FUNC(link_message_cb), browser); + // hookup to changes in js status message + gtk_signal_connect(GTK_OBJECT(browser->mozEmbed), "js_status", + GTK_SIGNAL_FUNC(js_status_cb), browser); + // hookup to see whenever a new window is requested + gtk_signal_connect(GTK_OBJECT(browser->mozEmbed), "new_window", + GTK_SIGNAL_FUNC(new_window_cb), browser); + // hookup to any requested visibility changes + gtk_signal_connect(GTK_OBJECT(browser->mozEmbed), "visibility", + GTK_SIGNAL_FUNC(visibility_cb), browser); + // hookup to the signal that says that the browser requested to be + // destroyed + gtk_signal_connect(GTK_OBJECT(browser->mozEmbed), "destroy_browser", + GTK_SIGNAL_FUNC(destroy_brsr_cb), browser); + // hookup to the signal that is called when someone clicks on a link + // to load a new uri + gtk_signal_connect(GTK_OBJECT(browser->mozEmbed), "open_uri", + GTK_SIGNAL_FUNC(open_uri_cb), browser); + // this signal is emitted when there's a request to change the + // containing browser window to a certain height, like with width + // and height args for a window.open in javascript + gtk_signal_connect(GTK_OBJECT(browser->mozEmbed), "size_to", + GTK_SIGNAL_FUNC(size_to_cb), browser); + // key event signals + gtk_signal_connect(GTK_OBJECT(browser->mozEmbed), "dom_key_down", + GTK_SIGNAL_FUNC(dom_key_down_cb), browser); + gtk_signal_connect(GTK_OBJECT(browser->mozEmbed), "dom_key_press", + GTK_SIGNAL_FUNC(dom_key_press_cb), browser); + gtk_signal_connect(GTK_OBJECT(browser->mozEmbed), "dom_key_up", + GTK_SIGNAL_FUNC(dom_key_up_cb), browser); + gtk_signal_connect(GTK_OBJECT(browser->mozEmbed), "dom_mouse_down", + GTK_SIGNAL_FUNC(dom_mouse_down_cb), browser); + gtk_signal_connect(GTK_OBJECT(browser->mozEmbed), "dom_mouse_up", + GTK_SIGNAL_FUNC(dom_mouse_up_cb), browser); + gtk_signal_connect(GTK_OBJECT(browser->mozEmbed), "dom_mouse_click", + GTK_SIGNAL_FUNC(dom_mouse_click_cb), browser); + gtk_signal_connect(GTK_OBJECT(browser->mozEmbed), "dom_mouse_dbl_click", + GTK_SIGNAL_FUNC(dom_mouse_dbl_click_cb), browser); + gtk_signal_connect(GTK_OBJECT(browser->mozEmbed), "dom_mouse_over", + GTK_SIGNAL_FUNC(dom_mouse_over_cb), browser); + gtk_signal_connect(GTK_OBJECT(browser->mozEmbed), "dom_mouse_out", + GTK_SIGNAL_FUNC(dom_mouse_out_cb), browser); + gtk_signal_connect(GTK_OBJECT(browser->mozEmbed), "dom_activate", + GTK_SIGNAL_FUNC(dom_activate_cb), browser); + gtk_signal_connect(GTK_OBJECT(browser->mozEmbed), "dom_focus_in", + GTK_SIGNAL_FUNC(dom_focus_in_cb), browser); + gtk_signal_connect(GTK_OBJECT(browser->mozEmbed), "dom_focus_out", + GTK_SIGNAL_FUNC(dom_focus_out_cb), browser); + g_signal_connect(browser->mozEmbed, "dom-context-menu", + GTK_SIGNAL_FUNC(dom_context_menu_cb), browser); + // hookup to when the window is destroyed + gtk_signal_connect(GTK_OBJECT(browser->mozEmbed), "destroy", + GTK_SIGNAL_FUNC(destroy_cb), browser); + + // set the chrome type so it's stored in the object + gecko_embed_set_chrome_mask(GECKO_EMBED(browser->mozEmbed), + actualChromeMask); + + gtk_widget_show_all (browser->topLevelVBox); + + return browser; +} + +void +set_browser_visibility (TestGeckoBrowser *browser, gboolean visibility) +{ + if (!visibility) + { + gtk_widget_hide(browser->topLevelWindow); + return; + } + + if (browser->menuBarOn) + gtk_widget_show_all(browser->menuBar); + else + gtk_widget_hide_all(browser->menuBar); + + // since they are on the same line here... + if (browser->toolBarOn || browser->locationBarOn) + gtk_widget_show_all(browser->toolbarHBox); + else + gtk_widget_hide_all(browser->toolbarHBox); + + if (browser->statusBarOn) + gtk_widget_show_all(browser->progressAreaHBox); + else + gtk_widget_hide_all(browser->progressAreaHBox); + + gtk_widget_show(browser->mozEmbed); + gtk_widget_show(browser->topLevelVBox); + gtk_widget_show(browser->topLevelWindow); +} + +void +back_clicked_cb (GtkButton *button, TestGeckoBrowser *browser) +{ + gecko_embed_go_back(GECKO_EMBED(browser->mozEmbed)); +} + +void +stop_clicked_cb (GtkButton *button, TestGeckoBrowser *browser) +{ + g_print("stop_clicked_cb\n"); + gecko_embed_stop_load(GECKO_EMBED(browser->mozEmbed)); +} + +void +forward_clicked_cb (GtkButton *button, TestGeckoBrowser *browser) +{ + g_print("forward_clicked_cb\n"); + gecko_embed_go_forward(GECKO_EMBED(browser->mozEmbed)); +} + +void +reload_clicked_cb (GtkButton *button, TestGeckoBrowser *browser) +{ + g_print("reload_clicked_cb\n"); + GdkModifierType state = (GdkModifierType)0; + gint x, y; + gdk_window_get_pointer(NULL, &x, &y, &state); + + gecko_embed_reload(GECKO_EMBED(browser->mozEmbed), + (state & GDK_SHIFT_MASK) ? + GECKO_EMBED_FLAG_RELOADBYPASSCACHE : + GECKO_EMBED_FLAG_RELOADNORMAL); +} + +void +stream_clicked_cb (GtkButton *button, TestGeckoBrowser *browser) +{ + const char *data; + const char *data2; + data = "<html>Hi"; + data2 = " there</html>\n"; + g_print("stream_clicked_cb\n"); + gecko_embed_open_stream(GECKO_EMBED(browser->mozEmbed), + "file://", "text/html"); + gecko_embed_append_data(GECKO_EMBED(browser->mozEmbed), + data, strlen(data)); + gecko_embed_append_data(GECKO_EMBED(browser->mozEmbed), + data2, strlen(data2)); + gecko_embed_close_stream(GECKO_EMBED(browser->mozEmbed)); +} + +void +url_activate_cb (GtkEditable *widget, TestGeckoBrowser *browser) +{ + gchar *text = gtk_editable_get_chars(widget, 0, -1); + g_print("loading url %s\n", text); + gecko_embed_load_url(GECKO_EMBED(browser->mozEmbed), text); + g_free(text); +} + +void +menu_open_new_cb (GtkMenuItem *menuitem, TestGeckoBrowser *browser) +{ + g_print("opening new browser.\n"); + TestGeckoBrowser *newBrowser = + new_gecko_browser(GECKO_EMBED_FLAG_DEFAULTCHROME); + gtk_widget_set_usize(newBrowser->mozEmbed, 400, 400); + set_browser_visibility(newBrowser, TRUE); +} + +void +menu_stream_cb (GtkMenuItem *menuitem, TestGeckoBrowser *browser) +{ + g_print("menu_stream_cb\n"); + const char *data; + const char *data2; + data = "<html>Hi"; + data2 = " there</html>\n"; + g_print("stream_clicked_cb\n"); + gecko_embed_open_stream(GECKO_EMBED(browser->mozEmbed), + "file://", "text/html"); + gecko_embed_append_data(GECKO_EMBED(browser->mozEmbed), + data, strlen(data)); + gecko_embed_append_data(GECKO_EMBED(browser->mozEmbed), + data2, strlen(data2)); + gecko_embed_close_stream(GECKO_EMBED(browser->mozEmbed)); +} + +void +menu_close_cb (GtkMenuItem *menuitem, TestGeckoBrowser *browser) +{ + gtk_widget_destroy(browser->topLevelWindow); +} + +void +menu_quit_cb (GtkMenuItem *menuitem, TestGeckoBrowser *browser) +{ + TestGeckoBrowser *tmpBrowser; + GList *tmp_list = browser_list; + tmpBrowser = (TestGeckoBrowser *)tmp_list->data; + while (tmpBrowser) { + tmp_list = tmp_list->next; + gtk_widget_destroy(tmpBrowser->topLevelWindow); + tmpBrowser = (TestGeckoBrowser *)tmp_list->data; + } +} + +gboolean +delete_cb(GtkWidget *widget, GdkEventAny *event, TestGeckoBrowser *browser) +{ + g_print("delete_cb\n"); + gtk_widget_destroy(widget); + return TRUE; +} + +void +destroy_cb (GtkWidget *widget, TestGeckoBrowser *browser) +{ + GList *tmp_list; + g_print("destroy_cb\n"); + num_browsers--; + tmp_list = g_list_find(browser_list, browser); + browser_list = g_list_remove_link(browser_list, tmp_list); + if (browser->tempMessage) + g_free(browser->tempMessage); + if (num_browsers == 0) + gtk_main_quit(); +} + +void +location_changed_cb (GeckoEmbed *embed, TestGeckoBrowser *browser) +{ + char *newLocation; + int newPosition = 0; + g_print("location_changed_cb\n"); + newLocation = gecko_embed_get_location(embed); + if (newLocation) + { + gtk_editable_delete_text(GTK_EDITABLE(browser->urlEntry), 0, -1); + gtk_editable_insert_text(GTK_EDITABLE(browser->urlEntry), + newLocation, strlen(newLocation), &newPosition); + g_free(newLocation); + } + else + g_print("failed to get location!\n"); + // always make sure to clear the tempMessage. it might have been + // set from the link before a click and we wouldn't have gotten the + // callback to unset it. + update_temp_message(browser, 0); + // update the nav buttons on a location change + update_nav_buttons(browser); +} + +void +title_changed_cb (GeckoEmbed *embed, TestGeckoBrowser *browser) +{ + char *newTitle; + g_print("title_changed_cb\n"); + newTitle = gecko_embed_get_title(embed); + if (newTitle) + { + gtk_window_set_title(GTK_WINDOW(browser->topLevelWindow), newTitle); + g_free(newTitle); + } + +} + +void +load_started_cb (GeckoEmbed *embed, TestGeckoBrowser *browser) +{ + g_print("load_started_cb\n"); + gtk_widget_set_sensitive(browser->stopButton, TRUE); + gtk_widget_set_sensitive(browser->reloadButton, FALSE); + browser->loadPercent = 0; + browser->bytesLoaded = 0; + browser->maxBytesLoaded = 0; + update_status_bar_text(browser); +} + +void +load_finished_cb (GeckoEmbed *embed, TestGeckoBrowser *browser) +{ + g_print("load_finished_cb\n"); + gtk_widget_set_sensitive(browser->stopButton, FALSE); + gtk_widget_set_sensitive(browser->reloadButton, TRUE); + browser->loadPercent = 0; + browser->bytesLoaded = 0; + browser->maxBytesLoaded = 0; + update_status_bar_text(browser); + gtk_progress_set_percentage(GTK_PROGRESS(browser->progressBar), 0); +} + + +void +net_state_change_cb (GeckoEmbed *embed, gint flags, guint status, + TestGeckoBrowser *browser) +{ + g_print("net_state_change_cb %d\n", flags); + if (flags & GECKO_EMBED_FLAG_IS_REQUEST) { + if (flags & GECKO_EMBED_FLAG_REDIRECTING) + browser->statusMessage = "Redirecting to site..."; + else if (flags & GECKO_EMBED_FLAG_TRANSFERRING) + browser->statusMessage = "Transferring data from site..."; + else if (flags & GECKO_EMBED_FLAG_NEGOTIATING) + browser->statusMessage = "Waiting for authorization..."; + } + + if (status == GECKO_EMBED_STATUS_FAILED_DNS) + browser->statusMessage = "Site not found."; + else if (status == GECKO_EMBED_STATUS_FAILED_CONNECT) + browser->statusMessage = "Failed to connect to site."; + else if (status == GECKO_EMBED_STATUS_FAILED_TIMEOUT) + browser->statusMessage = "Failed due to connection timeout."; + else if (status == GECKO_EMBED_STATUS_FAILED_USERCANCELED) + browser->statusMessage = "User canceled connecting to site."; + + if (flags & GECKO_EMBED_FLAG_IS_DOCUMENT) { + if (flags & GECKO_EMBED_FLAG_START) + browser->statusMessage = "Loading site..."; + else if (flags & GECKO_EMBED_FLAG_STOP) + browser->statusMessage = "Done."; + } + + update_status_bar_text(browser); + +} + +void net_state_change_all_cb (GeckoEmbed *embed, const char *uri, + gint flags, guint status, + TestGeckoBrowser *browser) +{ + // g_print("net_state_change_all_cb %s %d %d\n", uri, flags, status); +} + +void progress_change_cb (GeckoEmbed *embed, gint cur, gint max, + TestGeckoBrowser *browser) +{ + g_print("progress_change_cb cur %d max %d\n", cur, max); + + // avoid those pesky divide by zero errors + if (max < 1) + { + gtk_progress_set_activity_mode(GTK_PROGRESS(browser->progressBar), FALSE); + browser->loadPercent = 0; + browser->bytesLoaded = cur; + browser->maxBytesLoaded = 0; + update_status_bar_text(browser); + } + else + { + browser->bytesLoaded = cur; + browser->maxBytesLoaded = max; + if (cur > max) + browser->loadPercent = 100; + else + browser->loadPercent = (cur * 100) / max; + update_status_bar_text(browser); + gtk_progress_set_percentage(GTK_PROGRESS(browser->progressBar), browser->loadPercent / 100.0); + } + +} + +void progress_change_all_cb (GeckoEmbed *embed, const char *uri, + gint cur, gint max, + TestGeckoBrowser *browser) +{ + //g_print("progress_change_all_cb %s cur %d max %d\n", uri, cur, max); +} + +void +link_message_cb (GeckoEmbed *embed, TestGeckoBrowser *browser) +{ + char *message; + g_print("link_message_cb\n"); + message = gecko_embed_get_link_message(embed); + if (!message || !*message) + update_temp_message(browser, 0); + else + update_temp_message(browser, message); + if (message) + g_free(message); +} + +void +js_status_cb (GeckoEmbed *embed, TestGeckoBrowser *browser) +{ + char *message; + g_print("js_status_cb\n"); + message = gecko_embed_get_js_status(embed); + if (!message || !*message) + update_temp_message(browser, 0); + else + update_temp_message(browser, message); + if (message) + g_free(message); +} + +void +new_window_cb (GeckoEmbed *embed, GeckoEmbed **newEmbed, guint chromemask, TestGeckoBrowser *browser) +{ + g_print("new_window_cb\n"); + g_print("embed is %p chromemask is %d\n", (void *)embed, chromemask); + TestGeckoBrowser *newBrowser = new_gecko_browser(chromemask); + gtk_widget_set_usize(newBrowser->mozEmbed, 400, 400); + *newEmbed = GECKO_EMBED(newBrowser->mozEmbed); + g_print("new browser is %p\n", (void *)*newEmbed); +} + +void +visibility_cb (GeckoEmbed *embed, gboolean visibility, TestGeckoBrowser *browser) +{ + g_print("visibility_cb %d\n", visibility); + set_browser_visibility(browser, visibility); +} + +void +destroy_brsr_cb (GeckoEmbed *embed, TestGeckoBrowser *browser) +{ + g_print("destroy_brsr_cb\n"); + gtk_widget_destroy(browser->topLevelWindow); +} + +gint +open_uri_cb (GeckoEmbed *embed, const char *uri, TestGeckoBrowser *browser) +{ + g_print("open_uri_cb %s\n", uri); + + // interrupt this test load + if (!strcmp(uri, "http://people.redhat.com/blizzard/monkeys.txt")) + return TRUE; + // don't interrupt anything + return FALSE; +} + +void +size_to_cb (GeckoEmbed *embed, gint width, gint height, + TestGeckoBrowser *browser) +{ + g_print("*** size_to_cb %d %d\n", width, height); + gtk_widget_set_usize(browser->mozEmbed, width, height); +} + +gboolean dom_key_down_cb (GeckoEmbed *embed, + GeckoDOMEvent *gecko_event, + TestGeckoBrowser *browser) +{ + nsIDOMEvent *domevent = gecko_dom_event_get_I (gecko_event); + nsCOMPtr<nsIDOMKeyEvent> event (do_QueryInterface (domevent)); + + PRUint32 keyCode = 0; + // g_print("dom_key_down_cb\n"); + event->GetKeyCode(&keyCode); + // g_print("key code is %d\n", keyCode); + return NS_OK; +} + +gboolean dom_key_press_cb (GeckoEmbed *embed, + GeckoDOMEvent *gecko_event, + TestGeckoBrowser *browser) +{ + nsIDOMEvent *domevent = gecko_dom_event_get_I (gecko_event); + nsCOMPtr<nsIDOMKeyEvent> event (do_QueryInterface (domevent)); + + PRUint32 keyCode = 0; + // g_print("dom_key_press_cb\n"); + event->GetCharCode(&keyCode); + // g_print("char code is %d\n", keyCode); + return NS_OK; +} + +gboolean dom_key_up_cb (GeckoEmbed *embed, + GeckoDOMEvent *gecko_event, + TestGeckoBrowser *browser) +{ + nsIDOMEvent *domevent = gecko_dom_event_get_I (gecko_event); + nsCOMPtr<nsIDOMKeyEvent> event (do_QueryInterface (domevent)); + + PRUint32 keyCode = 0; + // g_print("dom_key_up_cb\n"); + event->GetKeyCode(&keyCode); + // g_print("key code is %d\n", keyCode); + return NS_OK; +} + +gboolean dom_mouse_down_cb (GeckoEmbed *embed, + GeckoDOMEvent *gecko_event, + TestGeckoBrowser *browser) +{ + // g_print("dom_mouse_down_cb\n"); + return NS_OK; + } + +gboolean dom_mouse_up_cb (GeckoEmbed *embed, + GeckoDOMEvent *gecko_event, + TestGeckoBrowser *browser) +{ + // g_print("dom_mouse_up_cb\n"); + return NS_OK; +} + +gboolean dom_mouse_click_cb (GeckoEmbed *embed, + GeckoDOMEvent *gecko_event, + TestGeckoBrowser *browser) +{ + nsIDOMEvent *domevent = gecko_dom_event_get_I (gecko_event); + nsCOMPtr<nsIDOMMouseEvent> event (do_QueryInterface (domevent)); + + // g_print("dom_mouse_click_cb\n"); + PRUint16 button; + event->GetButton(&button); + printf("button was %d\n", button); + return NS_OK; +} + +gboolean dom_mouse_dbl_click_cb (GeckoEmbed *embed, + GeckoDOMEvent *gecko_event, + TestGeckoBrowser *browser) +{ + // g_print("dom_mouse_dbl_click_cb\n"); + return NS_OK; +} + +gboolean dom_mouse_over_cb (GeckoEmbed *embed, + GeckoDOMEvent *gecko_event, + TestGeckoBrowser *browser) +{ + //g_print("dom_mouse_over_cb\n"); + return NS_OK; +} + +gboolean dom_mouse_out_cb (GeckoEmbed *embed, + GeckoDOMEvent *gecko_event, + TestGeckoBrowser *browser) +{ + //g_print("dom_mouse_out_cb\n"); + return NS_OK; +} + +gboolean dom_activate_cb (GeckoEmbed *embed, + GeckoDOMEvent *gecko_event, + TestGeckoBrowser *browser) +{ + //g_print("dom_activate_cb\n"); + return NS_OK; +} + +gboolean dom_focus_in_cb (GeckoEmbed *embed, + GeckoDOMEvent *gecko_event, + TestGeckoBrowser *browser) +{ + //g_print("dom_focus_in_cb\n"); + return NS_OK; +} + +gboolean dom_focus_out_cb (GeckoEmbed *embed, + GeckoDOMEvent *gecko_event, + TestGeckoBrowser *browser) +{ + //g_print("dom_focus_out_cb\n"); + return NS_OK; +} + +gboolean dom_context_menu_cb (GeckoEmbed *embed, + GeckoDOMEvent *gecko_event, + TestGeckoBrowser *browser) +{ + g_print("dom_context_menu_cb\n"); + return NS_OK; +} + +void new_window_orphan_cb (GeckoEmbedSingle *embed, + GeckoEmbed **retval, guint chromemask, + gpointer data) +{ + g_print("new_window_orphan_cb\n"); + g_print("chromemask is %d\n", chromemask); + TestGeckoBrowser *newBrowser = new_gecko_browser(chromemask); + *retval = GECKO_EMBED(newBrowser->mozEmbed); + g_print("new browser is %p\n", (void *)*retval); +} + +// utility functions + +void +update_status_bar_text(TestGeckoBrowser *browser) +{ + gchar message[256]; + + gtk_statusbar_pop(GTK_STATUSBAR(browser->statusBar), 1); + if (browser->tempMessage) + gtk_statusbar_push(GTK_STATUSBAR(browser->statusBar), 1, browser->tempMessage); + else + { + if (browser->loadPercent) + { + g_snprintf(message, 255, "%s (%d%% complete, %d bytes of %d loaded)", browser->statusMessage, browser->loadPercent, browser->bytesLoaded, browser->maxBytesLoaded); + } + else if (browser->bytesLoaded) + { + g_snprintf(message, 255, "%s (%d bytes loaded)", browser->statusMessage, browser->bytesLoaded); + } + else if (browser->statusMessage == NULL) + { + g_snprintf(message, 255, " "); + } + else + { + g_snprintf(message, 255, "%s", browser->statusMessage); + } + gtk_statusbar_push(GTK_STATUSBAR(browser->statusBar), 1, message); + } +} + +void +update_temp_message(TestGeckoBrowser *browser, const char *message) +{ + if (browser->tempMessage) + g_free(browser->tempMessage); + if (message) + browser->tempMessage = g_strdup(message); + else + browser->tempMessage = 0; + // now that we've updated the temp message, redraw the status bar + update_status_bar_text(browser); +} + + +void +update_nav_buttons (TestGeckoBrowser *browser) +{ + gboolean can_go_back; + gboolean can_go_forward; + can_go_back = gecko_embed_can_go_back(GECKO_EMBED(browser->mozEmbed)); + can_go_forward = gecko_embed_can_go_forward(GECKO_EMBED(browser->mozEmbed)); + if (can_go_back) + gtk_widget_set_sensitive(browser->backButton, TRUE); + else + gtk_widget_set_sensitive(browser->backButton, FALSE); + if (can_go_forward) + gtk_widget_set_sensitive(browser->forwardButton, TRUE); + else + gtk_widget_set_sensitive(browser->forwardButton, FALSE); + } |