Logo Search packages:      
Sourcecode: galeon version File versions

bookmarks-gtk-toolbar.c

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

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

#include <glib/gi18n.h>
#include "bookmarks-gtk-toolbar.h"
#include "bookmarks-tb-widget.h"
#include "bookmarks-dnd.h"
#include "galeon-dnd.h"
#include "galeon-marshal.h"
#include "gul-string.h"
#include "bookmarks-context-menu.h"
#include "bookmarks-gtk-menu-item.h"
#include "galeon-debug.h"

#include <gtk/gtkseparatortoolitem.h>
#include <gtk/gtkseparatormenuitem.h>
#include <gtk/gtktoolbutton.h>

/**
 * Private data
 */
#define GB_GTK_TOOLBAR_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), \
                               GB_TYPE_GTK_TOOLBAR, GbGtkToolbarPrivate))


struct _GbGtkToolbarPrivate {
      GbFolder *root;
      guint rebuild_timeout;

      GbLocationSource *location_source;
      GSList *toolbaritems;

      GtkToolItem *drag_item;
      GtkStatusbar *statusbar;
};

#define REBUILD_TIMEOUT 700

/**
 * Private functions, only availble from this file
 */
static void       gb_gtk_toolbar_finalize_impl        (GObject *o);
static void       gb_gtk_toolbar_build                (GbGtkToolbar *gm);
static void       gb_gtk_toolbar_build_bookmark       (GbGtkToolbar *gm, GbBookmark *item, guint index);

static void       gb_gtk_toolbar_child_added_cb       (GbFolder *p, GbBookmark *c, 
                                                 gint position, GbGtkToolbar *gm);
static void       gb_gtk_toolbar_child_removed_cb           (GbFolder *p, GbBookmark *c, 
                                                 gint position, GbGtkToolbar *gm);
static void       gb_gtk_toolbar_rebuild              (GbGtkToolbar *gm);
static void       gb_gtk_toolbar_bookmark_activated_cb      (GObject *sender,
                                                 GbBookmarkEventActivated *ev,
                                                 GbGtkToolbar *gm);


enum GbGtkToolbarSignalsEnum {
      GB_GTK_TOOLBAR_BOOKMARK_ACTIVATED,
      GB_GTK_TOOLBAR_LAST_SIGNAL
};
static gint GbGtkToolbarSignals[GB_GTK_TOOLBAR_LAST_SIGNAL];

/**
 * GtkToolbar object
 */

G_DEFINE_TYPE (GbGtkToolbar, gb_gtk_toolbar, GTK_TYPE_TOOLBAR);

static void
gb_gtk_toolbar_class_init (GbGtkToolbarClass *klass)
{
      G_OBJECT_CLASS (klass)->finalize = gb_gtk_toolbar_finalize_impl;

      GbGtkToolbarSignals[GB_GTK_TOOLBAR_BOOKMARK_ACTIVATED] = g_signal_new (
            "bookmark-activated", G_OBJECT_CLASS_TYPE (klass),  
            G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST | G_SIGNAL_RUN_CLEANUP,
                G_STRUCT_OFFSET (GbGtkToolbarClass, gb_gtk_toolbar_bookmark_activated), 
            NULL, NULL, 
            g_cclosure_marshal_VOID__POINTER,
            G_TYPE_NONE, 1, G_TYPE_POINTER);

      g_type_class_add_private (klass, sizeof (GbGtkToolbarPrivate));
}

static gboolean
gb_gtk_toolbar_button_press_cb (GtkWidget *wid, GdkEventButton *event, 
                        GbGtkToolbar *gtb)
{
      GbGtkToolbarPrivate *p = gtb->priv;
      g_return_val_if_fail (GB_IS_BOOKMARK (p->root), FALSE);

      if (event->button == 3)
      {
            gb_context_menu_quick (GB_BOOKMARK (p->root), event, p->location_source, G_OBJECT (gtb));
            return TRUE;
      }
      /* TODO: maybe paste?
      else if (event->button == 2)
      {
            const gchar *url = GB_IS_SITE (p->bm) ? GB_SITE (p->bm)->url : NULL;
            gb_activated_event (w, p->bm, url, GB_BAF_NEW_TAB_OR_WINDOW, (GdkEvent *) event);
            return TRUE;
      }
      */
      return FALSE;
}

static void 
gb_gtk_toolbar_init (GbGtkToolbar *m)
{
      GbGtkToolbarPrivate *p = GB_GTK_TOOLBAR_GET_PRIVATE (m);
      m->priv = p;

      gtk_toolbar_set_show_arrow (GTK_TOOLBAR (m), TRUE);
      gtk_toolbar_set_style (GTK_TOOLBAR (m), GTK_TOOLBAR_TEXT);

      g_signal_connect (m, "button_press_event",
                    G_CALLBACK (gb_gtk_toolbar_button_press_cb), m);
}

static void
gb_gtk_toolbar_finalize_impl (GObject *o)
{
      GbGtkToolbar *gm = GB_GTK_TOOLBAR (o);
      GbGtkToolbarPrivate *p = gm->priv;
      GSList *li;

      LOG ("Finalizing GbGtkToolbar");

      gb_gtk_toolbar_set_location_source (gm, NULL);

      g_signal_handlers_disconnect_matched (p->root, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, gm);
      if (GB_BOOKMARK (p->root)->set)
      {
            g_signal_handlers_disconnect_matched (GB_BOOKMARK (p->root)->set, 
                                          G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, gm);
      }

      if (p->rebuild_timeout)
      {
            g_source_remove (p->rebuild_timeout);
      }

      for (li = p->toolbaritems; li; li = li->next)
      {
            g_object_unref (li->data);
      }
      g_slist_free (p->toolbaritems);

      g_object_unref (G_OBJECT (p->root));

      if (p->statusbar)
      {
            g_object_unref (p->statusbar);
      }

      G_OBJECT_CLASS (gb_gtk_toolbar_parent_class)->finalize (o);
}

typedef struct
{
      GbFolder *folder;
      int pos;
} GbGtkToolbarDragDatareceivedInfo;

static void
gb_gtk_toolbar_each_url_receive_data_binder (const char * url, const char * title, gpointer context)
{
      GbGtkToolbarDragDatareceivedInfo *info = context;
      GbSite *niu;

      g_return_if_fail (GB_IS_FOLDER (info->folder));

      if (!title) title = url;

      niu = gb_site_new (GB_BOOKMARK (info->folder)->set, title, url);
      gb_bookmark_set_time_added_now (GB_BOOKMARK (niu));

      gb_folder_add_child (info->folder, GB_BOOKMARK (niu), info->pos);
      g_object_unref (niu);

      info->pos++;
}



static void
gb_gtk_toolbar_drag_data_received_cb (GtkWidget *widget,
                              GdkDragContext *dc,
                              gint x, gint y,
                              GtkSelectionData *selection_data,
                              guint info,
                              guint t,
                              GbGtkToolbar *tb)
{
      GbGtkToolbarPrivate *p = tb->priv;
      GbGtkToolbarDragDatareceivedInfo aux;
      aux.pos = gtk_toolbar_get_drop_index (GTK_TOOLBAR (widget), x, y);
      aux.folder = p->root;
      
      galeon_dnd_drag_data_receive (widget, dc, x, y, selection_data,
                              info, t, &aux, gb_gtk_toolbar_each_url_receive_data_binder);

      /* Rebuild immediately to avoid nasty sliding artifacts */
      gb_gtk_toolbar_rebuild (GB_GTK_TOOLBAR (widget));
}
      

static gboolean
toolbar_drag_motion (GbGtkToolbar *toolbar,
                 GdkDragContext *context,
                 gint            x,
                 gint            y,
                 guint           time,
                 gpointer        null)
{
      gint index;
      LOG ("toolbar_drag_motion");

      if( !gtk_drag_dest_find_target (GTK_WIDGET (toolbar), context, NULL))
      {
            return FALSE;
      }

      if (!toolbar->priv->drag_item)
      {
            /* This item is just used to add some padding for visual 
             * feedback */
            toolbar->priv->drag_item = gtk_tool_button_new (NULL, "m");
            g_object_ref (G_OBJECT (toolbar->priv->drag_item));
            gtk_object_sink (GTK_OBJECT (toolbar->priv->drag_item));
      }
  
      gdk_drag_status (context, context->suggested_action, time);

      index = gtk_toolbar_get_drop_index (GTK_TOOLBAR (toolbar), x, y);
      gtk_toolbar_set_drop_highlight_item (GTK_TOOLBAR (toolbar), 
                                   toolbar->priv->drag_item, index);

      return TRUE;
}

static void
toolbar_drag_leave (GbGtkToolbar   *toolbar,
                GdkDragContext *context,
                guint           time,
                gpointer          null)
{
      LOG ("toolbar_drag_leave");
      if (toolbar->priv->drag_item)
      {
            g_object_unref (G_OBJECT (toolbar->priv->drag_item));
            toolbar->priv->drag_item = NULL;
      }
      
      gtk_toolbar_set_drop_highlight_item (GTK_TOOLBAR (toolbar), NULL, 0);
}

GbGtkToolbar *
gb_gtk_toolbar_new (GbFolder *root)
{
      GbGtkToolbar *ret = g_object_new (GB_TYPE_GTK_TOOLBAR, NULL);
      GbGtkToolbarPrivate *p = ret->priv;

      p->root = root;
      g_object_ref (root);

      g_signal_connect (root, "child-added", 
                    G_CALLBACK (gb_gtk_toolbar_child_added_cb), ret);
      g_signal_connect (root, "child-removed", 
                    G_CALLBACK (gb_gtk_toolbar_child_removed_cb), ret);

      p->toolbaritems = NULL;
      gb_gtk_toolbar_rebuild (ret);

      galeon_dnd_url_drag_dest_set_with_flags (GTK_WIDGET (ret), GTK_DEST_DEFAULT_DROP);

      g_signal_connect (ret, "drag_data_received",
                    G_CALLBACK (gb_gtk_toolbar_drag_data_received_cb), ret);

      g_signal_connect (ret, "drag_motion",
                    G_CALLBACK (toolbar_drag_motion), ret);
      g_signal_connect (ret, "drag_leave", 
                    G_CALLBACK (toolbar_drag_leave), ret);

      return ret;
}

static gboolean
gb_gtk_toolbar_create_menu_proxy_cb (GtkToolItem *item, GbGtkToolbar *gtb)
{
      GbGtkToolbarPrivate *p = gtb->priv;
      GtkWidget *proxy;
      if (GTK_IS_SEPARATOR_TOOL_ITEM (item))
      {
            proxy = gtk_separator_menu_item_new ();
      }
      else
      {
            GbTbWidget *tbw = GB_TB_WIDGET (GTK_BIN (item)->child);
            GbBookmark *b = gb_tb_widget_get_bookmark (tbw);
            proxy = GTK_WIDGET (gb_gtk_menu_item_new (b));
            gb_gtk_menu_item_set_location_source (GB_GTK_MENU_ITEM (proxy), p->location_source);
            gb_gtk_menu_item_set_statusbar (GB_GTK_MENU_ITEM (proxy), p->statusbar);
            g_signal_connect (proxy, "bookmark-activated", 
                          G_CALLBACK (gb_gtk_toolbar_bookmark_activated_cb), gtb);
      }
      gtk_tool_item_set_proxy_menu_item (item, "bookmark-menu-item-proxy", GTK_WIDGET (proxy));
      return TRUE;
}

static void
gb_gtk_toolbar_build_separator (GbGtkToolbar *gm, guint index)
{
      GbGtkToolbarPrivate *p = gm->priv;
      GtkToolItem *sep = gtk_separator_tool_item_new ();
      g_signal_connect (sep, "create_menu_proxy",
                    G_CALLBACK (gb_gtk_toolbar_create_menu_proxy_cb), gm);
      gtk_widget_show (GTK_WIDGET (sep));
      p->toolbaritems = g_slist_prepend (p->toolbaritems, g_object_ref (sep));
      gtk_toolbar_insert (GTK_TOOLBAR (gm), sep, index);
}


static void
gb_gtk_toolbar_build_bookmark (GbGtkToolbar *gm, GbBookmark *item, guint index)
{
      GbGtkToolbarPrivate *p = gm->priv;
      GbTbWidget *w = gb_bookmark_create_toolbar_widget (item);
      GtkToolItem *ti = gtk_tool_item_new ();
      gb_tb_widget_set_location_source (w, p->location_source);
      gb_tb_widget_set_statusbar (w, p->statusbar);
      g_signal_connect (w, "bookmark-activated", 
                    G_CALLBACK (gb_gtk_toolbar_bookmark_activated_cb), gm);

      p->toolbaritems = g_slist_prepend (p->toolbaritems, g_object_ref (w));

      gtk_widget_show (GTK_WIDGET (w));
      
      gtk_container_add (GTK_CONTAINER (ti), GTK_WIDGET (w));
      gtk_widget_show (GTK_WIDGET (ti));

      g_signal_connect (ti, "create_menu_proxy",
                    G_CALLBACK (gb_gtk_toolbar_create_menu_proxy_cb), gm);

      gtk_toolbar_insert (GTK_TOOLBAR (gm), ti, index);
}


static void
gb_gtk_toolbar_build (GbGtkToolbar *gm)
{
      GbGtkToolbarPrivate *p = gm->priv;
      guint index = 0;
      GSList *items;
      GSList *li;

      items = gb_folder_list_children (p->root);

      for (li = items; li != NULL; li = li->next)
      {
            GbBookmark *i = li->data;
            
            if  (GB_IS_FOLDER (i) || GB_IS_SITE (i))
            {
                  gb_gtk_toolbar_build_bookmark (gm, i, index);
            }
            else if (GB_IS_SEPARATOR (i))
            {
                  gb_gtk_toolbar_build_separator (gm, index);
            }
            else
            {
                  g_warning ("something skipped when building bookmarks toolbar");
            }
            index++;
      }

      g_slist_free (items);
}

void
gb_gtk_toolbar_set_location_source (GbGtkToolbar *gm, GbLocationSource *src)
{
      GbGtkToolbarPrivate *p = gm->priv;
      const GSList *li;

      if (p->location_source)
      {
            g_object_remove_weak_pointer (G_OBJECT (p->location_source),
                                    (gpointer *) &p->location_source);
      }

      p->location_source = src;

      if (p->location_source)
      {
            g_object_add_weak_pointer (G_OBJECT (p->location_source), 
                                 (gpointer *) &p->location_source);
      }

      for (li = p->toolbaritems; li; li = li->next)
      {
            if (GB_IS_TB_WIDGET (li->data))
            {
                  gb_tb_widget_set_location_source (li->data, src);
            }
      }
}

void
gb_gtk_toolbar_set_statusbar (GbGtkToolbar *gt, GtkStatusbar *statusbar)
{
      GbGtkToolbarPrivate *p = gt->priv;
      const GSList *li;
      g_return_if_fail (!statusbar || GTK_IS_STATUSBAR (statusbar));
      if (p->statusbar)
      {
            g_object_unref (p->statusbar);
            p->statusbar = NULL;
      }

      if (statusbar)
      {
            p->statusbar = g_object_ref (statusbar);
      }     
      
      for (li = p->toolbaritems; li; li = li->next)
      {
            if (GB_IS_TB_WIDGET (li->data))
            {
                  gb_tb_widget_set_statusbar (li->data, statusbar);
            }
      }
}

static gboolean
gb_gtk_toolbar_rebuild_idle_cb (gpointer data)
{
      GbGtkToolbar *gm = data;
      GbGtkToolbarPrivate *p = gm->priv;
      LOG ("GbGtkToolbar rebuild idle");

      p->rebuild_timeout = 0;

      gb_gtk_toolbar_rebuild (data);
      return FALSE;
}

static void 
gb_gtk_toolbar_rebuild_when_idle (GbGtkToolbar *gm) 
{
      GbGtkToolbarPrivate *p = gm->priv;

      if (p->rebuild_timeout)
      {
            g_source_remove (p->rebuild_timeout);
      }
      
      p->rebuild_timeout = g_idle_add (gb_gtk_toolbar_rebuild_idle_cb, gm);
}

static void
gb_gtk_toolbar_rebuild (GbGtkToolbar *gm)
{
      GbGtkToolbarPrivate *p = gm->priv;
      GSList *sli;

      LOG ("gb_gtk_toolbar_rebuild called");
      
      /* this could be more fine grained. For now, just destroy everything and 
         build it again */
      
      /* remove already created toolbaritems*/
      for (sli = p->toolbaritems; sli; sli = sli->next)
      {
            GtkWidget *toolitem = GTK_WIDGET (sli->data);

            /* this is a bit ugly... */
            if (!GTK_IS_SEPARATOR_TOOL_ITEM (sli->data))
            {
                  toolitem = toolitem->parent;
            }
            gtk_container_remove (GTK_CONTAINER (gm), toolitem);
      }

      /* free the list of toolbaritems */
      for (sli = p->toolbaritems; sli; sli = sli->next)
      {
            g_object_unref (sli->data);
      }
      g_slist_free (p->toolbaritems);
      p->toolbaritems = NULL;

      gb_gtk_toolbar_build (gm);
}

static void
gb_gtk_toolbar_child_added_cb (GbFolder *p, GbBookmark *c, gint position, GbGtkToolbar *gm)
{
      gb_gtk_toolbar_rebuild_when_idle (gm);
}

static void
gb_gtk_toolbar_child_removed_cb (GbFolder *p, GbBookmark *c, gint position, GbGtkToolbar *gm)
{
      gb_gtk_toolbar_rebuild_when_idle (gm);
}

static void
gb_gtk_toolbar_bookmark_activated_cb (GObject *sender,
                           GbBookmarkEventActivated *ev,
                           GbGtkToolbar *gm)
{
      g_signal_emit (gm, GbGtkToolbarSignals[GB_GTK_TOOLBAR_BOOKMARK_ACTIVATED], 0, ev);
}


Generated by  Doxygen 1.6.0   Back to index