Logo Search packages:      
Sourcecode: galeon version File versions

galeon-tab.c

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

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

#define NOT_IMPLEMENTED g_warning ("not implemented: " G_STRLOC);

#include "galeon-tab.h"
#include "galeon-shell.h"
#include "galeon-popup.h"
#include "galeon-embed-utils.h"
#include "eel-gconf-extensions.h"
#include "prefs-strings.h"
#include "galeon-embed-prefs.h"
#include "galeon-embed-autoscroller.h"
#include "galeon-embed-manual-scroller.h"
#include "gul-download.h"
#include "gul-notebook.h"
#include "gul-gestures.h"
#include "galeon-embed-favicon.h"
#include "galeon-debug.h"
#include "bookmarks-gtk-menu.h"
#include "galeon-marshal.h"

#include <glib/gi18n.h>
#include <libgnomevfs/gnome-vfs-uri.h>
#include <gtk/gtklabel.h>
#include <gtk/gtkbutton.h>
#include <gtk/gtkstock.h>
#include <gtk/gtkmisc.h>
#include <gtk/gtkhbox.h>
#include <gtk/gtkimage.h>
#include <gtk/gtkiconfactory.h>
#include <gtk/gtkstyle.h>
#include <gtk/gtkselection.h>
#include <gtk/gtkclipboard.h>
#include <gtk/gtkmain.h>
#include <string.h>

#define GALEON_TAB_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), \
                               GALEON_TYPE_TAB, GaleonTabPrivate))


struct GaleonTabPrivate
{
      GList *notifiers;
      GtkWidget *tab_icon;
      TabLoadStatus load_status;
      EmbedSecurityLevel security_level;
      char *link_message;
      char *js_message;
      char status_message[255];
      char *title;
      char *location;
      char *blocked_popup_uri;
      int load_percent;
      gboolean visibility;
      int cur_requests;
      int total_requests;
      int width;
      int height;
      int zoom;
};

static GHashTable *gestures_actions = NULL;

enum
{
      PROP_0,
      PROP_TITLE,
      PROP_ZOOM,
      PROP_SECURITY,
      PROP_MESSAGE,
      PROP_PROGRESS,
      PROP_POPUP_BLOCKED,
      PROP_LOAD_STATUS,
      PROP_LOCATION,
      PROP_VISIBILITY,
};

enum
{
      SITE_VISITED,
      LAST_SIGNAL
};

static guint signals[LAST_SIGNAL] = { 0 };

static void
galeon_tab_class_init (GaleonTabClass *klass);
static void
galeon_tab_init (GaleonTab *tab);
static void
galeon_tab_finalize (GObject *object);

static void
galeon_tab_link_message_cb (GaleonEmbed *embed, 
                      const char *message,
                      GaleonTab *tab);
static void
galeon_tab_js_status_cb (GaleonEmbed *embed, 
                   const char *status,
                   GaleonTab *tab);
static void
galeon_tab_location_cb (GaleonEmbed *embed, GaleonTab *tab);
static void
galeon_tab_title_cb (GaleonEmbed *embed, GaleonTab *tab);
static void
galeon_tab_progress_cb (GaleonEmbed *embed, const char *uri,
                  gint curprogress, gint maxprogress,
                  GaleonTab *tab);
static void
galeon_tab_net_state_cb (GaleonEmbed *embed, const char *uri,
                   EmbedState state, GaleonTab *tab);
static void
galeon_tab_net_stop_cb (GaleonEmbed *embed, GaleonTab *tab);
static void
galeon_tab_net_start_cb (GaleonEmbed *embed, GaleonTab *tab);

static GaleonEmbed *
galeon_tab_new_window_cb (GaleonEmbed *embed, 
                    EmbedChromeMask chromemask, GaleonTab *tab);
static void
galeon_tab_visibility_cb (GaleonEmbed *embed, gboolean visibility,
                    GaleonTab *tab);
static void
galeon_tab_size_to_cb (GaleonEmbed *embed, gint width, gint height,
                   GaleonTab *tab);
static gint
galeon_tab_dom_mouse_click_cb (GaleonEmbed *embed,
                         GaleonEmbedEvent *event,
                         GaleonTab *tab);
static gint
galeon_tab_dom_mouse_down_cb (GaleonEmbed *embed,
                        GaleonEmbedEvent *event,
                        GaleonTab *tab);
static void
galeon_tab_contextmenu_cb (GaleonEmbed *embed,
                       GaleonEmbedEvent *event,
                     GaleonTab *tab);
static void
galeon_tab_security_change_cb (GaleonEmbed *embed, EmbedSecurityLevel level,
                         GaleonTab *tab);
static void
galeon_tab_zoom_changed_cb (GaleonEmbed *embed, gint zoom, 
                      GaleonTab *tab);
static void
galeon_tab_content_changed_cb (GaleonEmbed *embed, const gchar *url,
                         GaleonTab *tab);
static void
galeon_tab_destroy_brsr_cb (GaleonEmbed *embed, GaleonTab *tab);

static void
galeon_tab_popup_blocked_cb(GaleonEmbed *embed, const char *uri,
                      GaleonTab *tab);
static void
galeon_tab_size_allocate(GtkWidget *widget, GtkAllocation *allocation);

static void galeon_tab_destroy (GtkObject *object);

static void 
galeon_tab_map (GtkWidget *widget);

static void
galeon_tab_gesture_performed_cb (GulGestures *g, const gchar *sequence, GaleonTab *tab);

static GObjectClass *parent_class = NULL;

/* Class functions */

GType 
galeon_tab_get_type (void)
{
        static GType galeon_tab_type = 0;

        if (galeon_tab_type == 0)
        {
                static const GTypeInfo our_info =
                {
                        sizeof (GaleonTabClass),
                        NULL, /* base_init */
                        NULL, /* base_finalize */
                        (GClassInitFunc) galeon_tab_class_init,
                        NULL,
                        NULL, /* class_data */
                        sizeof (GaleonTab),
                        0, /* n_preallocs */
                        (GInstanceInitFunc) galeon_tab_init
                };

                galeon_tab_type = g_type_register_static (GTK_TYPE_BIN,
                                            "GaleonTab",
                                            &our_info, 0);
        }

        return galeon_tab_type;
}

static void
galeon_tab_set_property (GObject *object,
                   guint prop_id,
                   const GValue *value,
                   GParamSpec *pspec)
{
      GaleonTab *tab = GALEON_TAB (object);
      
      switch (prop_id)

      {
              case PROP_LOCATION:
                  galeon_tab_set_location (tab, g_value_get_string (value));
                  break;
            case PROP_LOAD_STATUS:
                  galeon_tab_set_load_status (tab, g_value_get_int (value));
                  break;
            case PROP_TITLE:
            case PROP_ZOOM:
            case PROP_SECURITY:
            case PROP_MESSAGE:
            case PROP_PROGRESS:
            case PROP_POPUP_BLOCKED:
            case PROP_VISIBILITY:
                  /* read only */
                  break;
      }
}

static void
galeon_tab_get_property (GObject *object,
                   guint prop_id,
                   GValue *value,
                   GParamSpec *pspec)
{
      GaleonTab *tab = GALEON_TAB (object);

      switch (prop_id)
      {
              case PROP_LOCATION:
                  g_value_set_string (value, tab->priv->location);
                  break;
            case PROP_TITLE:
                  g_value_set_string (value, tab->priv->title);
                  break;
            case PROP_ZOOM:
                  g_value_set_int (value, tab->priv->zoom);
                  break;
            case PROP_SECURITY:
                  g_value_set_int (value, tab->priv->security_level);
                  break;
            case PROP_MESSAGE:
                  g_value_set_string (value, galeon_tab_get_status_message (tab));
                  break;
            case PROP_PROGRESS:
                  g_value_set_int (value, tab->priv->load_percent);
                  break;
            case PROP_LOAD_STATUS:
                  g_value_set_int (value, tab->priv->load_status);
                  break;
            case PROP_POPUP_BLOCKED:
                  g_value_set_boolean (value, tab->priv->blocked_popup_uri ? TRUE : FALSE);
                  break;
            case PROP_VISIBILITY:
                  g_value_set_boolean (value, tab->priv->visibility);
                  break;
      }
}



static void
galeon_tab_class_init (GaleonTabClass *klass)
{
      GObjectClass *object_class   = G_OBJECT_CLASS (klass);
      GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
      GtkObjectClass *gtk_object_class = GTK_OBJECT_CLASS (klass);

      parent_class = g_type_class_peek_parent (klass);

      widget_class->size_allocate = galeon_tab_size_allocate;
      widget_class->map           = galeon_tab_map;
      gtk_object_class->destroy   = galeon_tab_destroy;
      object_class->finalize      = galeon_tab_finalize;
      object_class->set_property  = galeon_tab_set_property;
      object_class->get_property  = galeon_tab_get_property;

      signals[SITE_VISITED] =
                g_signal_new ("site_visited",
                        G_OBJECT_CLASS_TYPE (klass),
                              G_SIGNAL_RUN_FIRST,
                              G_STRUCT_OFFSET (GaleonTabClass, site_visited),
                              NULL, NULL,
                              galeon_marshal_VOID__STRING_STRING,
                              G_TYPE_NONE,
                              2,
                        G_TYPE_STRING,
                        G_TYPE_STRING);

      g_object_class_install_property (object_class,
                               PROP_TITLE,
                               g_param_spec_string ("title",
                                                "Title",
                                                "The tab's title",
                                                _("Untitled"),
                                                G_PARAM_READABLE));
      g_object_class_install_property (object_class,
                               PROP_LOCATION,
                               g_param_spec_string ("location",
                                                "Location",
                                                "The tab's location (as displayed in the url bar)",
                                                "",
                                                G_PARAM_READWRITE));

      g_object_class_install_property (object_class,
                               PROP_ZOOM,
                               g_param_spec_int ("zoom",
                                             "Zoom",
                                             "The tab's zoom value",
                                             10,
                                             9999,
                                             100,
                                             G_PARAM_READABLE));
      g_object_class_install_property (object_class,
                               PROP_SECURITY,
                               g_param_spec_int ("security-level",
                                             "Security Level",
                                             "The tab's security level",
                                              STATE_IS_UNKNOWN,
                                              STATE_IS_SECURE_HIGH,
                                              STATE_IS_UNKNOWN,
                                              G_PARAM_READABLE));

      g_object_class_install_property (object_class,
                               PROP_SECURITY,
                               g_param_spec_int ("load-status",
                                             "Load Status",
                                             "The status of the load",
                                              TAB_LOAD_NONE,
                                              TAB_LOAD_COMPLETED,
                                              TAB_LOAD_NONE,
                                              G_PARAM_READWRITE));

      g_object_class_install_property (object_class,
                               PROP_MESSAGE,
                               g_param_spec_string ("message",
                                                "Message",
                                                "The tab's statusbar message",
                                                NULL,
                                                G_PARAM_READABLE));
      g_object_class_install_property (object_class,
                               PROP_ZOOM,
                               g_param_spec_int ("progress",
                                             "Progress",
                                             "The tab's load progress",
                                             0,
                                             100,
                                             0,
                                             G_PARAM_READABLE));

      g_object_class_install_property (object_class,
                               PROP_POPUP_BLOCKED,
                               g_param_spec_boolean ("popup-blocked",
                                                 "Popup Blocked",
                                                 "Whether a popup windows was blocked",
                                                 FALSE,
                                                 G_PARAM_READABLE));

      g_object_class_install_property (object_class,
                               PROP_VISIBILITY,
                               g_param_spec_boolean ("visibility",
                                                 "Visibility",
                                                 "The tab's visibility",
                                                 TRUE,
                                                 G_PARAM_READABLE));

      g_type_class_add_private (klass, sizeof (GaleonTabPrivate));
}


static void
galeon_tab_size_allocate(GtkWidget *widget, GtkAllocation *allocation)
{
      GtkWidget *child;
      GtkAllocation invalid = { -1, -1, 1, 1 };

      g_return_if_fail (GALEON_IS_TAB (widget));
      
      widget->allocation = *allocation;
      child = GTK_BIN (widget)->child;
      g_return_if_fail (child != NULL);

      /* Only resize if we're mapped (bug #124558),
       * or if this is the initial size-allocate (bug #156854). */
      if (GTK_WIDGET_MAPPED (child) ||
          memcmp (&child->allocation, &invalid, sizeof (GtkAllocation)) == 0)
      {
            gtk_widget_size_allocate (child, allocation);
      }
}

static void
galeon_tab_map (GtkWidget *widget)
{
      GtkWidget *child;

      child = GTK_BIN (widget)->child;

      /* We do this as using old versions of gtk, when switching
       * to a tab after a resize, it wouldn't get allocated the
       * size */
      if (child &&
          memcmp (&child->allocation, &widget->allocation,
                sizeof (GtkAllocation)) != 0)
      {
            gtk_widget_size_allocate (child, &widget->allocation);
      }

      GTK_WIDGET_CLASS (parent_class)->map (widget);
}

static void
galeon_tab_destroy (GtkObject *object)
{
      GaleonEmbed *embed;
      
      embed = galeon_tab_get_embed (GALEON_TAB (object));
      if (embed)
      {
            /* The GaleonTab (and thus the embed) are about to be
             * destroyed. We therefore don't care about any
             * signals that the embed might emit. So we block them
             * all (bug #138529 - see tests/popup.html testcase)
             *
             * The one exception is the "new_window" signal,
             * which we do want to still listen to, otherwise
             * if a tab tries to launch a popup window when
             * it closes, we will crash. So block all, then
             * unblock just that signal
             */
            LOG ("Blocking all signals (except new_window)");
            g_signal_handlers_block_matched (embed, G_SIGNAL_MATCH_DATA, 
                                     0, 0, NULL, NULL, object);

            /* But don't block the new_window callback */
            g_signal_handlers_unblock_matched (embed, G_SIGNAL_MATCH_FUNC,
                                       0, 0, NULL, 
                                       galeon_tab_new_window_cb, object);

      }
      
      GTK_OBJECT_CLASS (parent_class)->destroy (object);
}

static void
galeon_tab_favicon_cb (GaleonEmbed *embed, const char *favicon_url,
                   GaleonTab *tab)
{
      char *url;

      url = galeon_embed_get_location (embed, TRUE, FALSE);

      if (url)
      {
            GaleonFaviconCache *cache;
            cache = galeon_shell_get_favicon_cache (galeon_shell);
            galeon_favicon_cache_insert_from_url (cache, url,
                                          favicon_url);
      }

      g_free (url);
}


static void
tab_icon_set_visibility (GaleonFavicon *favicon)
{
      int mode = eel_gconf_get_integer (CONF_TABS_FAVICON);

      switch (mode)
      {
      case 0:
            gtk_widget_hide (GTK_WIDGET(favicon));
            break;

      case 1:
            gtk_widget_show (GTK_WIDGET(favicon));
            break;

      default:
            if (galeon_favicon_get_is_default (favicon))
            {
                  gtk_widget_hide (GTK_WIDGET(favicon));
            }
            else
            {
                  gtk_widget_show (GTK_WIDGET(favicon));
            }
            break;
      }
}


static void
tab_icon_changed_cb (GaleonFavicon *favicon, gpointer dummy)
{
      tab_icon_set_visibility (favicon);
}


static void
tab_favicon_mode_gconf_changed_cb (GConfClient *client, guint cnxn_id,
                           GConfEntry *entry, GaleonTab *tab)
{
      tab_icon_set_visibility (GALEON_FAVICON (tab->priv->tab_icon));
}


static void
galeon_tab_init (GaleonTab *tab)
{
      GObject *embed;
      
      LOG ("Creating tab %p", tab);

        tab->priv = GALEON_TAB_GET_PRIVATE (tab);

      embed = G_OBJECT (galeon_embed_new ());

      tab->priv->tab_icon = galeon_embed_favicon_new (GALEON_EMBED (embed));
      g_object_ref (G_OBJECT (tab->priv->tab_icon));
      gtk_object_sink (GTK_OBJECT (tab->priv->tab_icon));

      tab_icon_set_visibility (GALEON_FAVICON (tab->priv->tab_icon));

      galeon_notification_add(CONF_TABS_FAVICON,
                        (GConfClientNotifyFunc)tab_favicon_mode_gconf_changed_cb,
                        tab, &tab->priv->notifiers);

      g_signal_connect_object (tab->priv->tab_icon, "changed",
                         G_CALLBACK (tab_icon_changed_cb), 
                         tab, 0);

      tab->priv->link_message = g_strdup ("");
      tab->priv->js_message = g_strdup ("");
      *tab->priv->status_message = '\0';
      tab->priv->load_status = TAB_LOAD_NONE;
      tab->priv->load_percent = 0;
      tab->priv->title = NULL;
      tab->priv->location = NULL;
      tab->priv->total_requests = 0;
      tab->priv->cur_requests = 0;
      tab->priv->width = -1;
      tab->priv->height = -1;
      tab->priv->zoom   = 100;
      tab->priv->visibility = FALSE;

      gtk_container_add (GTK_CONTAINER (tab), GTK_WIDGET (embed));
      gtk_widget_show (GTK_WIDGET(embed));

      g_signal_connect_object (embed, "ge_link_message",
                         GTK_SIGNAL_FUNC (galeon_tab_link_message_cb), 
                         tab, 0);
      g_signal_connect_object (embed, "ge_js_status",
                         GTK_SIGNAL_FUNC (galeon_tab_js_status_cb), 
                         tab, 0);
      g_signal_connect_object (embed, "ge_location",
                         GTK_SIGNAL_FUNC (galeon_tab_location_cb), 
                         tab, 0);
      g_signal_connect_object (embed, "ge_title",
                         GTK_SIGNAL_FUNC (galeon_tab_title_cb), 
                         tab, 0);
      g_signal_connect_object (embed, "ge_zoom_change",
                         GTK_SIGNAL_FUNC (galeon_tab_zoom_changed_cb),
                         tab, 0);
      g_signal_connect_object (embed, "ge_content_change",
                         GTK_SIGNAL_FUNC (galeon_tab_content_changed_cb),
                         tab, 0);
      g_signal_connect_object (embed, "ge_progress",
                         GTK_SIGNAL_FUNC (galeon_tab_progress_cb), 
                         tab, 0);
      g_signal_connect_object (embed, "ge_net_state",
                         GTK_SIGNAL_FUNC (galeon_tab_net_state_cb), 
                         tab, 0);
      g_signal_connect_object (embed, "ge_net_stop",
                         GTK_SIGNAL_FUNC (galeon_tab_net_stop_cb), 
                         tab, 0);
      g_signal_connect_object (embed, "ge_net_start",
                         GTK_SIGNAL_FUNC (galeon_tab_net_start_cb), 
                         tab, 0);
      g_signal_connect_object (embed, "ge_new_window",
                         GTK_SIGNAL_FUNC (galeon_tab_new_window_cb), 
                         tab, 0);
      g_signal_connect_object (embed, "ge_visibility",
                         GTK_SIGNAL_FUNC (galeon_tab_visibility_cb), 
                         tab, 0);
      g_signal_connect_object (embed, "ge_destroy_brsr",
                         GTK_SIGNAL_FUNC (galeon_tab_destroy_brsr_cb), 
                         tab, 0);
      g_signal_connect_object (embed, "ge_size_to",
                         GTK_SIGNAL_FUNC (galeon_tab_size_to_cb), 
                         tab, 0);
      g_signal_connect_object (embed, "ge_dom_mouse_click",
                         GTK_SIGNAL_FUNC (galeon_tab_dom_mouse_click_cb), 
                         tab, 0);
      g_signal_connect_object (embed, "ge_dom_mouse_down",
                         GTK_SIGNAL_FUNC (galeon_tab_dom_mouse_down_cb), 
                         tab, 0);
      g_signal_connect_object (embed, "ge_contextmenu",
                         GTK_SIGNAL_FUNC (galeon_tab_contextmenu_cb), 
                         tab, 0);
      g_signal_connect_object (embed, "ge_security_change",
                         GTK_SIGNAL_FUNC (galeon_tab_security_change_cb), 
                         tab, 0);
      g_signal_connect_object (embed, "ge_favicon",
                         G_CALLBACK (galeon_tab_favicon_cb),
                         tab, 0);
      g_signal_connect_object (embed, "ge_popupblocked",
                         G_CALLBACK(galeon_tab_popup_blocked_cb),
                         tab, 0);
}

/* Destructor */

static void
galeon_tab_finalize (GObject *object)
{
        GaleonTab *tab = GALEON_TAB (object);

      galeon_notification_remove (&tab->priv->notifiers);

      g_idle_remove_by_data (tab);

      g_object_unref (G_OBJECT(tab->priv->tab_icon));

      g_free (tab->priv->link_message);
      g_free (tab->priv->js_message);
      g_free (tab->priv->blocked_popup_uri);

        g_free (tab->priv->title);
        g_free (tab->priv->location);

      G_OBJECT_CLASS (parent_class)->finalize (object);

      LOG ("GaleonTab finalized %p", tab);
}


static gboolean
address_has_web_scheme (const char *address)
{
      gboolean has_web_scheme;

      if (address == NULL) return FALSE;

      has_web_scheme = (g_str_has_prefix (address, "http:") ||
                    g_str_has_prefix (address, "https:") ||
                    g_str_has_prefix (address, "ftp:") ||
                    g_str_has_prefix (address, "file:") ||
                    g_str_has_prefix (address, "gopher:"));

      return has_web_scheme;
}


/* Public functions */

GaleonTab *
galeon_tab_new (void)
{
      GaleonTab *tab;

      tab = GALEON_TAB (g_object_new (GALEON_TYPE_TAB, NULL));

      return tab;
}

void
galeon_tab_set_load_status (GaleonTab *tab,
                      TabLoadStatus status)
{
      if (status == tab->priv->load_status)
      {
            return;
      }

      if (status == TAB_LOAD_COMPLETED)
      {
            Session *s;
            s = galeon_shell_get_session (galeon_shell);
            session_save (s, SESSION_CRASHED);
      }

      tab->priv->load_status = status;

      g_object_notify (G_OBJECT (tab), "load-status");
}

GaleonEmbed *
galeon_tab_get_embed (GaleonTab *tab)
{
      GtkWidget* child;

      g_return_val_if_fail (GALEON_IS_TAB (tab), NULL);

      child = gtk_bin_get_child (GTK_BIN (tab));

      return child ? GALEON_EMBED (child) : NULL;
}

GaleonWindow *
galeon_tab_get_window (GaleonTab *tab)
{
      GtkWidget *toplevel;

      toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tab));
      g_return_val_if_fail (GALEON_IS_WINDOW (toplevel), NULL);

      return GALEON_WINDOW (toplevel);
}

gboolean
galeon_tab_get_visibility (GaleonTab *tab)
{
      return tab->priv->visibility;
}

void
galeon_tab_get_size (GaleonTab *tab, int *width, int *height)
{
      *width = tab->priv->width;
      *height = tab->priv->height;
}

GtkWidget *
galeon_tab_get_icon (GaleonTab *tab)
{
      return tab->priv->tab_icon;
}

static void 
galeon_tab_set_visibility (GaleonTab *tab,
                           gboolean visible)
{     
      g_return_if_fail (GALEON_IS_TAB (tab));

      if (visible)
      {
            gtk_widget_show (GTK_WIDGET (tab));
      }
      else
      {
            gtk_widget_hide (GTK_WIDGET (tab));
      }

      tab->priv->visibility = visible;

      g_object_notify (G_OBJECT (tab), "visibility");
}

/* Private callbacks for embed signals */

static void
galeon_tab_link_message_cb (GaleonEmbed *embed, 
                      const char *message,
                      GaleonTab *tab)
{
      g_return_if_fail (GALEON_IS_TAB (tab));

      g_free (tab->priv->link_message);
      tab->priv->link_message = g_strdup (message);
      
      g_object_notify (G_OBJECT (tab), "message");
}

static void
galeon_tab_js_status_cb (GaleonEmbed *embed,
                   const char *status,
                   GaleonTab *tab)
{
      g_return_if_fail (GALEON_IS_TAB (tab));
      
      g_free (tab->priv->js_message);
      tab->priv->js_message = g_strdup (status);

      g_object_notify (G_OBJECT (tab), "message");
}

static void
galeon_tab_location_cb (GaleonEmbed *embed, GaleonTab *tab)
{           
      char *location;

      g_return_if_fail (GALEON_IS_EMBED (embed));
      g_return_if_fail (GALEON_IS_TAB (tab));

      location = galeon_embed_get_location(embed, TRUE, FALSE);
      galeon_tab_set_location (tab, location);


      g_signal_emit (tab, signals[SITE_VISITED], 0, tab->priv->location, tab->priv->title);

      g_free (location);
}

static void
galeon_tab_content_changed_cb (GaleonEmbed *embed, const gchar *address,
                         GaleonTab *tab)
{
      LOG ("Content changed: %s", address);

      /* restore zoom level, but only for pages that are from the
       * Internet, i.e. not javascript, about or data pages */
      if (address_has_web_scheme (address))
      {
            GlobalHistory *history;
            GaleonEmbedShell *ges;
            gint saved_zoom, current_zoom;

            ges = galeon_shell_get_embed_shell (galeon_shell);
            history = galeon_embed_shell_get_global_history (ges);

            saved_zoom = global_history_get_host_zoom (history, address);
            current_zoom = galeon_embed_zoom_get (embed);
            if (saved_zoom > 0 && current_zoom != saved_zoom)
            {
                  g_signal_handlers_block_by_func (embed, galeon_tab_zoom_changed_cb, tab);
                  tab->priv->zoom = saved_zoom;
                  galeon_embed_zoom_set (embed, saved_zoom);
                  g_signal_handlers_unblock_by_func (embed, galeon_tab_zoom_changed_cb, tab);
            }
      }
}

static void
galeon_tab_zoom_changed_cb (GaleonEmbed *embed, gint zoom, GaleonTab *tab)
{
      char *address;

      g_return_if_fail (GALEON_IS_TAB (tab));

      tab->priv->zoom = zoom;

      address = galeon_embed_get_location (embed, TRUE, TRUE);
      if (address_has_web_scheme (address))
      {
            GlobalHistory *history;
            GaleonEmbedShell *ges;  

            ges = galeon_shell_get_embed_shell (galeon_shell);
            history = galeon_embed_shell_get_global_history (ges);
            global_history_set_host_zoom (history, address, zoom);
      }

      g_free (address);
      g_object_notify (G_OBJECT (tab), "zoom");
}

static void
galeon_tab_set_title (GaleonTab *tab, const char* title)
{
      if (tab->priv->title)
      {
            g_free (tab->priv->title);
      }
      
      tab->priv->title = g_strdup (title);

      if (*(tab->priv->title) == '\0')
      {
            g_free (tab->priv->title);
            if (!strcmp (tab->priv->location, "about:blank"))
            {
                  tab->priv->title = g_strdup(_("Untitled"));
            }
            else
            {
                  tab->priv->title = g_strdup (tab->priv->location);
            }
      }
      
      g_signal_emit (tab, signals[SITE_VISITED], 0, tab->priv->location, tab->priv->title);

      g_object_notify (G_OBJECT (tab), "title");
}


static void
galeon_tab_title_cb (GaleonEmbed *embed, GaleonTab *tab)
{
      gchar *title = NULL;

      g_return_if_fail (GALEON_IS_EMBED (embed));
      g_return_if_fail (GALEON_IS_TAB (tab));

      title = galeon_embed_get_title (embed);

      if (title)
      {
            galeon_tab_set_title (tab, title);
      }

      g_free (title);
}

static int
build_load_percent (int bytes_loaded, int max_bytes_loaded)
{
      if (max_bytes_loaded > 0)
      {
            return (bytes_loaded * 100) / max_bytes_loaded;
      }
      else
      {
            return -1;
      }
}

static char *
get_host_name_from_uri (const char *uri)
{
      GnomeVFSURI *vfs_uri = NULL;
      const char *host = NULL;
      char *result;
      
      if (uri)
      {
            vfs_uri = gnome_vfs_uri_new (uri);
      }
      
      if (vfs_uri)
      {
            host = gnome_vfs_uri_get_host_name (vfs_uri);
      }
      
      if (!host)
      {
            host = _("site");
      }

      result = g_strdup (host);
      
      if (vfs_uri) gnome_vfs_uri_unref (vfs_uri);
      
      return result;
}

static void
build_progress_message (char *message,
                  const char *uri,
                  int bytes_loaded, 
                  int max_bytes_loaded, 
                  int load_percent)
{
      char *host;

      host = get_host_name_from_uri (uri);
      
      if (max_bytes_loaded == 0 || 
          bytes_loaded > max_bytes_loaded ) 
      {
            g_snprintf (message, 255, 
                      _("Transferring data from %s (%d kB loaded)"), 
                            host, bytes_loaded / 1024);     
      }
      else
      {
            g_snprintf (message, 255, 
                            _("Transferring data from %s (%d%% complete, %d kB of %d kB loaded)"),
                            host, load_percent, bytes_loaded / 1024, max_bytes_loaded / 1024);
      }

      g_free (host);
}

static void
galeon_tab_progress_cb (GaleonEmbed *embed, const char *uri,
                  gint curprogress, gint maxprogress,
                  GaleonTab *tab)
{
      g_return_if_fail (GALEON_IS_TAB (tab));

      build_progress_message (tab->priv->status_message,
                        uri,
                        curprogress,
                        maxprogress,
                        tab->priv->load_percent);
      
      g_object_notify (G_OBJECT (tab), "message");
}

static void
build_net_state_message (char *message,
                   const char *uri,
                   EmbedState flags)
{
      const char *msg = NULL; 
      char *host;

      host = get_host_name_from_uri (uri);
      
      /* REQUEST and NETWORK can be both set */
      
      if (flags & EMBED_STATE_IS_REQUEST)
        {
                if (flags & EMBED_STATE_REDIRECTING)
                {
                  msg = _("Redirecting to %s...");
                }
                else if (flags & EMBED_STATE_TRANSFERRING)
                {
                        msg = _("Transferring data from %s...");
                }
                else if (flags & EMBED_STATE_NEGOTIATING)
                {
                        msg = _("Waiting for authorization from %s...");
                }
        }
      
      if (flags & EMBED_STATE_IS_NETWORK)
        {
                if (flags & EMBED_STATE_START)
                {
                        msg = _("Loading %s...");
                }
                else if (flags & EMBED_STATE_STOP)
                {
                        msg = " ";
                }
        }

      if (msg)
      {
            g_snprintf (message, 255, msg, host);
      }

      g_free (host);
}

static void
build_progress_from_requests (GaleonTab *tab, EmbedState state)
{
      int load_percent;
      
      if (state & EMBED_STATE_IS_REQUEST)
        {
                if (state & EMBED_STATE_START)
                {
                  tab->priv->total_requests ++;
            }
            else if (state & EMBED_STATE_STOP)
            {
                  tab->priv->cur_requests ++;
            }
            
            load_percent = build_load_percent (tab->priv->cur_requests,
                                       tab->priv->total_requests);
            if (load_percent > tab->priv->load_percent)
            {
                  tab->priv->load_percent = load_percent;

                  g_object_notify (G_OBJECT (tab), "progress");
            }
      }
}

static void
galeon_tab_net_start_cb (GaleonEmbed *embed, GaleonTab *tab)
{
      tab->priv->total_requests = 0;
      tab->priv->cur_requests   = 0;
      tab->priv->load_percent   = 0;

      if (tab->priv->blocked_popup_uri)
      {
            g_free(tab->priv->blocked_popup_uri);
            tab->priv->blocked_popup_uri = NULL;

            g_object_notify (G_OBJECT (tab), "popup-blocked");
      }

      galeon_tab_set_load_status (tab, TAB_LOAD_STARTED);
}


static void
galeon_tab_net_state_cb (GaleonEmbed *embed, const char *uri,
                   EmbedState state, GaleonTab *tab)
{     
      build_net_state_message (tab->priv->status_message, uri, state);
      build_progress_from_requests (tab, state);
      
      g_object_notify (G_OBJECT (tab), "message");
}

static void
galeon_tab_net_stop_cb (GaleonEmbed *embed, GaleonTab *tab)
{
      tab->priv->load_percent = 0;
      g_object_notify (G_OBJECT (tab), "progress");

      galeon_tab_set_load_status (tab, TAB_LOAD_COMPLETED);
}

static GaleonEmbed *
galeon_tab_new_window_cb (GaleonEmbed *embed,
                    EmbedChromeMask chromemask, GaleonTab *tab)
{
      GaleonTab *new_tab;
      GaleonWindow *window;
      gboolean open_in_tab;

      open_in_tab = (chromemask & EMBED_CHROME_OPENASCHROME) ?
                  FALSE :
                  eel_gconf_get_boolean (CONF_TABS_TABBED_POPUPS);

      if (open_in_tab)
      {
            window = galeon_tab_get_window (tab);
      }
      else
      {
            window = galeon_window_new ();
            galeon_window_set_chrome (window, chromemask);
      }
      
      new_tab = galeon_tab_new ();
      gtk_widget_show (GTK_WIDGET (new_tab));
        galeon_window_add_tab (window, new_tab,
                         GALEON_WINDOW_ADD_TAB_GROUPED, FALSE);
      
      return galeon_tab_get_embed (new_tab);
}

static void
galeon_tab_visibility_cb (GaleonEmbed *embed, gboolean visibility,
                    GaleonTab *tab)
{
      galeon_tab_set_visibility (tab, visibility);
}


static gboolean
galeon_tab_destroy_brsr_idle_cb (GaleonTab *tab)
{
      GulNotebook *nb;
      GaleonWindow *window;

      LOG ("galeon_tab_destroy_brsr_idle_cb");

      g_return_val_if_fail (GALEON_IS_TAB (tab), FALSE);
      
      window = galeon_tab_get_window (tab);
      g_return_val_if_fail (GALEON_IS_WINDOW (window), FALSE);

      /* Don't use galeon_window_remove_tab here, we don't
       * want to run the "unsubmitted" changes code */
      nb = galeon_window_get_notebook (window);
      gul_notebook_remove_page (GUL_NOTEBOOK (nb), GTK_WIDGET (tab));

      return FALSE;
}


static void
galeon_tab_destroy_brsr_cb (GaleonEmbed *embed, GaleonTab *tab)
{
      /* This is a dirty to hack to work around mozillas problems
       * with closing windows via javascript that dont have focus.
       * 
       * The problem is that if you have a tab loaded in the
       * background in the notebook, then under some circumstances
       * mozilla won't emit the ge_destroy_brsr signal until it gets
       * focus by someone clicking on the tab label.  At that point,
       * the signal is emitted, we close the tab, remove the label,
       * and then the notebook crashes because widget for the label
       * has been destroyed.
       *
       * See bug #116256
       *
       * So lets work around the problem by adding an g_idle function
       * that destroys the tab when we know nothing is referencing it
       * in the stack.
       */
      LOG ("galeon_tab_destroy_brsr_cb");

      g_idle_add_full (G_PRIORITY_HIGH_IDLE, 
                   (GSourceFunc)galeon_tab_destroy_brsr_idle_cb, tab, NULL);
}

static gboolean
let_me_resize_hack (gpointer data)
{
      g_return_val_if_fail (GALEON_IS_TAB (data), FALSE);

      gtk_widget_set_size_request (GTK_WIDGET(data), -1, -1);
      return FALSE;
}

static void
galeon_tab_size_to_cb (GaleonEmbed *embed, gint width, gint height,
                   GaleonTab *tab)
{
      GList *tabs;
      GaleonWindow *window;
      EmbedChromeMask chromemask;

      tab->priv->width = width;
      tab->priv->height = height;
      
      window = galeon_tab_get_window (tab);
      tabs = (GList *) galeon_window_get_tabs (window);
      chromemask = galeon_window_get_chrome (window);
      
      /* Do not resize window with multiple tabs.
       * Do not resize window already showed because
       * it's not possible to calculate a sensible window
       * size based on the embed size */
      if (g_list_length (tabs) == 1 && !tab->priv->visibility)
      {
            gtk_widget_set_size_request 
                  (GTK_WIDGET (tab), width, height);

            /* HACK reset widget requisition after the container
             * has been resized. It appears to be the only way
             * to have the window sized according to embed 
             * size correctly.
             * We dont do it for XUL dialogs because in that case
             * a "forced" requisition appear correct.
             */
            if (!(chromemask & EMBED_CHROME_OPENASCHROME))
            {
                  g_idle_add (let_me_resize_hack, tab);
            }
      }
}

static void
galeon_tab_show_embed_popup (GaleonTab *tab, GaleonEmbedEvent *event)
{
      GaleonPopup *popup;
      GaleonWindow *window;
      GaleonEmbed *embed;

      window = galeon_tab_get_window (tab);
      embed = galeon_tab_get_embed (tab);

      popup = GALEON_POPUP (galeon_window_get_popup_factory (window));
      galeon_popup_set_event (popup, event);
      galeon_popup_show (popup, embed);
}

static void
galeon_tab_bookmark_activated_cb (GbGtkMenu *sender,
                          GbBookmarkEventActivated *ev,
                          GaleonWindow *w)
{
      g_return_if_fail (GB_IS_GTK_MENU (sender));
      g_return_if_fail (GALEON_IS_WINDOW (w));

      galeon_window_bookmark_activate (w, ev);

      g_object_unref (sender);
}

static void
galeon_tab_show_bookmark_menu (GaleonTab *tab, int button)
{
      GbBookmarkSet *bs = galeon_shell_get_bookmark_set (galeon_shell);
      GtkWidget *menu;
      GaleonWindow *window;
      GbGtkMenu *ggm;

      window = galeon_tab_get_window (tab);
      menu = gtk_menu_new();

      ggm = gb_gtk_menu_new (bs->root, GTK_MENU_SHELL (menu));
      gtk_object_sink (GTK_OBJECT (menu));
      gb_gtk_menu_set_location_source (ggm, GB_LOCATION_SOURCE (window));
      gb_gtk_menu_set_statusbar (ggm, GTK_STATUSBAR (galeon_window_get_statusbar (window)));
      gb_gtk_menu_fill_children_submenus (ggm);
      
      g_signal_connect (ggm, "bookmark-activated", 
                    G_CALLBACK (galeon_tab_bookmark_activated_cb), 
                    window);

      gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, button,
                  gtk_get_current_event_time());
}

static gint
galeon_tab_dom_mouse_down_cb  (GaleonEmbed *embed,
                         GaleonEmbedEvent *event,
                         GaleonTab *tab)
{
      GaleonWindow *window;
      int button;
      EmbedEventContext context;
        
      g_assert (GALEON_IS_EMBED_EVENT(event));

      window = galeon_tab_get_window (tab);
      g_return_val_if_fail (window != NULL, FALSE);

      button  = galeon_embed_event_get_mouse_button (event);
      context = galeon_embed_event_get_context (event);

      if (button == 3)
      {
            /* Handled in the contextmenu callback */
      }
      else if (button == 2
            && !(context & EMBED_CONTEXT_LINK
                 || context & EMBED_CONTEXT_EMAIL_LINK
                 || context & EMBED_CONTEXT_INPUT))
      {
            gint action = eel_gconf_get_integer (CONF_MOUSE_MIDDLE_BUTTON_ACTION);
            switch (action) 
            {
            case 0: /* bookmarks context menu */
                  galeon_tab_show_bookmark_menu (tab, button);
                  break;
            case 1: /* paste url: handled by click_cb */
            case 6: /* paste url in current tab: handled by click_cb */
                  break;
            case 2: /* go back */
                  galeon_embed_go_back (embed);
                  return TRUE;
            case 3: /* gestures */
            {
                  GulGestures *g = gul_gestures_new ();
                  guint x, y;
                  galeon_embed_event_get_coords (event, &x, &y);
                  gul_gestures_start (g, GTK_WIDGET (window), button, x, y);
                  
                  g_signal_connect (g, "gesture-performed", 
                                G_CALLBACK (galeon_tab_gesture_performed_cb), tab);
                  
                  g_object_unref (g);
                  return TRUE;
            }
            case 4: /* auto scroll */
            {
                  GaleonEmbedAutoscroller *as = galeon_embed_autoscroller_new ();
                  guint x, y;
                  galeon_embed_event_get_coords (event, &x, &y);
                  galeon_embed_autoscroller_set_embed (as, embed);
                  galeon_embed_autoscroller_start_scroll (as, GTK_WIDGET (window), x, y);
                  g_object_unref (as);
                  return TRUE;
            }
            case 5: /* manual scroll */
            {
                  GaleonEmbedManualScroller *ms = galeon_embed_manual_scroller_new ();
                  guint x, y;
                  galeon_embed_event_get_coords (event, &x, &y);
                  galeon_embed_manual_scroller_set_embed (ms, embed);
                  galeon_embed_manual_scroller_start_scroll (ms, GTK_WIDGET (window), x, y);
                  g_object_unref (ms);
                  return TRUE;
            }
            default:
                  g_warning ("Unexpected pref value for " CONF_MOUSE_MIDDLE_BUTTON_ACTION "\n");
                  break;
            }
      }

      return FALSE;
}

/**
 *  Callback function from the paste of text.
 */
static void
galeon_tab_clipboard_text_received_cb (GtkClipboard *clipboard, const gchar *text,
                               gpointer data)
{
      gpointer *weak_ptr = (gpointer*)data;
      GaleonTab *tab = NULL;
      gint action;

      if (*weak_ptr != NULL)
      {
            tab = GALEON_TAB (*weak_ptr);
            g_object_remove_weak_pointer (G_OBJECT (tab), weak_ptr);
      }
      g_free (data);

      if (tab == NULL || text == NULL || text[0] == '\0')
      {
            return;
      }

      action = eel_gconf_get_integer(CONF_MOUSE_MIDDLE_BUTTON_ACTION);
      
      if (action == 6) /* Paste into current tab */
      {
            galeon_embed_load_url (galeon_tab_get_embed (tab), text);
      }
      else /* Paste into new tab (action == 1 or default) */
      {
            GaleonWindow * window = galeon_tab_get_window (tab);

            galeon_shell_new_tab(galeon_shell, window, tab,
                             text, 0);
      }
}

static gint
galeon_tab_dom_mouse_click_cb(GaleonEmbed *embed,
                        GaleonEmbedEvent *event,
                        GaleonTab *tab)
{
      GaleonWindow *window;
      guint button, modifier;
      EmbedEventContext context;
        
      g_assert(GALEON_IS_EMBED_EVENT(event));

      window = galeon_tab_get_window(tab);
      g_return_val_if_fail(window != NULL, FALSE);

      button = galeon_embed_event_get_mouse_button(event);
      context = galeon_embed_event_get_context(event);
      modifier = galeon_embed_event_get_modifier(event);

      if (button == 1 && (context & EMBED_CONTEXT_LINK) &&
          (modifier & GDK_SHIFT_MASK))
      {
            galeon_embed_utils_download_event_property (embed, event, 
                                              FALSE, NULL, "link");
      }
      else if (button == 1 && (context & EMBED_CONTEXT_IMAGE) &&
             (modifier & GDK_SHIFT_MASK))
      {
            galeon_embed_utils_save_event_property(embed, event, 
                                           TRUE,  /* always_ask_dir */
                                           FALSE, /* show_progress */
                                           _("Save Image As..."),
                                           "image");
      }
      else if ((button == 1 && (context & EMBED_CONTEXT_LINK) &&
              (modifier & GDK_CONTROL_MASK)) ||
             (button == 2 && (context & EMBED_CONTEXT_LINK)))
      {
            GaleonNewTabFlags flags = 0;
            const GValue *value;
            const gchar *link;

            if (button == 2)
            {
                  flags = galeon_shell_modifier_flags (modifier);
            }
            value = galeon_embed_event_get_property(event, "link");
            link = g_value_get_string (value);

            flags |= GALEON_NEW_TAB_COPY_HISTORY;
            if (galeon_embed_event_has_property(event, "link-can-open-in-new-tab"))
            {
                  galeon_shell_new_tab(galeon_shell, window, tab, 
                                   link, flags);
            }
            else
            {
                  galeon_embed_load_url (galeon_tab_get_embed (tab), link);
            }
      }
      else if (button == 2 &&
             (eel_gconf_get_integer(CONF_MOUSE_MIDDLE_BUTTON_ACTION) == 1 ||
              eel_gconf_get_integer(CONF_MOUSE_MIDDLE_BUTTON_ACTION) == 6) &&
             !(context & EMBED_CONTEXT_LINK ||
               context & EMBED_CONTEXT_EMAIL_LINK ||
               context & EMBED_CONTEXT_INPUT))
      {
            /* Handle UTF8 characters as well as normal variants, see bug 133633 */

            /* Ensure that if the tab is destroyed while we are requesting text,
             * we don't dereference  a bogus tab pointer */
            gpointer * weak_ptr = g_new (gpointer, 1);
            *weak_ptr = tab;
            g_object_add_weak_pointer (G_OBJECT (tab), weak_ptr);

            gtk_clipboard_request_text (gtk_widget_get_clipboard (GTK_WIDGET (embed),
                                                      GDK_SELECTION_PRIMARY),
                                  galeon_tab_clipboard_text_received_cb, weak_ptr);
      }
      else
      {
            return FALSE; /* Not handled, continue propgation */
      }

      return TRUE;
}

static void
galeon_tab_contextmenu_cb (GaleonEmbed *embed,
                       GaleonEmbedEvent *event,
                     GaleonTab *tab)
{
      gint action = 0;
      guint button;
      GaleonWindow *window;

      button = galeon_embed_event_get_mouse_button (event);

      if (button)
      {
            action = eel_gconf_get_integer (CONF_MOUSE_RIGHT_BUTTON_ACTION);
      }

      window = galeon_tab_get_window (tab);
      g_return_if_fail (GALEON_IS_WINDOW (window));

      switch (action)
      {
      case 0: /* display context menu immediately */
            galeon_tab_show_embed_popup (tab, event);
            break;
      case 1: /* perform gestures, show context menu on mouse up */
      { 
            GulGestures *g = gul_gestures_new ();
            guint x, y;
            g_object_set_data_full(G_OBJECT(g), "embed_event", 
                               g_object_ref (event), 
                               g_object_unref);
            
            galeon_embed_event_get_coords (event, &x, &y);
            gul_gestures_start (g, GTK_WIDGET (window), button, x, y);
            
            g_signal_connect (g, "gesture-performed", 
                          G_CALLBACK (galeon_tab_gesture_performed_cb), tab);
            
            g_object_unref (g);
            break;
      }
      default:
            g_warning ("Unexpected pref value for " CONF_MOUSE_RIGHT_BUTTON_ACTION "\n");
            break;
      }
}


static void
galeon_tab_set_security_level (GaleonTab *tab, EmbedSecurityLevel level)
{
      g_return_if_fail (GALEON_IS_TAB (tab));

      tab->priv->security_level = level;

      g_object_notify (G_OBJECT (tab), "security-level");
}

static void
galeon_tab_security_change_cb (GaleonEmbed *embed, EmbedSecurityLevel level,
                         GaleonTab *tab)
{
      g_return_if_fail (GALEON_IS_TAB (tab));
      
      galeon_tab_set_security_level (tab, level);
}

static void
galeon_tab_popup_blocked_cb(GaleonEmbed *embed, const char *uri,  
                            GaleonTab *tab)
{
      g_return_if_fail (GALEON_IS_TAB (tab));

      if (tab->priv->blocked_popup_uri)
            g_free(tab->priv->blocked_popup_uri);

      tab->priv->blocked_popup_uri = uri ? g_strdup(uri) : NULL;

      g_object_notify (G_OBJECT (tab), "popup-blocked");
}

TabLoadStatus 
galeon_tab_get_load_status (GaleonTab *tab)
{
      return tab->priv->load_status;      
}

int
galeon_tab_get_load_percent (GaleonTab *tab)
{
      return tab->priv->load_percent;
}

const char *
galeon_tab_get_status_message (GaleonTab *tab)
{
      /* The statusbar message is the first one of the following:
       * 1) the URL if hovering the mouse over a link
       * 2) the javascript message if overwriting the statusbar is allowed
       * 3) normal status message (Loading..., Done, etc.)
       *
       * Note: CONF_FILTERING_DEFAULT_STATUSBAR is basically obsolete since
       * we don't let people 'fake' URLs by rewriting the statusbar.
       */

      if (*tab->priv->link_message)
      {
            return tab->priv->link_message;
      }
      else if (*tab->priv->js_message
             && eel_gconf_get_boolean (CONF_FILTERING_DEFAULT_STATUSBAR))
      {
            return tab->priv->js_message;
      }
      return tab->priv->status_message;
}

const char *
galeon_tab_get_title (GaleonTab *tab)
{
      if (tab->priv->title && 
          g_utf8_strlen(tab->priv->title, -1))
      {
            return tab->priv->title;
      }
      else
      {
            return _("Untitled");
      }
}

const char *
galeon_tab_get_location (GaleonTab *tab)
{
      return tab->priv->location;
}

const char *
galeon_tab_get_blocked_popup_uri(GaleonTab *tab)
{
      return tab->priv->blocked_popup_uri;
}

int
galeon_tab_get_zoom(GaleonTab *tab)
{
      return tab->priv->zoom;
}

void
galeon_tab_clear_blocked_popup_uri(GaleonTab *tab)
{
      if (tab->priv->blocked_popup_uri)
      {
            g_free(tab->priv->blocked_popup_uri);
            tab->priv->blocked_popup_uri = NULL;

            g_object_notify (G_OBJECT (tab), "popup-blocked");
      }
}

void 
galeon_tab_set_location (GaleonTab *tab,
                   const char *location)
{
      g_return_if_fail (GALEON_IS_TAB (tab));

      if (tab->priv->location) g_free (tab->priv->location);
      tab->priv->location = g_strdup (location);

      g_object_notify (G_OBJECT (tab), "location");
}

static void
galeon_tab_update_gestures (void)
{
      /* this should read a pref, parse it, setup a listener, etc */
      /* for now, just hardcode some */

      int i;
      static const struct 
      {
            gchar *sequence;
            gchar *action;
      } default_gestures[] = {
                /* menu */
                { "5"           , "menu"          },

            /* down */
                { "258"         , "new_tab"       },
            
                /* up */
                { "852"         , "new_window"    },
            
                /* up-down */
                { "85258"       , "reload"        },
                { "8525"        , "reload"        },
                { "5258"        , "reload"        },

                /* up-down-up */
                { "8525852"     , "reload_bypass" },
                { "852585"      , "reload_bypass" },
                { "85252"       , "reload_bypass" },
                { "85852"       , "reload_bypass" },
                { "525852"      , "reload_bypass" },
                { "52585"       , "reload_bypass" },

                /* up-left-down */
                { "9632147"     , "homepage"      },
                { "963214"      , "homepage"      },
                { "632147"      , "homepage"      },
                { "962147"      , "homepage"      },
                { "963147"      , "homepage"      },

                /* down-up */
                { "25852"       , "clone_window"  },
                { "2585"        , "clone_window"  },
                { "5852"        , "clone_window"  },

                /* down-up-down */
                { "2585258"     , "clone_tab"     },
                { "258525"      , "clone_tab"     },
                { "25858"       , "clone_tab"     },
                { "25258"       , "clone_tab"     },
                { "585258"      , "clone_tab"     },
                { "58525"       , "clone_tab"     },

                /* up-left-up */
                { "96541"       , "up"            },
                { "9651"        , "up"            },
                { "9541"        , "up"            },

                /* right-left-right */
                { "4565456"     , "close"         },
                { "456545"      , "close"         },
                { "45656"       , "close"         },
                { "45456"       , "close"         },
                { "565456"      , "close"         },
                { "56545"       , "close"         },

                /* down-right */
                { "14789"       , "close"         },
                { "1489"        , "close"         },

                /* left */
                { "654"         , "back"          },

                /* right */
                { "456"         , "forward"       },

                /* down-left */
                { "36987"       , "fullscreen"    },
                { "3687"        , "fullscreen"    },

                /* up-right */
                { "74123"       , "next_tab"      },
                { "7423"        , "next_tab"      },

                /* up-left */
                { "96321"       , "prev_tab"      },
                { "9621"        , "prev_tab"      },

                /* s */
                { "321456987"   , "view_source"   },
                { "21456987"    , "view_source"   },
                { "32145698"    , "view_source"   },
                { "3256987"     , "view_source"   },
                { "3214587"     , "view_source"   },
                { "32145987"    , "view_source"   },
                { "32156987"    , "view_source"   },

                /* left-up */
                { "98741"       , "stop"          },
                { "9841"        , "stop"          },

                /* left-down */
                { "32147"       , "prev_link"     },
                { "3247"        , "prev_link"     },
            
                /* right-down */
                { "12369"       , "next_link"     },
                { "1269"        , "next_link"     },

                /* up-right-up */
                { "74563"       , "contents_link" },
                { "7453"        , "contents_link" },
                { "7563"        , "contents_link" },

            { NULL            , NULL              }

      };
      
      if (gestures_actions)
      {
            g_hash_table_destroy (gestures_actions);
      }

      gestures_actions = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);

      for (i = 0; default_gestures[i].sequence; ++i)
      {
            g_hash_table_insert (gestures_actions, 
                             g_strdup (default_gestures[i].sequence), 
                             g_strdup (default_gestures[i].action));
      }
}

static void
galeon_tab_gesture_performed_cb (GulGestures *g, const gchar *sequence, GaleonTab *tab)
{
      const gchar  *action;
      GaleonWindow *window;
      GaleonEmbed  *embed;
      
      LOG ("gesture: %s", sequence);
      
      if (!gestures_actions)
      {
            galeon_tab_update_gestures ();
      }
      
      action = g_hash_table_lookup (gestures_actions, sequence);
      
      if (!action) 
      {
            return;
      }
      
      LOG ("action: %s", action);
      window = galeon_tab_get_window (tab);
      embed = galeon_tab_get_embed (tab);
      
      if (!strcmp (action, "menu"))
      {
            GaleonEmbedEvent *event = g_object_get_data(G_OBJECT(g), "embed_event");
            if (event != NULL)
            {
                  galeon_tab_show_embed_popup (tab, event);
            }
      }
      else if (!strcmp (action, "new_tab"))
      {
            galeon_shell_new_tab (galeon_shell, window, tab, NULL, 
                              GALEON_NEW_TAB_HOMEPAGE |
                              GALEON_NEW_TAB_IN_EXISTING_WINDOW |
                              GALEON_NEW_TAB_JUMP);
      }
      else if (!strcmp (action, "new_window"))
      {
            galeon_shell_new_tab (galeon_shell, window, tab, NULL,
                              GALEON_NEW_TAB_HOMEPAGE |
                              GALEON_NEW_TAB_IN_NEW_WINDOW |
                              GALEON_NEW_TAB_JUMP);
      }
      else if (!strcmp (action, "reload"))
      {
            galeon_embed_reload (embed, EMBED_RELOAD_NORMAL);
      }
      else if (!strcmp (action, "reload_bypass"))
      {
            galeon_embed_reload (embed, EMBED_RELOAD_FORCE);
      }
      else if (!strcmp (action, "homepage"))
      {
            char *homepage;

            homepage = eel_gconf_get_string (CONF_GENERAL_HOMEPAGE);
            g_return_if_fail (homepage != NULL);

            galeon_embed_load_url (embed, homepage);

            g_free (homepage);
      }
      else if (!strcmp (action, "clone_window"))
      {
            NOT_IMPLEMENTED;
      }
      else if (!strcmp (action, "clone_tab"))
      {
            galeon_shell_new_tab (galeon_shell, window, tab, NULL,
                              GALEON_NEW_TAB_IN_EXISTING_WINDOW |
                              GALEON_NEW_TAB_JUMP |
                              GALEON_NEW_TAB_COPY_HISTORY |
                              GALEON_NEW_TAB_IS_A_COPY);
      }
      else if (!strcmp (action, "up"))
      {
            galeon_embed_go_up (embed);
      }
      else if (!strcmp (action, "close"))
      {
            galeon_window_remove_tab (window, tab);
      }
      else if (!strcmp (action, "back"))
      {
            galeon_embed_go_back (embed);
      }
      else if (!strcmp (action, "forward"))
      {
            galeon_embed_go_forward (embed);
      }
      else if (!strcmp (action, "fullscreen"))
      {
            galeon_window_toggle_fullscreen (window);
      }
      else if (!strcmp (action, "next_tab"))
      {
            galeon_window_next_tab (window);
      }
      else if (!strcmp (action, "prev_tab"))
      {
            galeon_window_prev_tab (window);
      }
      else if (!strcmp (action, "view_source"))
      {
            galeon_shell_new_tab (galeon_shell, window, tab, NULL,
                              GALEON_NEW_TAB_IN_EXISTING_WINDOW |
                              GALEON_NEW_TAB_JUMP |
                              GALEON_NEW_TAB_COPY_HISTORY |
                              GALEON_NEW_TAB_VIEW_SOURCE);
      }
      else if (!strcmp (action, "stop"))
      {
            galeon_embed_stop_load (embed);
      }
      else if (!strcmp (action, "prev_link"))
      {
            NOT_IMPLEMENTED;
      }
      else if (!strcmp (action, "next_link"))
      {
            NOT_IMPLEMENTED;
      }
      else if (!strcmp (action, "contents_link"))
      {
            NOT_IMPLEMENTED;
      }
      else
      {
            /* unrecognized */
      }
}

gboolean
galeon_tab_is_empty (GaleonTab *tab)
{
      char *location;
      gboolean is_empty = FALSE;
      GaleonEmbed *embed;
      
      g_return_val_if_fail (GALEON_IS_TAB (tab), FALSE);

      embed = galeon_tab_get_embed (GALEON_TAB (tab));
      location = galeon_embed_get_location (embed, TRUE, TRUE);

      if (location == NULL    || 
          location[0] == '\0' || 
          strcmp (location, "about:blank") == 0)
      {
            is_empty = TRUE;
      }

      g_free (location);

      return is_empty;
}

Generated by  Doxygen 1.6.0   Back to index