Can drop but can't drag

In my application I can drag from outside my program and drop in it. So I know my drop code is good. However, my drag code doesn’t work even within my program.

I worked on this problem for a good long while but gave up. I’ve come back to it. Help please. Any examples please…

Here is the calling code:

 void source_drag_image
 (
 	GtkWidget          *widget,
 	__attribute__((unused))GdkDragContext     *context,
 	GtkSelectionData   *selection_data,
 	__attribute__((unused))guint               info,
 	__attribute__((unused))guint               time,
 	__attribute__((unused))gpointer            data
 )
 {
 	char widget_name[WIDGET_NAME_LENGTH];
 	int strip_location;
 	guchar *dropped_text;
 
 	gui_printf("drag_image_sourced\n");      // source_drag_image is NEVER called, ???
 
 	strcpy(widget_name, gtk_widget_get_name(widget));
 	strip_location = atoi(widget_name);
 	dropped_text = (guchar *)film_strip_data[strip_location].dropped_text;
 
 	gtk_selection_data_set
 	(
 		selection_data,
 		gtk_selection_data_get_target(selection_data),
 		8,	// bytes
 		dropped_text, sizeof(dropped_text)
 	);
 }
 
 /*-----------------------------------------------------------------------------*/
 
 		g_signal_connect
 		(
 			image_strip[k],       // an array of  image 'cells'
 			"drag-data-get",     // is this right ?
 			G_CALLBACK(source_drag_image),
 			NULL
 		);
 
 		gtk_drag_dest_set
 		(
 			GTK_WIDGET(image_strip[k]),
 			GTK_DEST_DEFAULT_ALL,
 			target_table,
 			G_N_ELEMENTS(target_table),
 			GDK_ACTION_COPY
 		);
 
 		gtk_drag_source_set
 		(
 			GTK_WIDGET(image_strip[k]),
 			GDK_BUTTON1_MASK,	// GdkModifierType start_button_mask,
 			target_table,
 			G_N_ELEMENTS(target_table),
 			GDK_ACTION_MOVE
 		);

I’m not into this topic but did you check the documentation?

Thanks for the quick reply. I’m using GTK 3.0 which seems to have completely different API to 4.0 and I can’t find an equivalent page in the 3.0 documentation.

For the GTK3 API, there’s a tutorial on the GNOME wiki: HowDoI/DragAndDrop - GNOME Wiki!

Thanks Emmanuele but I just find a large flow chart diagram and not a code example. It isn’t a tutorial just a high level chart of how drag and drop operates.

The diagram explains what to do at every step, including what API to call.

If you want code to copy-paste, then you can look into the gtk3-demo demo application that is provided by GTK itself; it has an interactive example of drag and drop, and it provides the code. It’s also available in the Git repository: demos/gtk-demo/clipboard.c · gtk-3-24 · GNOME / gtk · GitLab

1 Like

That’s more like it !

Except there is some thing weird with the first few lines:


GtkWidget *
do_clipboard (GtkWidget *do_widget)
{
  static GtkWidget *window = NULL;

  if (!window)
    {
      GtkWidget *vbox, *hbox;
      GtkWidget *label;
      GtkWidget *entry, *button;
      GtkWidget *ebox, *image;
      GtkClipboard *clipboard;
                ...

The top level window is set to NULL then tested if it is NULL. There is no explanation. It must be something left over from testing…

Well, I have no much experience with designing DnD sources. Nevertheless, two considerations:

(1) Your gtk_drag_source_set sets GDK_ACTION_MOVE. Is it really necessary? This action is different from what you set in gtk_drag_dest_set, which can be a cause for the failure.
(2) The documentation about gtk_drag_source_set says “The [source] widget must have a window.” They probably mean that the DnD source widget must have a GdkWindow of its own and not simply use a GdkWindow of its container. You can add a GdkWindow by putting the widget in question into a GtkEventBox.

In the sample code posted by Mr. Bassi you see this quite well:

image = gtk_image_new_from_icon_name (“dialog-warning”, GTK_ICON_SIZE_BUTTON);
ebox = gtk_event_box_new ();

gtk_container_add (GTK_CONTAINER (ebox), image);
gtk_container_add (GTK_CONTAINER (hbox), ebox);

/* make ebox a drag source */
gtk_drag_source_set (ebox, GDK_BUTTON1_MASK, NULL, 0, GDK_ACTION_COPY);
// …

The image is inserted into an event box that acts then as a source widget, at least, technically - in function parameters. Among other things, you’d better connect signals to the event box and not to the contained widget.

No, it’s not. The top level window is stored in a static variable, which means it’s kept around until the window is explicitly destroyed; this allows the demo shell to reuse the same window instead of constructing it from scratch every time.

I now see the static declaration.

I’m plowing along with the “Clipboard” demo which does drag-and-drop within the program just fine.

My own code does drag-and-drop from outside from “Nautilus” (the Linux Mint file manager) to my program just fine, too. In this case the drop is a text string that has to be slightly parsed to retrieve the filename and subsequently the image file.

The demo code has:

gtk_drag_source_add_image_targets(ebox);
gtk_drag_dest_add_image_targets(ebox);

But my code doesn’t set these targets but uses a target table (instead ?)

gtk_drag_source_set
(
    ebox, 
    GDK_BUTTON1_MASK, 
    target_table,
    G_N_ELEMENTS(target_table),
    GDK_ACTION_COPY
);

However I’m guessing that using:

gtk_drag_source_add_text_targets(ebox);
gtk_drag_dest_add_text_targets(ebox);

Would be equivalent is this the case ?

Can I used both ?

gtk_drag_source_add_text_targets(ebox);
gtk_drag_dest_add_text_targets(ebox);
gtk_drag_source_add_image_targets(ebox);
gtk_drag_dest_add_image_targets(ebox);

Most importantly:
I also assume that the text string returned from the drag within the program will be quite different so there will have to be a different behavior depending on the drag source ?

Things are cruising along and I found this:
Old Drag and Drop Tutorial
which indicates the drag receiver should get a target type to switch on but I always get zero.

Here is the called code:

Images happily drag and drop within my demo but dragging an image from the file manager just bounces. The dropped data is text (a filename), that I know.

I don’t think my solution is great but it does work. I’d much rather switch on the target_type than detecting a NULL filename.

void drag_data_received     // dropped
(
    GtkWidget           *widget,
    GdkDragContext      *context,
    gint                x,
    gint                y,
    GtkSelectionData    *selection_data,
    guint               target_type,       // target type
    guint32             time,
    gpointer            image_widget
)
{
	GdkPixbuf *pixbuf;
    char *filename, clean_filename[FILENAME_DIRENT_MAX];
 
    printf("drag_data_received (dropped) type %u\n", target_type);
	filename = (char *)gtk_selection_data_get_text(selection_data);
    
    if(filename != NULL)
    {
        clean_up_uri_filename(filename, clean_filename);
        printf("(dropped)%s\n", clean_filename);
        pixbuf = read_file_image_to_pixbuf(clean_filename);
		gtk_image_set_from_pixbuf(GTK_IMAGE(image_widget), pixbuf);
		g_object_unref(pixbuf);
    }
    else
	if(gtk_selection_data_get_length(selection_data) > 0)
	{
        printf("(dropped) an image\n");
		pixbuf = gtk_selection_data_get_pixbuf(selection_data);
		gtk_image_set_from_pixbuf(GTK_IMAGE(image_widget), pixbuf);
		g_object_unref(pixbuf);
	}
    else
    {
        printf("(dropped) unrecognized\n");
    }
}

Emmanuele,
Is there some formal way that a “drop” can identify the “drag” widget ?
I’m using a global variable but there has to be a better way…
Clive.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.