The documentation for GtkWidget's drag-motion signal http://library.gnome.org/devel/gtk/stable/GtkWidget.html#GtkWidget-drag-motion says " If the decision whether the drop will be accepted or rejected can't be made based solely on the cursor position and the type of the data, the handler may inspect the dragged data by calling gtk_drag_get_data() and defer the gdk_drag_status() call to the "drag-data-received" handler. " But when I try to do this the cursor is grabbed while dragging and no further drag-and-drop signals are emitted. I guess I'm doing something wrong but i can't see what. I attached a simple test case. Watch out - you'll have to Shift-Alt-F1 to get a terminal so you can kill the test case after it grabs the cursor. I'm actually trying to do this so I can show a preview item in a canvas before the actual item is created on the canvas when the drop happens. -- murrayc@xxxxxxxxxxx www.murrayc.com www.openismus.com
/* Build with: * gcc test_get_data_in_drag_motion.cc.c `pkg-config gtk+-2.0 --cflags --libs` */ #include <gtk/gtk.h> #include <stdlib.h> #include <string.h> GtkWidget *dest = NULL; int drag_item = 0; /* We can't put an item on a button so this is just to show the idea. */ gboolean drag_preview_requested = FALSE; const int DRAG_DATA_FORMAT = 8; /* 8 bits format */ static void on_button_drag_data_get(GtkWidget *widget, GdkDragContext *drag_context, GtkSelectionData *selection_data, guint info, guint time, gpointer user_data) { GdkAtom target_atom = selection_data->target; const gchar *target_name = gdk_atom_name (target_atom); printf("on_button_drag_data_get(): target=%s\n", target_name); static gchar* drag_data = "something_to_drag"; gtk_selection_data_set(selection_data, target_atom, DRAG_DATA_FORMAT, (const guchar*)drag_data, strlen (drag_data)); } static gboolean on_dest_drag_drop(GtkWidget *widget, GdkDragContext *drag_context, gint x, gint y, guint time, gpointer user_data) { GdkAtom target_atom = gtk_drag_dest_find_target(dest, drag_context, NULL); const gchar *target_name = gdk_atom_name (target_atom); printf("on_dest_drag_drop(): target=%s\n", target_name); return TRUE; /* Allow the drop. */ } static gboolean on_dest_drag_motion(GtkWidget *widget, GdkDragContext *drag_context, gint x, gint y, guint timestamp, gpointer user_data) { GdkAtom target_atom = gtk_drag_dest_find_target(dest, drag_context, NULL); const gchar *target_name = gdk_atom_name (target_atom); printf("on_dest_drag_motion(): target=%s\n", target_name); gtk_drag_highlight (dest); /* Create the temporary dest item if necessary: */ if(!drag_item) { /* TODO: This stops the drop (or any further motion events) from happening: */ /* We need to examine the SelectionData: * This will cause our drag_data_received callback to be called, with that information: */ drag_preview_requested = TRUE; gtk_drag_get_data(dest, drag_context, target_atom, timestamp); return TRUE; } gdk_drag_status(drag_context, GDK_ACTION_COPY, timestamp); /* Here we would change the position of a temporary dest item. */ return TRUE; /* Allow the drop. */ } static void on_dest_drag_data_received(GtkWidget *widget, GdkDragContext *drag_context, gint x, gint y, GtkSelectionData *selection_data, guint info, guint timestamp, gpointer user_data) { /* This is called when an item is dropped on the dest, * or after our drag_motion handler has called drag_get_data(). */ /* Discover what toolbar item was dropped: * In a real application, we would this use (or ideally an ID) * to identify what should be created on the dest. */ gchar* item_name = NULL; if((selection_data->length >= 0) && (selection_data->format == DRAG_DATA_FORMAT)) { item_name = g_strndup (selection_data->data, selection_data->length); } printf("on_dest_drag_data_received(): dragged item type=%s", item_name); g_free (item_name); if(drag_preview_requested) { printf(" on_dest_drag_data_received(): drag_preview_requested"); /* Create the temporary drag item if necessary: */ if(!drag_item) { drag_item = 1; gdk_drag_status(drag_context, GDK_ACTION_COPY, timestamp); } drag_preview_requested = FALSE; } else { gtk_drag_finish (drag_context, TRUE, FALSE, timestamp); gtk_drag_unhighlight (dest); /* Remove the temporary drag item: */ drag_item = 0; /* Add the requested item to the dest: */ } } static gboolean on_delete_event (GtkWidget *window, GdkEvent *event, gpointer unused_data) { gtk_main_quit (); } int main (int argc, char *argv[]) { gtk_init (&argc, &argv); /* Create the widgets: */ GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_default_size (GTK_WINDOW (window), 640, 600); g_signal_connect (window, "delete_event", (GtkSignalFunc) on_delete_event, NULL); GtkWidget *vbox = gtk_vbox_new (FALSE, 6); gtk_widget_show (vbox); gtk_container_add (GTK_CONTAINER (window), vbox); GtkWidget *button = gtk_button_new_with_label("Drag Me"); gtk_widget_show (button); gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); dest = gtk_button_new_with_label ("drag dest"); gtk_widget_set_size_request (dest, 400, 400); gtk_widget_show (dest); gtk_box_pack_end (GTK_BOX (vbox), dest, TRUE, TRUE, 0); /* Setup the drag source: */ const GtkTargetEntry drag_targets[] = { { "my-drag-format", GTK_TARGET_SAME_APP, 0 } }; gtk_drag_source_set (button, GDK_MODIFIER_MASK, drag_targets, G_N_ELEMENTS (drag_targets), GDK_ACTION_COPY); /* gtk_drag_source_set_icon (); */ /* Let the item supply some data when the destination asks for it: */ g_signal_connect (button, "drag_data_get", (GtkSignalFunc) on_button_drag_data_get, NULL); /* Setup the drag target: */ gtk_drag_dest_set (dest, GTK_DEST_DEFAULT_ALL, drag_targets, G_N_ELEMENTS (drag_targets), GDK_ACTION_COPY); g_signal_connect (dest, "drag_drop", (GtkSignalFunc) on_dest_drag_drop, NULL); g_signal_connect (dest, "drag_motion", (GtkSignalFunc) on_dest_drag_motion, NULL); g_signal_connect (dest, "drag_data_received", (GtkSignalFunc) on_dest_drag_data_received, NULL); /* Pass control to the GTK+ main event loop. */ gtk_widget_show (window); gtk_main (); return 0; }
_______________________________________________ gtk-list mailing list gtk-list@xxxxxxxxx http://mail.gnome.org/mailman/listinfo/gtk-list