Logo Search packages:      
Sourcecode: galeon version File versions

mozilla-embed.cpp

/*
 *  Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2, or (at your option)
 *  any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "gtkmozembed.h"
#include "gul-string.h"
#include "galeon-embed-utils.h"
#include "galeon-embed.h"
#include "mozilla-embed.h"
#include "GaleonWrapper.h"
#include "EventContext.h"
#include "galeon-debug.h"
#include "GaleonUtils.h"
#include "GulString.h"

#include <glib/gi18n.h>

#include <nsIURI.h>
#include <nsIURL.h>
#include <nsMemory.h>
#include <nsIRequest.h>
#include <nsIWebProgressListener.h>
#include <nsIWindowWatcher.h>
#include <nsIDOMStyleSheetList.h>
#include <nsIDOMStyleSheet.h>
#include <nsIDOMHTMLLinkElement.h>
#include <nsIStyleSheet.h>
#include <nsIDOMDocument.h>
#include <nsIServiceManager.h>
#include <nsIPrintSettings.h>
#include <nsIDOMWindow.h>

#include <math.h>

#define WINDOWWATCHER_CONTRACTID "@mozilla.org/embedcomp/window-watcher;1"

static void
galeon_embed_init (GaleonEmbedClass *embed_class);


static gboolean
mozilla_embed_get_uri_parent (const char *uri, GulCString &parent);

static EmbedSecurityLevel
mozilla_embed_security_level (PRUint32 state);


typedef enum
{
      MOZILLA_EMBED_LOAD_STARTED,
      MOZILLA_EMBED_LOAD_REDIRECTING,
      MOZILLA_EMBED_LOAD_LOADING,
      MOZILLA_EMBED_LOAD_STOPPED
} MozillaEmbedLoadState;


struct MozillaEmbedPrivate
{
      MozillaEmbedPrivate() : wrapper(NULL), security_state(-1), 
                        load_state (MOZILLA_EMBED_LOAD_STARTED),
                        loaded_url (FALSE), loading_url(0),
                        focus_timeout(0)
      { /* nothing */ }

      GaleonWrapper *wrapper;
      gint security_state;
      MozillaEmbedLoadState load_state;

      /* LOAD HACK: When loading a site, either initially, or when
       * loaded from "about:blank" remember the url that was
       * attempted to load, and always return that for the
       * get_location, and also fake it so that refresh loads that
       * url
       *
       * Note that we only do this hack for the "about:blank" case
       * when the first page was "about:blank"
       */
      gboolean loaded_url; //!< Has a web page been loaded
      gchar *loading_url;  //!< The URL we are trying to load


      // Timeout for the focus hack
      guint focus_timeout;
};

static GObjectClass *parent_class = NULL;

G_DEFINE_TYPE_WITH_CODE (MozillaEmbed, mozilla_embed, GTK_TYPE_MOZ_EMBED,
                   G_IMPLEMENT_INTERFACE (GALEON_TYPE_EMBED,
                                    galeon_embed_init));


/****************************************************************
 * Start Dirty Mouse Wheel hack
 *
 * This hack is needed as the mozilla embed object doesn't emit a
 * zoom changed signal, and you can't seem to be able to capture
 * the mouse wheel movements in the parent widgets. This is also
 * abusing the fact that we know that gtkmozembed object is also
 * a GtkContainer containing the real widget.
 ****************************************************************/

static gint before_zoom_val = 0;

/**
 *  This function will get called before the actual scroll-event
 *  has been delivered to the widget, this allows us to get the current
 *  zoom value
 */
static gboolean
mozilla_embed_child_scroll_event_cb (GtkWidget    *widget, 
                             GdkEvent     *event,
                             MozillaEmbed *embed)
{
      before_zoom_val = galeon_embed_zoom_get (GALEON_EMBED (embed));
      return FALSE;
}


/**
 *  This gets called after the scroll event has been delivered to the
 *  widget. We can get the new zoom value, and emit the appropriate
 *  signal if the zoom factor changed 
 */
static gboolean
mozilla_embed_child_event_after_cb (GtkWidget    *widget, 
                            GdkEvent     *event,
                            MozillaEmbed *embed)
{
      int zoom;
      if (event->type != GDK_SCROLL) return FALSE;

      zoom = galeon_embed_zoom_get (GALEON_EMBED (embed));
      if (zoom != before_zoom_val)
      {
            g_signal_emit_by_name (embed, "ge_zoom_change", zoom);
      }
      return FALSE;
}


/**
 * Timeout so that the focus is set correctly for the Mozilla Embed
 * this needs to be in a timeout, otherwise for some reason it doesn't seem
 * to work correctly
 */
static gboolean
activate_focus_timeout_cb (gpointer pointer)
{
      MozillaEmbed *embed = MOZILLA_EMBED (pointer);

      embed->priv->focus_timeout = 0;

      if (embed->priv->wrapper)
      {
            embed->priv->wrapper->FocusActivate();
      }

      return FALSE;
}


static gboolean
deactivate_focus_timeout_cb (gpointer pointer)
{
      MozillaEmbed *embed = MOZILLA_EMBED (pointer);

      embed->priv->focus_timeout = 0;

      if (embed->priv->wrapper)
      {
            embed->priv->wrapper->FocusDeactivate();
      }

      return FALSE;
}


/**
 * Hack: Whenever the *user* wants the focus on the embed there's always going
 * to be an associated GdkEvent (click on embed, enter on location entry, etc...)
 * If the event doesn't exist (none being processed at the moment) we'll assume
 * it's Mozilla trying to steal the focus after done loading the page.  In that
 * case stop the focus from moving anywhere.
 *
 * Yet another attempt to fix http://bugzilla.gnome.org/show_bug.cgi?id=72125
 * and work around https://bugzilla.mozilla.org/show_bug.cgi?id=210373
 */
static void
mozilla_embed_child_grab_focus_cb (GtkWidget *widget, MozillaEmbed *embed)
{
      GdkEvent *event;
      GtkWidget *focused, *toplevel;
       
      event = gtk_get_current_event ();

      if (event)
      {
            gdk_event_free (event);
            return;
      }

      /* Find the GtkWidget that currently has focus, and if it
       * is the MozContainer, find the corresponding MozillaEmbed */
      toplevel = gtk_widget_get_toplevel (widget);
      focused = gtk_window_get_focus (GTK_WINDOW (toplevel));

      if (focused && !strcmp ("MozContainer", G_OBJECT_TYPE_NAME (focused)))
      {
            focused = gtk_widget_get_parent (focused);
      }

      if (focused && GTK_WIDGET (embed) != focused)
      {
            g_signal_stop_emission_by_name (widget, "grab-focus");

            /* Focus was trying to move, so deactivate embed which
             * attempted to grab it */
            if (embed->priv->focus_timeout)
            {
                  g_source_remove (embed->priv->focus_timeout);
            }
            embed->priv->focus_timeout =
                  g_timeout_add (0, deactivate_focus_timeout_cb, embed);


            if (MOZILLA_IS_EMBED (focused))
            {
                  MozillaEmbed *membed = MOZILLA_EMBED (focused);

                  if (membed->priv->focus_timeout)
                  {
                        g_source_remove (membed->priv->focus_timeout);
                  }

                  /* And if the old widget was a mozille embed, 
                   * let it grab the focus back again */
                  membed->priv->focus_timeout = 
                        g_timeout_add (0, activate_focus_timeout_cb, membed);
            }
      }
}

/**
 *  Hack: We know that the parent class is really GtkBin object, so
 *  hook onto the "add" signal and connect appropriate signals for the
 *  child
 */
static void
mozilla_embed_add (GtkContainer *container, GtkWidget *widget)
{
      MozillaEmbed *embed = MOZILLA_EMBED (container);

      GTK_CONTAINER_CLASS(parent_class)->add (container, widget);

      g_object_connect (widget,
                    "signal::scroll-event", mozilla_embed_child_scroll_event_cb, embed,
                    "signal::event-after", mozilla_embed_child_event_after_cb, embed,
                    "signal::grab-focus", mozilla_embed_child_grab_focus_cb, embed,
                    NULL);
}


/**
 *  If the child is removed, remove the signals that we attached 
 */
static void
mozilla_embed_remove (GtkContainer *container, GtkWidget *widget)
{
      MozillaEmbed *embed = MOZILLA_EMBED (container);

      g_object_disconnect (widget,
                       "any_signal::scroll-event", mozilla_embed_child_scroll_event_cb, embed,
                       "any_signal::event-after", mozilla_embed_child_event_after_cb, embed,
                       "any_signal::grab-focus", mozilla_embed_child_grab_focus_cb, embed,
                       NULL);

      GTK_CONTAINER_CLASS(parent_class)->remove (container, widget);
}

/*************************************************************
 * End dirty mouse wheel zoom hack
 *************************************************************/

static void
mozilla_embed_realize (GtkWidget *widget)
{
      MozillaEmbedPrivate *mpriv = MOZILLA_EMBED (widget)->priv;

      GTK_WIDGET_CLASS(parent_class)->realize (widget);

      nsresult result;
      result = mpriv->wrapper->Init (GTK_MOZ_EMBED (widget));

      if (NS_FAILED(result))
      {
                  g_warning ("Browser initialization failed");
      }
}

static void 
mozilla_embed_grab_focus (GtkWidget *widget)
{
      GtkWidget *child = GTK_BIN(widget)->child;

      // when the embed (that's us, not Mozilla) wants to grab the focus we
      // want GtkMozEmbed to get it, really, so skip the focus hack above
      // (otherwise the event check will block focus grab when loading a new
      // URL from command line)

      g_signal_handlers_block_by_func (child, (void*)mozilla_embed_child_grab_focus_cb, widget);
      gtk_widget_grab_focus (child);
      g_signal_handlers_unblock_by_func (child, (void*)mozilla_embed_child_grab_focus_cb, widget);
}

static void
mozilla_embed_init (MozillaEmbed *embed)
{
        embed->priv          = new MozillaEmbedPrivate;
      embed->priv->wrapper = new GaleonWrapper ();

      LOG ("MozillaEmbed ctor (%p)", embed);
}

static void
mozilla_embed_finalize (GObject *object)
{
        MozillaEmbed *embed;

        g_return_if_fail (object != NULL);
        g_return_if_fail (MOZILLA_IS_EMBED (object));

      embed = MOZILLA_EMBED (object);
      
      g_return_if_fail (embed->priv != NULL);
      
      if (embed->priv->wrapper)
      {
            embed->priv->wrapper->Destroy();
            delete embed->priv->wrapper;
            embed->priv->wrapper = NULL;
      }

      if (embed->priv->focus_timeout)
      {
            g_source_remove (embed->priv->focus_timeout);
      }

      g_free (embed->priv->loading_url);

      delete embed->priv;
      
        G_OBJECT_CLASS (parent_class)->finalize (object);

      LOG ("MozillaEmbed dtor (%p)", embed);
}

gpointer
mozilla_embed_get_galeon_wrapper (MozillaEmbed *embed)
{
      return embed->priv->wrapper;
}

static void
impl_load_url (GaleonEmbed *embed, 
               const char *url)
{
      char *clean_url;

        clean_url = gul_string_remove_outside_whitespace (url);

        gtk_moz_embed_load_url (GTK_MOZ_EMBED(embed),
                                clean_url);

      /* LOAD HACK: If we haven't loaded a url yet, remember this one, 
       * and flag that we are trying to load this url */
      MozillaEmbed *membed = MOZILLA_EMBED (embed);
      if (!membed->priv->loaded_url)
      {
            g_free (membed->priv->loading_url);
            membed->priv->loading_url = clean_url;

            /* Fake a "location" signal, so that the layer above picks up
             * this url, and doesn't think there is no current url */
            g_signal_emit_by_name (membed, "ge_location");
            return;
      }

      g_free (clean_url);

      return;
}

static void
impl_stop_load (GaleonEmbed *embed)
{
      gtk_moz_embed_stop_load (GTK_MOZ_EMBED(embed)); 
}

static gboolean
impl_can_go_back (GaleonEmbed *embed)
{
      return gtk_moz_embed_can_go_back (GTK_MOZ_EMBED(embed));
}

static gboolean
impl_can_go_forward (GaleonEmbed *embed)
{
      return gtk_moz_embed_can_go_forward (GTK_MOZ_EMBED(embed));
}

static gboolean
impl_can_go_up (GaleonEmbed *embed)
{
      char *location;
      gboolean result;

      location = galeon_embed_get_location (embed, TRUE, FALSE);
      if (!location) return FALSE;

      GulCString parent;
      result =  mozilla_embed_get_uri_parent (location, parent);
      g_free (location);

      return result;
}

static GSList *
impl_get_go_up_list (GaleonEmbed *embed)
{
      char *location;
      char *s;
      GSList * l = NULL;

      location = galeon_embed_get_location (embed, TRUE, FALSE);

      g_return_val_if_fail (location != NULL, NULL);
      
      s = location;
      GulCString parent;
      while (mozilla_embed_get_uri_parent (s, parent))
      {
            s = g_strdup (parent.get());
            l = g_slist_prepend (l, s);
      }

      g_free (location);
      return g_slist_reverse (l);
}

static void
impl_go_back (GaleonEmbed *embed)
{
      gtk_moz_embed_go_back (GTK_MOZ_EMBED(embed));
}
            
static void
impl_go_forward (GaleonEmbed *embed)
{
      gtk_moz_embed_go_forward (GTK_MOZ_EMBED(embed));
}

static void
impl_go_up (GaleonEmbed *embed)
{
      char *uri;
      
      uri = galeon_embed_get_location (embed, TRUE, FALSE);
      g_return_if_fail (uri != NULL);
      
      GulCString parent_uri;
      gboolean ret = mozilla_embed_get_uri_parent (uri, parent_uri);
      g_return_if_fail (ret);
      
      galeon_embed_load_url (embed, parent_uri.get());
}

static gboolean
mozilla_embed_get_uri_parent (const char *aUri, GulCString &aParent)
{
        nsresult rv;

        nsCOMPtr<nsIURI> uri;
        rv = GaleonUtils::NewURI (getter_AddRefs(uri), GulDependentCString (aUri));
        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) */
      GulCString scheme;
      rv = uri->GetScheme (scheme);
      if (NS_FAILED(rv) || !scheme.Length()) return FALSE;
      if (scheme.Equals ("chrome")) return FALSE;

      GulCString path;
      rv = uri->GetPath(path);
      if (NS_FAILED(rv)) return FALSE;

      const char *slash = strrchr (path.get(), '/');
      if (!slash || path.Equals("/"))
      {
            return FALSE;
      }

      if (slash[1] == '\0')
      {
            // ends with a slash - a directory, go to parent
            rv = uri->Resolve (NS_LITERAL_CSTRING(".."), aParent);
      }
      else
      {
            // otherwise it's a file, go to the directory
            rv = uri->Resolve (NS_LITERAL_CSTRING("."), aParent);
      }
      return NS_SUCCEEDED(rv) ? TRUE : FALSE;
}

static gboolean
impl_render_data (GaleonEmbed *embed, 
                  const char *data,
                  guint32 len,
                  const char *base_uri, 
                  const char *mime_type)
{
      gtk_moz_embed_render_data (GTK_MOZ_EMBED(embed),
                           data,
                           len,
                           base_uri,
                           mime_type);
      
      return TRUE;
}

static gboolean
impl_open_stream (GaleonEmbed *embed,
                  const char *base_uri,
                  const char *mime_type)
{
      gtk_moz_embed_open_stream (GTK_MOZ_EMBED(embed),
                           base_uri, mime_type);
      
      return TRUE;
}

static void
impl_append_data (GaleonEmbed *embed,
                  const char *data, 
                  guint32 len)
{
      gtk_moz_embed_append_data (GTK_MOZ_EMBED(embed),
                           data, len);
}

static void
impl_close_stream (GaleonEmbed *embed)
{
      gtk_moz_embed_close_stream (GTK_MOZ_EMBED(embed));
}

static char *
impl_get_title (GaleonEmbed *embed)
{
      return gtk_moz_embed_get_title (GTK_MOZ_EMBED(embed));
}

/* This can be used to get the real location of the currently
 * loaded page. It bypasses gtkmozembed, and the loading_page
 * hack, to get the actual location mozilla thinks it has loaded
 */
char *
mozilla_embed_get_real_location (MozillaEmbed *embed)
{
      GulCString url;
      GaleonWrapper *wrapper = MOZILLA_EMBED(embed)->priv->wrapper;
      nsresult rv = wrapper->GetRealURL (url);
      if (NS_FAILED (rv)) return 0;

      return (!url.IsEmpty()) ? g_strdup (url.get()) : NULL;
}

static char *
impl_get_location (GaleonEmbed *embed, 
                   gboolean toplevel,
                   gboolean requested)
{
      char *l;
      nsresult rv;
      GulCString url;
      GaleonWrapper *wrapper;

      wrapper = MOZILLA_EMBED(embed)->priv->wrapper;

      /* FIXME !toplevel requested not implemented */
      
      if (toplevel)
      {
            l = gtk_moz_embed_get_location 
                  (GTK_MOZ_EMBED(embed));
      }
      else if (!toplevel)
      {
            rv = wrapper->GetDocumentUrl (url);
            l = (NS_SUCCEEDED (rv) && !url.IsEmpty()) ?
                 g_strdup (url.get()) : NULL;         
      }
      else if (requested)
      {
            l = mozilla_embed_get_real_location (MOZILLA_EMBED (embed));
      
      }

      /* LOAD HACK: If we are trying to load a url, and we didn't
       * manage it (the location is still "about:blank"), return the
       * attempted url to the caller, so that they know the right thing */
      MozillaEmbed *membed = MOZILLA_EMBED (embed);
      if (!membed->priv->loaded_url && membed->priv->loading_url && l &&
          !strcmp ("about:blank", l))
      {
            g_free (l);
            l = g_strdup (membed->priv->loading_url);
      }

      return l;
}

static void
impl_reload (GaleonEmbed *embed, 
             EmbedReloadFlags flags)
{
      char *location;
      GtkMozEmbedReloadFlags reloadFlags = GTK_MOZ_EMBED_FLAG_RELOADNORMAL;
      
      MozillaEmbed *membed = MOZILLA_EMBED (embed);
      GaleonWrapper *wrapper = MOZILLA_EMBED(embed)->priv->wrapper;
      
      if (flags == EMBED_RELOAD_FRAME)
      {
            wrapper->ReloadFrame();
            return;
      }
      
      location = mozilla_embed_get_real_location (membed);
      if (!location) return;

      /* LOAD HACK: If we are loading a url, but it didn't load
       * properly, then load the url that was originally requested */
      if (!membed->priv->loaded_url && membed->priv->loading_url &&
          !strcmp (location,"about:blank"))
      {
            galeon_embed_load_url (embed, membed->priv->loading_url);
            g_free (location);
            return;
      } 

      /* NOTE, bypassing the proxy just tells the proxy not to read from
       * its cache, it doesn't actually talk to the server directly */

      /* If the page is a view-source: url, we need to force the reload */
      if (location && g_str_has_prefix (location, "view-source:"))
      {
            LOG ("Reloading view-source page");
            wrapper->ReloadViewSourcePage();
            return;
      }
      else if (flags & EMBED_RELOAD_FORCE)
      {
            reloadFlags = GTK_MOZ_EMBED_FLAG_RELOADBYPASSPROXYANDCACHE;
            LOG ("Should bypass cache and proxy");
      }
      
      g_free (location);

      
#ifndef HAVE_GTKMOZEMBED_BROKEN_RELOAD
      gtk_moz_embed_reload (GTK_MOZ_EMBED(embed), reloadFlags);
#else
      /* Workaround for broken reload with frames, see mozilla bug
       * http://bugzilla.mozilla.org/show_bug.cgi?id=246392
       */
      wrapper->ReloadPage (reloadFlags);
#endif
}

static void
impl_copy_page (GaleonEmbed *dest,
            GaleonEmbed *source,
            EmbedDisplayType display_type)
{
      GaleonWrapper *dWrapper = MOZILLA_EMBED(dest)->priv->wrapper;;
      GaleonWrapper *sWrapper = MOZILLA_EMBED(source)->priv->wrapper;;

        nsresult rv;

        nsCOMPtr<nsISupports> pageDescriptor;
        rv = sWrapper->GetPageDescriptor(getter_AddRefs(pageDescriptor));
        if (!pageDescriptor || NS_FAILED(rv)) return;

        rv = dWrapper->LoadDocument(pageDescriptor, static_cast<PRUint32>(display_type));
        if (NS_FAILED(rv)) return;

      /* LOAD HACK: Ensure that we remember the url that we are loading 
       * (if the source is in the middle of loading the url */
      if (!MOZILLA_EMBED (dest)->priv->loaded_url)
      {
            char *url;
            url = galeon_embed_get_location (source, FALSE, TRUE);
            if (url)
            {
                  MOZILLA_EMBED (dest)->priv->loading_url = url;

                  /* Fake a "location" signal, so that the layer above picks up
                   * this url, and doesn't think there is no current url */
                  g_signal_emit_by_name (dest, "ge_location");
            }
      }

      return;
}

static GList *
impl_get_link_tags (GaleonEmbed *embed,
                    const char *link_type)
{
      return NULL;
}

static void
impl_zoom_set (GaleonEmbed *embed, 
               int zoom)
{
      GaleonWrapper *wrapper = MOZILLA_EMBED(embed)->priv->wrapper;
      nsresult result;

      result = wrapper->SetZoom ((float)(zoom) / 100);

      if (NS_SUCCEEDED (result))
      {
            g_signal_emit_by_name (embed, "ge_zoom_change", zoom);
      }
}

static int
impl_zoom_get (GaleonEmbed *embed)
{
      GaleonWrapper *wrapper = MOZILLA_EMBED(embed)->priv->wrapper;
      float f;

      nsresult result = wrapper->GetZoom (&f);
      if (NS_FAILED (result)) return 100;

      return (int) rint (f * 100);
}

static gboolean
impl_selection_can_cut (GaleonEmbed *embed)
{
      GaleonWrapper *wrapper = MOZILLA_EMBED(embed)->priv->wrapper;
      gboolean result;
      
      wrapper->CanCutSelection (&result);
      
      return result;
}

static gboolean
impl_selection_can_copy (GaleonEmbed *embed)
{
      GaleonWrapper *wrapper = MOZILLA_EMBED(embed)->priv->wrapper;
      gboolean result;
      
      wrapper->CanCopySelection (&result);
      
      return result;
}

static gboolean
impl_can_paste (GaleonEmbed *embed)
{
      GaleonWrapper *wrapper = MOZILLA_EMBED(embed)->priv->wrapper;
      gboolean result;
      
      wrapper->CanPaste (&result);
      
      return result;
}

static void
impl_select_all (GaleonEmbed *embed)
{
      GaleonWrapper *wrapper = MOZILLA_EMBED(embed)->priv->wrapper;
      
      wrapper->SelectAll ();
}

static void
impl_selection_cut (GaleonEmbed *embed)
{
      GaleonWrapper *wrapper = MOZILLA_EMBED(embed)->priv->wrapper;
      
      wrapper->CutSelection ();
}

static void
impl_selection_copy (GaleonEmbed *embed)
{
      GaleonWrapper *wrapper = MOZILLA_EMBED(embed)->priv->wrapper;
      
      wrapper->CopySelection ();
}

static void
impl_paste (GaleonEmbed *embed)
{
      GaleonWrapper *wrapper = MOZILLA_EMBED(embed)->priv->wrapper;
      
      wrapper->Paste ();
}

static int
impl_shistory_count  (GaleonEmbed *embed)
{
      GaleonWrapper *wrapper = MOZILLA_EMBED(embed)->priv->wrapper;
      nsresult rv;
      int c, index;
      
      rv = wrapper->GetSHInfo (&c, &index);
      if (NS_FAILED (rv)) return 0;

      return c;
}

static gboolean
impl_shistory_get_nth (GaleonEmbed *embed, 
                       int nth,
                       gboolean is_relative,
                       char **aUrl,
                       char **aTitle)
{
      GaleonWrapper *wrapper = MOZILLA_EMBED(embed)->priv->wrapper;
      nsresult rv;

      if (is_relative)
      {
            nth += galeon_embed_shistory_get_pos (embed);
      }
      
        GulCString url;
        rv = wrapper->GetSHUrlAtIndex(nth, url);
        *aUrl = (NS_SUCCEEDED (rv) && !url.IsEmpty()) ? g_strdup(url.get()) : NULL;

      PRUnichar *title;
      rv = wrapper->GetSHTitleAtIndex(nth, &title);
      *aTitle = g_strdup (GulCString (title).get());
      nsMemory::Free(title);

      return TRUE;
}

static int
impl_shistory_get_pos (GaleonEmbed *embed)
{
      GaleonWrapper *wrapper = MOZILLA_EMBED(embed)->priv->wrapper;
      nsresult rv;
      int count, index;
      
      rv = wrapper->GetSHInfo (&count, &index);

      return NS_SUCCEEDED(rv) ? index : 0;
}

static gboolean
impl_shistory_go_nth (GaleonEmbed *embed, 
                      int nth)
{
      GaleonWrapper *wrapper = MOZILLA_EMBED(embed)->priv->wrapper;
      nsresult rv;
      
      rv = wrapper->GoToHistoryIndex (nth);

      return NS_SUCCEEDED(rv) ? TRUE : FALSE;
}

static void
impl_shistory_copy (GaleonEmbed *source,
                GaleonEmbed *dest,
                gboolean back_history,
                gboolean forward_history,
                gboolean set_current)
{
      GaleonWrapper *s_wrapper = MOZILLA_EMBED(source)->priv->wrapper;
      GaleonWrapper *d_wrapper = MOZILLA_EMBED(dest)->priv->wrapper;
      
      s_wrapper->CopyHistoryTo (d_wrapper, back_history, forward_history, set_current);

}

static void
impl_shistory_clear (GaleonEmbed *embed)
{
      GaleonWrapper *wrapper = MOZILLA_EMBED(embed)->priv->wrapper;

      wrapper->ClearHistory();
}


static void
impl_scroll (GaleonEmbed *embed, 
             EmbedScrollDirection direction)
{
      GaleonWrapper *wrapper = MOZILLA_EMBED(embed)->priv->wrapper;

      switch (direction)
      {
      case EMBED_SCROLL_UP:
            wrapper->ScrollUp ();
            break;
      case EMBED_SCROLL_DOWN:
            wrapper->ScrollDown ();
            break;
      case EMBED_SCROLL_LEFT:
            wrapper->ScrollLeft ();
            break;
      case EMBED_SCROLL_RIGHT:
            wrapper->ScrollRight ();
            break;
      }
}

static void
impl_fine_scroll (GaleonEmbed *embed, int horiz, int vert)
{
      GaleonWrapper *wrapper = MOZILLA_EMBED(embed)->priv->wrapper;

      wrapper->FineScroll (horiz, vert);
}

static gboolean
impl_get_security_level (GaleonEmbed *embed, 
                         EmbedSecurityLevel *level,
                         char **description)
{
      nsresult rv;

      if (level) *level = STATE_IS_UNKNOWN;
      if (description)*description = NULL;

      GaleonWrapper *wrapper = MOZILLA_EMBED(embed)->priv->wrapper;

      PRUint32 state;
      GulCString desc;
      rv = wrapper->GetSecurityInfo (&state, desc);
        if (NS_FAILED (rv)) return FALSE;

      if (level) *level = mozilla_embed_security_level (state);
      if (description) *description = g_strdup (desc.get());

      return TRUE;
}

static gboolean
impl_print (GaleonEmbed *embed,
            EmbedPrintInfo *info)
{
      GaleonWrapper *wrapper = MOZILLA_EMBED(embed)->priv->wrapper;
      nsresult result;

        nsCOMPtr<nsIPrintSettings> options;
      result = GaleonUtils::EmbedPrintInfoToPrintSettings(info,
                                              getter_AddRefs(options));
      if (NS_FAILED (result)) return FALSE;

      char *string;

      string = gtk_moz_embed_get_title (GTK_MOZ_EMBED (embed));
      options->SetTitle (GulString (string).get());
      g_free (string);

      string = mozilla_embed_get_real_location (MOZILLA_EMBED (embed));
      options->SetDocURL(GulString (string).get());
      g_free (string);

        options->SetPrintSilent (PR_TRUE);

      result = wrapper->Print(options, info->preview,
                        GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (embed))));

      options->SetPrintSilent (PR_FALSE);

      return NS_SUCCEEDED (result) ? TRUE : FALSE;
}

static void
impl_print_preview_close (GaleonEmbed *embed)
{
      GaleonWrapper *wrapper = MOZILLA_EMBED(embed)->priv->wrapper;
      
      wrapper->PrintPreviewClose();
}

static int
impl_print_preview_num_pages (GaleonEmbed *embed)
{
      GaleonWrapper *wrapper = MOZILLA_EMBED(embed)->priv->wrapper;
      int ret = 0;

      wrapper->PrintPreviewNumPages(&ret);

      return ret;
}

static gboolean
impl_print_preview_navigate (GaleonEmbed *embed,
                       EmbedPrintPreviewNavType navType,
                       gint pageNum)
{
      GaleonWrapper *wrapper = MOZILLA_EMBED(embed)->priv->wrapper;
      nsresult result;

      result = wrapper->PrintPreviewNavigate(navType, pageNum);
      return NS_SUCCEEDED(result) ? TRUE : FALSE;
}

static gboolean
impl_find_next (GaleonEmbed *embed, 
                gboolean backwards)
{
      GaleonWrapper *wrapper = MOZILLA_EMBED(embed)->priv->wrapper;
      nsresult result;
        PRBool didFind;

        result = wrapper->Find (backwards, &didFind);
      
      return didFind ? TRUE : FALSE;
}


static void
impl_find_set_properties (GaleonEmbed *embed, 
                          char *search_string,
                        gboolean case_sensitive,
                    gboolean wrap_around)
{
      GaleonWrapper *wrapper = MOZILLA_EMBED(embed)->priv->wrapper;

        wrapper->FindSetProperties (GulString (search_string).get(), 
                            case_sensitive, wrap_around);
}

static gboolean
impl_set_encoding (GaleonEmbed *embed,
               const char *charset)
{
      GaleonWrapper *wrapper = MOZILLA_EMBED(embed)->priv->wrapper;
      nsresult rv;

      rv = wrapper->SetForcedEncoding (charset);
      if (NS_FAILED (rv)) return FALSE;

#ifndef HAVE_GTKMOZEMBED_BROKEN_RELOAD
      gtk_moz_embed_reload (GTK_MOZ_EMBED (embed),
                        GTK_MOZ_EMBED_FLAG_RELOADCHARSETCHANGE);
#else
      /* Roll our own reload function. Mozilla is broken
       * w.r.t framesets.
       *
       * See http://bugzilla.mozilla.org/show_bug.cgi?id=246392
       */
      wrapper->ReloadPage (GTK_MOZ_EMBED_FLAG_RELOADCHARSETCHANGE);
#endif
 
      return TRUE;
}

static GaleonEncodingPageInfo *
impl_get_encoding_info (GaleonEmbed *embed)
{
      MozillaEmbedPrivate *mpriv = MOZILLA_EMBED(embed)->priv;
      nsresult rv;

      GulCString encoding;
      rv = mpriv->wrapper->GetEncoding (encoding);
      if (NS_FAILED (rv)) return NULL;

      GulCString forced_encoding;
      mpriv->wrapper->GetForcedEncoding (forced_encoding);

      GaleonEncodingPageInfo *info;
      info = g_new0 (GaleonEncodingPageInfo, 1);

      info->encoding = g_strdup (encoding.get());
      info->forced   = forced_encoding.Length() ? TRUE : FALSE;

      return info;
}


static gboolean
impl_has_modified_forms (GaleonEmbed *embed)
{
      MozillaEmbedPrivate *mpriv = MOZILLA_EMBED(embed)->priv;

      PRBool modified = PR_FALSE;
      mpriv->wrapper->GetHasModifiedForms (&modified);

      return modified == PR_TRUE ? TRUE : FALSE;
}

static gboolean
impl_can_view_source (GaleonEmbed *embed)
{
      char *location;
      gboolean ret = TRUE;

      location = galeon_embed_get_location (embed, TRUE, FALSE);
      if (!location) return FALSE;

      if (g_str_has_prefix (location, "view-source:") ||
          g_str_has_prefix (location, "wyciwyg:"))
      {
            ret = FALSE;
      }

      g_free (location);

      return ret;
}

static void
impl_evaluate_javascript (GaleonEmbed *embed, const char *script)
{
      MozillaEmbedPrivate *mpriv = MOZILLA_EMBED(embed)->priv;

      mpriv->wrapper->EvaluateJS (script);
}

static void
mozilla_embed_location_changed (GtkMozEmbed *embed)
{
      MozillaEmbed *membed = MOZILLA_EMBED (embed);
      g_signal_emit_by_name (membed, "ge_location");
}

static void
mozilla_embed_title_changed (GtkMozEmbed *embed)
{
      MozillaEmbed *membed = MOZILLA_EMBED (embed);
      g_signal_emit_by_name (membed, "ge_title");
}

/* Work out what the state of the page is, this ensures allows us
 * to notify the application just before the content is rendered
 * so it can restore the zoom level and things like that.
 *
 * This function is blatantly copied from epiphany */
static void
update_load_state (MozillaEmbed *membed, gint state)
{
      MozillaEmbedPrivate *priv = membed->priv;

      if (state & GTK_MOZ_EMBED_FLAG_IS_NETWORK)
      {
            if (state & GTK_MOZ_EMBED_FLAG_START)
            {
                  priv->load_state = MOZILLA_EMBED_LOAD_STARTED;
            }
            else if (state & GTK_MOZ_EMBED_FLAG_STOP)
            {
                  priv->load_state = MOZILLA_EMBED_LOAD_STOPPED;
            }
      }
      else if (state & GTK_MOZ_EMBED_FLAG_START &&
               state & GTK_MOZ_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 = gtk_moz_embed_get_location (GTK_MOZ_EMBED (membed));
                  g_signal_emit_by_name (membed, "ge_content_change", address);
                  g_free (address);
            }
      }
      else if (state & GTK_MOZ_EMBED_FLAG_REDIRECTING &&
               priv->load_state == MOZILLA_EMBED_LOAD_STARTED)
      {
            priv->load_state = MOZILLA_EMBED_LOAD_REDIRECTING;
      }
}

static void
mozilla_embed_net_state_all (GtkMozEmbed *embed, const char *aURI,
                             gint state, guint status)
{
      MozillaEmbed *membed = MOZILLA_EMBED (embed);
      EmbedState estate = EMBED_STATE_UNKNOWN;
      int i;
      
      struct
      {
            guint state;
            EmbedState embed_state;
      }
      conversion_map [] =
      {
            { GTK_MOZ_EMBED_FLAG_START, EMBED_STATE_START },
            { GTK_MOZ_EMBED_FLAG_STOP, EMBED_STATE_STOP },
            { GTK_MOZ_EMBED_FLAG_REDIRECTING, EMBED_STATE_REDIRECTING },
            { GTK_MOZ_EMBED_FLAG_TRANSFERRING, EMBED_STATE_TRANSFERRING },
            { GTK_MOZ_EMBED_FLAG_NEGOTIATING, EMBED_STATE_NEGOTIATING },
            { GTK_MOZ_EMBED_FLAG_IS_REQUEST, EMBED_STATE_IS_REQUEST },
            { GTK_MOZ_EMBED_FLAG_IS_DOCUMENT, EMBED_STATE_IS_DOCUMENT },
            { GTK_MOZ_EMBED_FLAG_IS_NETWORK, EMBED_STATE_IS_NETWORK },
            { 0, EMBED_STATE_UNKNOWN }
      };

      for (i = 0; conversion_map[i].state != 0; i++)
      {
            if (state & conversion_map[i].state)
            {
                  estate = (EmbedState) (estate | conversion_map[i].embed_state);   
            }
      }
      
      update_load_state (membed, state);

      g_signal_emit_by_name (membed, "ge_net_state", aURI, estate);
}

static void
mozilla_embed_net_stop (GtkMozEmbed *embed)
{
      MozillaEmbed *membed = MOZILLA_EMBED (embed);
      /* LOAD HACK: Check to see if a real url is currently loaded.
       * If it is, then forget the "loading_url", and mark the embed
       * as having had a url loaded */
      if (!membed->priv->loaded_url)
      {
            char *l = mozilla_embed_get_real_location (MOZILLA_EMBED(embed));
            if (strcmp ("about:blank", l))
            {
                  /* We have loaded a real page */
                  g_free (membed->priv->loading_url);
                  membed->priv->loading_url = 0;
                  membed->priv->loaded_url = TRUE;
            }
            g_free (l);
      }
      g_signal_emit_by_name (membed, "ge_net_stop" );

}

static void
mozilla_embed_net_start (GtkMozEmbed *embed)
{
      MozillaEmbed *membed = MOZILLA_EMBED (embed);
      g_signal_emit_by_name (membed, "ge_net_start" );
}

static void
mozilla_embed_progress (GtkMozEmbed *embed, const char *aURI,
                        gint curprogress, gint maxprogress)
{
      MozillaEmbed *membed = MOZILLA_EMBED (embed);
      g_signal_emit_by_name (membed, "ge_progress", aURI, 
                         curprogress, maxprogress);
}

static void
mozilla_embed_link_message (GtkMozEmbed *embed)
{
      MozillaEmbed *membed = MOZILLA_EMBED (embed);
      char *msg = gtk_moz_embed_get_link_message (embed);

      g_signal_emit_by_name (membed, "ge_link_message", msg );

      g_free (msg);
}

static void
mozilla_embed_js_status (GtkMozEmbed *embed)
{
      MozillaEmbed *membed = MOZILLA_EMBED (embed);
      char *msg = gtk_moz_embed_get_js_status (embed);

      g_signal_emit_by_name (membed, "ge_js_status", msg);

      g_free (msg);
}

static void
mozilla_embed_visibility (GtkMozEmbed *embed, gboolean visibility)
{
      MozillaEmbed *membed = MOZILLA_EMBED (embed);

      g_signal_emit_by_name (membed, "ge_visibility", visibility); 

      GaleonWrapper *wrapper = MOZILLA_EMBED(membed)->priv->wrapper;

      nsresult rv;
      nsCOMPtr<nsIWindowWatcher> wwatch
            (do_GetService(WINDOWWATCHER_CONTRACTID, &rv));
      if (NS_FAILED(rv) || !wwatch) return;

      nsCOMPtr<nsIDOMWindow> domWindow;
      rv = wrapper->GetDOMWindow(getter_AddRefs(domWindow));
      if(NS_FAILED(rv) || !domWindow) return;

      rv = wwatch->SetActiveWindow(domWindow);
}

static void
mozilla_embed_destroy_brsr (GtkMozEmbed *embed)
{
      MozillaEmbed *membed = MOZILLA_EMBED (embed);
      g_signal_emit_by_name (membed, "ge_destroy_brsr"); 
}

static gint
mozilla_embed_emit_mouse_signal (MozillaEmbed *membed, gpointer dom_event, 
                         const char *signal)
{
      GaleonWrapper *wrapper = membed->priv->wrapper;
      GaleonEmbedEvent *info;
      gint return_value = 0;
      nsresult result;

      info = galeon_embed_event_new();
      
      EventContext ctx;
      ctx.Init(wrapper);
        result = ctx.GetMouseEventInfo(static_cast<nsIDOMMouseEvent*>(dom_event), info);
      if (NS_SUCCEEDED(result))
      {
            nsCOMPtr<nsIDOMDocument> domDoc;
            result = ctx.GetTargetDocument(getter_AddRefs(domDoc));
            if (NS_SUCCEEDED(result))
            {
                  result = wrapper->PushTargetDocument(domDoc, info);
                  if (NS_SUCCEEDED(result))
                  {
                        g_signal_emit_by_name (membed, signal,
                                          info, &return_value); 
                  }
            }

      }

      g_object_unref(info);
      
      return return_value;
}

static gint
mozilla_embed_dom_mouse_click (GtkMozEmbed *embed, gpointer dom_event)
{
      return mozilla_embed_emit_mouse_signal (MOZILLA_EMBED (embed), 
                                    dom_event,
                                    "ge_dom_mouse_click");
}

static gint
mozilla_embed_dom_mouse_down (GtkMozEmbed *embed, gpointer dom_event)
{
      return mozilla_embed_emit_mouse_signal (MOZILLA_EMBED (embed), 
                                    dom_event,
                                    "ge_dom_mouse_down");
}

static void
mozilla_embed_size_to (GtkMozEmbed *embed, gint width, gint height)
{
      MozillaEmbed *membed = MOZILLA_EMBED (embed);
      g_signal_emit_by_name (membed, "ge_size_to", width, height);
}

static void
mozilla_embed_new_window (GtkMozEmbed *embed, 
                    GtkMozEmbed **newEmbed,
                          guint chromemask)
{
      MozillaEmbed *membed = MOZILLA_EMBED (embed);
      int i;
      EmbedChromeMask mask = EMBED_CHROME_OPENASPOPUP;
      GaleonEmbed *new_embed = NULL;

      struct
      {
            guint chromemask;
            EmbedChromeMask embed_mask;
      }
      conversion_map [] =
      {
            { GTK_MOZ_EMBED_FLAG_DEFAULTCHROME, EMBED_CHROME_DEFAULT },
            { GTK_MOZ_EMBED_FLAG_MENUBARON, EMBED_CHROME_MENUBARON },
            { GTK_MOZ_EMBED_FLAG_TOOLBARON, EMBED_CHROME_TOOLBARON },
            /* Map the bookmarks bar to the default, as otherwise _blank
             * pages don't honour the gconf settings, and always have the
             * bookmarks bar, which just confuses people (bug 122410) */
            { GTK_MOZ_EMBED_FLAG_PERSONALTOOLBARON, EMBED_CHROME_DEFAULT },
            { GTK_MOZ_EMBED_FLAG_STATUSBARON, EMBED_CHROME_STATUSBARON },
            { GTK_MOZ_EMBED_FLAG_WINDOWRAISED, EMBED_CHROME_WINDOWRAISED },
            { GTK_MOZ_EMBED_FLAG_WINDOWLOWERED, EMBED_CHROME_WINDOWLOWERED },
            { GTK_MOZ_EMBED_FLAG_CENTERSCREEN, EMBED_CHROME_CENTERSCREEN },
            { GTK_MOZ_EMBED_FLAG_OPENASDIALOG, EMBED_CHROME_OPENASDIALOG },
            { GTK_MOZ_EMBED_FLAG_OPENASCHROME, EMBED_CHROME_OPENASCHROME },
            { 0, EMBED_CHROME_NONE }
      };

      for (i = 0; conversion_map[i].chromemask != 0; i++)
      {
            if (chromemask & conversion_map[i].chromemask)
            {
                  mask = (EmbedChromeMask) (mask | conversion_map[i].embed_mask);   
            }
      }
      
      g_signal_emit_by_name (membed, "ge_new_window", mask, &new_embed);

      g_assert (new_embed != NULL);
      
      gtk_moz_embed_set_chrome_mask (GTK_MOZ_EMBED(new_embed), chromemask);

      *newEmbed = GTK_MOZ_EMBED(new_embed);
}

static void
mozilla_embed_security_change (GtkMozEmbed *embed, 
                         gpointer request,
                         guint state)
{
      MozillaEmbed *membed = MOZILLA_EMBED (embed);
      EmbedSecurityLevel level;

      level = mozilla_embed_security_level (state);

      g_signal_emit_by_name (membed, "ge_security_change", level);
}

static EmbedSecurityLevel
mozilla_embed_security_level (PRUint32 state)
{
      EmbedSecurityLevel level;

      switch (state)
        {
        case nsIWebProgressListener::STATE_IS_INSECURE:
                level = STATE_IS_INSECURE;
                break;
        case nsIWebProgressListener::STATE_IS_BROKEN:
                level = STATE_IS_BROKEN;
                break;
        case nsIWebProgressListener::STATE_IS_SECURE|
             nsIWebProgressListener::STATE_SECURE_HIGH:
                level = STATE_IS_SECURE_HIGH;
                break;
        case nsIWebProgressListener::STATE_IS_SECURE|
             nsIWebProgressListener::STATE_SECURE_MED:
                level = STATE_IS_SECURE_MED;
                break;
        case nsIWebProgressListener::STATE_IS_SECURE|
             nsIWebProgressListener::STATE_SECURE_LOW:
                level = STATE_IS_SECURE_LOW;
                break;
        default:
                level = STATE_IS_UNKNOWN;
                break;
        }
      return level;
}

static gint
stylesheet_find_func (gconstpointer a, gconstpointer b)
{
      const EmbedStyleSheet *sheet = (const EmbedStyleSheet*)a;
      const char * name = (const char*)b;

      return strcmp (sheet->name, name);;
}

static EmbedPageProperties *
impl_get_page_properties(GaleonEmbed *embed)
{
      nsresult result;

        GaleonWrapper *wrapper = MOZILLA_EMBED(embed)->priv->wrapper;

      EmbedPageProperties *props = g_new0(EmbedPageProperties, 1);

      result = wrapper->GetPageProperties (props);

      if (NS_FAILED (result))
      {
            g_free (props);
            return NULL;
      }
      return props;
}


static void
impl_show_page_certificate (GaleonEmbed *embed)
{
        GaleonWrapper *wrapper = MOZILLA_EMBED(embed)->priv->wrapper;
      wrapper->ShowPageCertificate();
}

struct MozillaEmbedStyleSheet : public EmbedStyleSheet
{
      MozillaEmbedStyleSheet() // : name(0), sheet(0), type(STYLESHEET_NONE)
      { 
            LOG ("MozillaEmbedStyleSheet ctor (%p)", this);
            name = NULL; sheet = NULL; type = STYLESHEET_NONE;
      }
      ~MozillaEmbedStyleSheet()
      {
            LOG ("MozillaEmbedStyleSheet dtor (%p)", this);
      }

      nsCOMPtr<nsIDOMStyleSheet> domStyle;
      nsCOMPtr<nsIStyleSheet>    style;
};

static gboolean
stylesheet_is_alternate(nsIDOMStyleSheet *item)
{
      nsresult result;
      gboolean ret = FALSE;

      nsCOMPtr<nsIDOMNode> node;
      result = item->GetOwnerNode(getter_AddRefs(node));
      if (NS_FAILED(result)) return FALSE;

      nsCOMPtr<nsIDOMHTMLLinkElement> link = do_QueryInterface(node);
      
      if (link)
      {
            GulString str;
            link->GetRel(str);
            
            gchar *tmp = g_ascii_strdown(GulCString (str).get(), -1);
            
            if (strstr (tmp, "alternate") != NULL) ret = TRUE;

            g_free(tmp);
      }

      return ret;
}

static GList *
impl_get_stylesheets (GaleonEmbed *embed)
{
      nsresult result;

        GaleonWrapper *wrapper = MOZILLA_EMBED(embed)->priv->wrapper;

      nsCOMPtr<nsIDOMStyleSheetList> list;
      result = wrapper->GetStyleSheets(getter_AddRefs(list));
      if (NS_FAILED(result) || !list) return NULL;

      PRUint32 count(0); 
      result = list->GetLength(&count);
      if (NS_FAILED(result)) return NULL;

      //Sometimes Mozilla wants to return -1 as an unsigned value...
      if ((count+1) == 0) count = 0;

      gint found(0);
      gint found_named(0);
      GList *csslist(NULL);
      for (PRUint32 i = 0; i < count; i++)
      {
            nsCOMPtr<nsIDOMStyleSheet> item;
            result = list->Item(i, getter_AddRefs(item));
            if (NS_FAILED(result) || !item) continue;

            found++;

            GulString string;
            result = item->GetTitle(string);
            if (NS_FAILED(result)) continue;

            if (string.IsEmpty()) continue;

            GulCString name (string);

            if (g_list_find_custom (csslist, name.get(), stylesheet_find_func))
            {
                  continue;
            }

            if (!stylesheet_is_alternate (item))
            {
                  found_named++;
            }

            MozillaEmbedStyleSheet *sheet = new MozillaEmbedStyleSheet();
            sheet->name  = g_strdup (name.get());
            sheet->sheet = item;
            sheet->type  = STYLESHEET_NAMED;
            sheet->domStyle = item;

            csslist = g_list_append(csslist, sheet);
      }

      if (found > 0 && found_named == 0)
      {
            /* Add in the "Default" style if we found stylesheets but
             * we didn't find any (non-alternate) named ones) */
            MozillaEmbedStyleSheet *sheet = new MozillaEmbedStyleSheet();
            sheet->name  = g_strdup(_("Default"));
            sheet->sheet = NULL;
            sheet->type  = STYLESHEET_BASIC;

            csslist = g_list_append(csslist, sheet);
      }

      if (found > 0)
      {
            /* prepend None item if any sheets were found */
            MozillaEmbedStyleSheet *sheet = new MozillaEmbedStyleSheet();
            sheet->name = g_strdup(_("None"));
            sheet->sheet = NULL;
            sheet->type = STYLESHEET_NONE;

            csslist = g_list_prepend(csslist, sheet);
      }

      return csslist;
}

static EmbedStyleSheet *
impl_get_selected_stylesheet(GaleonEmbed *embed)
{
      gboolean found = FALSE;
      nsresult result;

        GaleonWrapper *wrapper = MOZILLA_EMBED(embed)->priv->wrapper;
      
      nsCOMPtr<nsIDOMStyleSheetList> list;
      result = wrapper->GetStyleSheets(getter_AddRefs(list));
      if (NS_FAILED(result) || !list) return NULL;
      
      PRUint32 count, i; 
      result = list->GetLength(&count);
      if (NS_FAILED(result)) return NULL;

        //Sometimes Mozilla wants to return -1 as an unsigned value...
        if ((count+1) == 0) count = 0;

      for (i = 0; i < count; i++)
      {
            nsCOMPtr<nsIDOMStyleSheet> item;
            result = list->Item(i, getter_AddRefs(item));
            if (NS_FAILED(result) || !item) continue;

            GulString string;
            result = item->GetTitle(string);
            if (NS_FAILED(result)) continue;

            PRBool disabled;
            item->GetDisabled(&disabled);
            
            if (string.IsEmpty())
            {
                  /* fine, but let's try to get something more sensible */
                  if (disabled == PR_FALSE) found = TRUE;
                  continue;
            }
            
            if (disabled == PR_FALSE)
            {
                  MozillaEmbedStyleSheet *sheet =
                        new MozillaEmbedStyleSheet();
                  sheet->name = g_strdup(GulCString (string).get());
                  sheet->sheet = item;
                  sheet->type = STYLESHEET_NAMED;
                  sheet->domStyle = item;

                  return sheet;
            }
      }

      if (found)
      {
            MozillaEmbedStyleSheet *sheet = new MozillaEmbedStyleSheet();
            sheet->type = STYLESHEET_BASIC;
            return sheet;
      }
      else
      {
            return NULL;
      }
}

static void
impl_set_stylesheet(GaleonEmbed *embed,
                EmbedStyleSheet *sheet)
{
      nsresult result;

        GaleonWrapper *wrapper = MOZILLA_EMBED(embed)->priv->wrapper;
      
      nsCOMPtr<nsIDOMStyleSheetList> list;
      result = wrapper->GetStyleSheets(getter_AddRefs(list));
      if (NS_FAILED(result) || !list) return;
      
      PRUint32 count, i; 
      result = list->GetLength(&count);
      if (NS_FAILED(result)) return;

        //Sometimes Mozilla wants to return -1 as an unsigned value...
        if ((count+1) == 0) count = 0;

      for (i = 0; i < count; i++)
      {
            nsCOMPtr<nsIDOMStyleSheet> item;
            result = list->Item(i, getter_AddRefs(item));
            if (NS_FAILED(result) || !item) continue;
            
            GulString string;
            result = item->GetTitle(string);
            if (NS_FAILED(result)) continue;

            GulCString cTitle (string);

            /*
             * if STYLESHEET_NONE is requtested, disable all.
             * if STYLESHEET_BASIC is requested, enable only unnamed sheets
             * if STYLESHEET_NAMED is requested load all sheets that have
             *    that name, and all unnamed ones
             */
            if      (item == sheet->sheet || cTitle.Equals (sheet->name))
            {
                  item->SetDisabled(FALSE);
            }
            else if (sheet->type != STYLESHEET_NONE && string.IsEmpty())
            {
                  item->SetDisabled(FALSE);
            }
            else
            {
                  item->SetDisabled(TRUE);
            }
      }
}

static gboolean
impl_apply_user_stylesheet(GaleonEmbed *embed,
                     const gchar *sheetfile,
                     EmbedStyleSheet **retSheet)
{
        GaleonWrapper *wrapper = MOZILLA_EMBED(embed)->priv->wrapper;

      gchar *path = galeon_embed_utils_get_user_sheet_path(sheetfile);

      gchar *tmp = g_strconcat("file://", path, NULL);
      g_free(path);

      nsCOMPtr<nsIStyleSheet> item;
      wrapper->LoadOverrideStyleSheet(tmp, getter_AddRefs(item));
      g_free (tmp);

      MozillaEmbedStyleSheet *sheet = new MozillaEmbedStyleSheet();
      sheet->name = g_strdup(sheetfile);
      sheet->sheet = item;
      sheet->type = STYLESHEET_NAMED;
      sheet->style = item;

      (*retSheet) = sheet;
      return TRUE;
}

static void
impl_remove_user_stylesheet(GaleonEmbed *embed,
                      EmbedStyleSheet *sheet)
{
      if (!sheet) return;

      MozillaEmbedStyleSheet *mess = NS_STATIC_CAST(MozillaEmbedStyleSheet*, sheet);
      g_return_if_fail(mess != NULL);

        GaleonWrapper *wrapper = MOZILLA_EMBED(embed)->priv->wrapper;

      wrapper->RemoveOverrideStyleSheet(mess->style);
}

EmbedStyleSheet *
galeon_embed_stylesheet_new (EmbedStyleSheetType type, const char *name)
{
      MozillaEmbedStyleSheet *mess = new MozillaEmbedStyleSheet();
      mess->type = type;
      mess->name = g_strdup (name);
      return mess;
}

void
galeon_embed_stylesheet_free (EmbedStyleSheet *sheet)
{
      MozillaEmbedStyleSheet *mess = NS_STATIC_CAST(MozillaEmbedStyleSheet*, sheet);

      if (mess)
      {
            g_free (mess->name);
            delete mess;
      }
}

static void
galeon_embed_init (GaleonEmbedClass *embed_class)
{
      embed_class->load_url = impl_load_url; 
      embed_class->stop_load = impl_stop_load;
      embed_class->can_go_back = impl_can_go_back;
      embed_class->can_go_forward =impl_can_go_forward;
      embed_class->can_go_up = impl_can_go_up;
      embed_class->get_go_up_list = impl_get_go_up_list;
      embed_class->go_back = impl_go_back;
      embed_class->go_forward = impl_go_forward;
      embed_class->go_up = impl_go_up;
      embed_class->render_data = impl_render_data;
      embed_class->open_stream = impl_open_stream;
      embed_class->append_data = impl_append_data;
      embed_class->close_stream = impl_close_stream;
      embed_class->get_title = impl_get_title;
      embed_class->get_location = impl_get_location;
      embed_class->reload = impl_reload;
      embed_class->copy_page = impl_copy_page;
      embed_class->get_link_tags = impl_get_link_tags;
      embed_class->zoom_set = impl_zoom_set;
      embed_class->zoom_get = impl_zoom_get;
      embed_class->selection_can_cut = impl_selection_can_cut;
      embed_class->selection_can_copy = impl_selection_can_copy;
      embed_class->can_paste = impl_can_paste;
      embed_class->selection_cut = impl_selection_cut;
      embed_class->selection_copy = impl_selection_copy;
      embed_class->paste = impl_paste;
      embed_class->shistory_count = impl_shistory_count;
      embed_class->shistory_get_nth = impl_shistory_get_nth;
      embed_class->shistory_get_pos = impl_shistory_get_pos;
      embed_class->shistory_go_nth = impl_shistory_go_nth;
      embed_class->shistory_copy = impl_shistory_copy;
      embed_class->shistory_clear = impl_shistory_clear;
      embed_class->scroll = impl_scroll;
      embed_class->fine_scroll = impl_fine_scroll;
      embed_class->get_security_level = impl_get_security_level;
      embed_class->find_set_properties = impl_find_set_properties;
      embed_class->find_next = impl_find_next;
      embed_class->set_encoding = impl_set_encoding;
      embed_class->get_encoding_info = impl_get_encoding_info;
      embed_class->has_modified_forms = impl_has_modified_forms;
      embed_class->can_view_source = impl_can_view_source;
      embed_class->select_all = impl_select_all;
      embed_class->print = impl_print;
      embed_class->print_preview_close = impl_print_preview_close;
      embed_class->print_preview_num_pages = impl_print_preview_num_pages;
      embed_class->print_preview_navigate = impl_print_preview_navigate;
      embed_class->get_page_properties = impl_get_page_properties;
      embed_class->show_page_certificate = impl_show_page_certificate;
      embed_class->get_stylesheets = impl_get_stylesheets;
      embed_class->get_selected_stylesheet = impl_get_selected_stylesheet;
      embed_class->set_stylesheet = impl_set_stylesheet;
      embed_class->apply_user_stylesheet = impl_apply_user_stylesheet;
      embed_class->remove_user_stylesheet = impl_remove_user_stylesheet;
      embed_class->evaluate_javascript = impl_evaluate_javascript;
}

GaleonEmbed  *
galeon_embed_new()
{
      GaleonEmbed *embed;
      
      embed = GALEON_EMBED (g_object_new (MOZILLA_TYPE_EMBED, NULL));

      return embed;
}

static void
mozilla_embed_class_init (MozillaEmbedClass *klass)
{
      GObjectClass *object_class = G_OBJECT_CLASS (klass);
      GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
      GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); 
      GtkMozEmbedClass *embed_class = GTK_MOZ_EMBED_CLASS (klass);

      parent_class = (GObjectClass *) g_type_class_peek_parent (klass);

      object_class->finalize = mozilla_embed_finalize;

      widget_class->realize    = mozilla_embed_realize;
      widget_class->grab_focus = mozilla_embed_grab_focus;

      container_class->add    = mozilla_embed_add;
      container_class->remove = mozilla_embed_remove;

      embed_class->location        = mozilla_embed_location_changed;
      embed_class->title           = mozilla_embed_title_changed;
      embed_class->net_state_all   = mozilla_embed_net_state_all;
      embed_class->progress_all    = mozilla_embed_progress;
      embed_class->link_message    = mozilla_embed_link_message;
      embed_class->js_status       = mozilla_embed_js_status;
      embed_class->visibility      = mozilla_embed_visibility;
      embed_class->destroy_brsr    = mozilla_embed_destroy_brsr;
      embed_class->dom_mouse_click = mozilla_embed_dom_mouse_click;
      embed_class->dom_mouse_down  = mozilla_embed_dom_mouse_down;
      embed_class->size_to         = mozilla_embed_size_to;
      embed_class->new_window      = mozilla_embed_new_window;
      embed_class->security_change = mozilla_embed_security_change;
      embed_class->net_stop        = mozilla_embed_net_stop;
      embed_class->net_start       = mozilla_embed_net_start;
}

Generated by  Doxygen 1.6.0   Back to index