aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog12
-rw-r--r--src/bookmarks/ephy-topic-action.c169
2 files changed, 165 insertions, 16 deletions
diff --git a/ChangeLog b/ChangeLog
index 1ca027721..3ebef6892 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2004-07-11 Marco Pesenti Gritti <marco@gnome.org>
+
+ * src/bookmarks/ephy-topic-action.c: (create_tool_item),
+ (menu_deactivate_cb), (remove_from_model), (remove_activate_cb),
+ (drag_data_get_cb), (drag_data_delete_cb), (stop_drag_check),
+ (check_horizontal_threshold), (drag_motion_cb),
+ (button_toggled_cb), (button_release_cb), (button_press_cb),
+ (connect_proxy):
+
+ Implement topics drag and drop. Totally tricky but it seem
+ to work fine :)
+
2004-07-11 Christian Persch <chpe@cvs.gnome.org>
* src/bookmarks/ephy-bookmark-action.c: (drag_motion_cb):
diff --git a/src/bookmarks/ephy-topic-action.c b/src/bookmarks/ephy-topic-action.c
index bdbd1e50f..ab3259219 100644
--- a/src/bookmarks/ephy-topic-action.c
+++ b/src/bookmarks/ephy-topic-action.c
@@ -25,6 +25,7 @@
#include <gtk/gtktoolitem.h>
#include <glib/gi18n.h>
#include <libgnomevfs/gnome-vfs-uri.h>
+#include <string.h>
#include "ephy-topic-action.h"
#include "ephy-node-common.h"
@@ -33,6 +34,7 @@
#include "ephy-favicon-cache.h"
#include "ephy-shell.h"
#include "ephy-debug.h"
+#include "ephy-dnd.h"
#include "ephy-gui.h"
#include "ephy-string.h"
#include "ephy-marshal.h"
@@ -42,10 +44,20 @@ static void ephy_topic_action_class_init (EphyTopicActionClass *class);
#define EPHY_TOPIC_ACTION_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), EPHY_TYPE_TOPIC_ACTION, EphyTopicActionPrivate))
+static GtkTargetEntry drag_targets[] =
+{
+ { EPHY_DND_TOPIC_TYPE, 0, 0 }
+};
+static int n_drag_targets = G_N_ELEMENTS (drag_targets);
+
struct EphyTopicActionPrivate
{
guint topic_id;
EphyNode *topic_node;
+
+ guint motion_handler;
+ gint drag_x;
+ gint drag_y;
};
enum
@@ -109,6 +121,7 @@ create_tool_item (GtkAction *action)
gtk_container_add (GTK_CONTAINER (item), hbox);
button = gtk_toggle_button_new ();
+ gtk_widget_add_events (GTK_WIDGET (button), GDK_BUTTON1_MOTION_MASK);
gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
gtk_widget_show (button);
gtk_container_add (GTK_CONTAINER (hbox), button);
@@ -133,6 +146,7 @@ create_tool_item (GtkAction *action)
static void
menu_deactivate_cb (GtkMenuShell *ms, GtkWidget *button)
{
+ g_object_set_data (G_OBJECT (button), "popup", NULL);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), FALSE);
gtk_button_released (GTK_BUTTON (button));
}
@@ -348,17 +362,17 @@ open_in_tabs_activate_cb (GtkWidget *menu, EphyTopicAction *action)
}
static void
-remove_activate_cb (GtkWidget *menu, GtkWidget *proxy)
+remove_from_model (GtkWidget *widget)
{
EphyBookmarks *bookmarks;
EggToolbarsModel *model;
GtkWidget *item, *toolbar;
int pos;
- item = gtk_widget_get_ancestor (proxy, GTK_TYPE_TOOL_ITEM);
+ item = gtk_widget_get_ancestor (widget, GTK_TYPE_TOOL_ITEM);
g_return_if_fail (item != NULL);
- toolbar = gtk_widget_get_ancestor (proxy, GTK_TYPE_TOOLBAR);
+ toolbar = gtk_widget_get_ancestor (widget, GTK_TYPE_TOOLBAR);
g_return_if_fail (toolbar != NULL);
pos = gtk_toolbar_get_item_index (GTK_TOOLBAR (toolbar),
@@ -369,6 +383,12 @@ remove_activate_cb (GtkWidget *menu, GtkWidget *proxy)
egg_toolbars_model_remove_item (model, 0, pos);
}
+static void
+remove_activate_cb (GtkWidget *menu, GtkWidget *proxy)
+{
+ remove_from_model (proxy);
+}
+
static GtkWidget *
add_open_in_tabs_menu (EphyTopicAction *action, GtkWidget *menu)
{
@@ -518,27 +538,104 @@ build_menu (EphyTopicAction *action)
}
static void
+drag_data_get_cb (GtkWidget *widget, GdkDragContext *context,
+ GtkSelectionData *selection_data, guint info,
+ guint32 time, EphyTopicAction *action)
+{
+ EphyBookmarks *bookmarks;
+ char *uri;
+
+ bookmarks = ephy_shell_get_bookmarks (ephy_shell);
+ g_return_if_fail (bookmarks != NULL);
+
+ uri = ephy_bookmarks_get_topic_uri (bookmarks, action->priv->topic_node);
+ g_return_if_fail (uri != NULL);
+
+ gtk_selection_data_set (selection_data, selection_data->target, 8,
+ uri, strlen (uri));
+
+ g_free (uri);
+}
+
+static void
+drag_data_delete_cb (GtkWidget *widget, GdkDragContext *context,
+ EphyTopicAction *action)
+{
+ remove_from_model (widget);
+}
+
+static gboolean
+stop_drag_check (EphyTopicAction *action, GtkWidget *widget)
+{
+ if (action->priv->motion_handler)
+ {
+ g_signal_handler_disconnect (widget, action->priv->motion_handler);
+ action->priv->motion_handler = 0;
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+check_horizontal_threshold (GtkWidget *widget, gint start_x, gint start_y,
+ gint current_x, gint current_y)
+{
+ gint drag_threshold;
+
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
+
+ g_object_get (gtk_widget_get_settings (widget),
+ "gtk-dnd-drag-threshold", &drag_threshold,
+ NULL);
+
+ return (ABS (current_x - start_x) > drag_threshold &&
+ ABS (current_y - start_y) < drag_threshold);
+}
+
+static gboolean
+drag_motion_cb (GtkWidget *widget, GdkEventMotion *event, EphyTopicAction *action)
+{
+ GtkWidget *button, *event_widget;
+
+ event_widget = gtk_get_event_widget ((GdkEvent*) event);
+ button = GTK_WIDGET (g_object_get_data (G_OBJECT (widget), "button"));
+
+ if (!gtk_widget_is_ancestor (event_widget, widget) &&
+ check_horizontal_threshold (widget, action->priv->drag_x,
+ action->priv->drag_y, event->x, event->y))
+ {
+ GtkTargetList *target_list;
+
+ target_list = gtk_target_list_new (drag_targets, n_drag_targets);
+
+ stop_drag_check (action, widget);
+ gtk_menu_popdown (GTK_MENU (widget));
+ gtk_drag_begin (button, target_list, GDK_ACTION_MOVE |
+ GDK_ACTION_COPY, 1, (GdkEvent*)event);
+ }
+
+ return TRUE;
+}
+
+static void
button_toggled_cb (GtkWidget *button,
EphyTopicAction *action)
{
- GtkWidget *menu;
-
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)))
{
+ GtkWidget *menu;
+
menu = build_menu (action);
g_signal_connect (menu, "deactivate",
G_CALLBACK (menu_deactivate_cb), button);
gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
ephy_gui_menu_position_under_widget,
button, 1, gtk_get_current_event_time ());
- }
-}
-static void
-button_pressed_cb (GtkWidget *button,
- EphyTopicAction *action)
-{
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
+ g_object_set_data (G_OBJECT (button), "popup", menu);
+ }
}
static GtkWidget *
@@ -606,12 +703,48 @@ popup_menu_cb (GtkWidget *widget, EphyTopicAction *action)
}
static gboolean
+button_release_cb (GtkWidget *widget,
+ GdkEventButton *event,
+ EphyTopicAction *action)
+{
+ if (event->button == 1)
+ {
+ stop_drag_check (action, widget);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), FALSE);
+ }
+
+ return FALSE;
+}
+
+static gboolean
button_press_cb (GtkWidget *widget,
GdkEventButton *event,
EphyTopicAction *action)
{
- if (event->button == 3 &&
- gtk_widget_get_ancestor (widget, EPHY_TYPE_BOOKMARKSBAR))
+ if (event->button == 1 &&
+ gtk_widget_get_ancestor (widget, EPHY_TYPE_BOOKMARKSBAR))
+ {
+ if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
+ {
+ GtkWidget *menu;
+
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE);
+ menu = g_object_get_data (G_OBJECT (widget), "popup");
+ g_return_val_if_fail (menu != NULL, FALSE);
+
+ g_object_set_data (G_OBJECT (menu), "button", widget);
+
+ action->priv->drag_x = event->x;
+ action->priv->drag_y = event->y;
+ action->priv->motion_handler = g_signal_connect
+ (menu, "motion_notify_event",
+ G_CALLBACK (drag_motion_cb), action);
+
+ return TRUE;
+ }
+ }
+ else if (event->button == 3 &&
+ gtk_widget_get_ancestor (widget, EPHY_TYPE_BOOKMARKSBAR))
{
show_context_menu (action, widget, NULL);
return TRUE;
@@ -642,8 +775,12 @@ connect_proxy (GtkAction *action, GtkWidget *proxy)
G_CALLBACK (popup_menu_cb), action);
g_signal_connect (button, "button-press-event",
G_CALLBACK (button_press_cb), action);
- g_signal_connect (button, "pressed",
- G_CALLBACK (button_pressed_cb), action);
+ g_signal_connect (button, "button-release-event",
+ G_CALLBACK (button_release_cb), action);
+ g_signal_connect (button, "drag_data_get",
+ G_CALLBACK (drag_data_get_cb), action);
+ g_signal_connect (button, "drag_data_delete",
+ G_CALLBACK (drag_data_delete_cb), action);
}
}