Question related to setting up text drag and drop (pygtk3)

Hi,

I’m facing an issue with the drag 'n drop feature, in an existing project (gnuradio-companion).

The destination widget (Gtk.DrawingArea) is set up to receive text:

    self.drag_dest_set_target_list(None)
    self.drag_dest_add_text_targets()

However the source widget (Gtk.TreeView) is not set up as a text source, i.e. there is no calls such as:

   self.drag_source_set_target_list(None)
   self.drag_source_add_text_targets()

The application is nevertheless working fine with some test platforms (X11) but fails on mine (macOS/quartz), as the destination widget always receives an empty SelectionData instance - no text, no raw data, no type.

I traced the issue back to the source SelectionData instance whose set_text() function returns False if no call to drag_source_add_text_targets has not been made prior to set_text().

Any idea why the feature would work on other platforms and not mine?

  • Is the drag_source_add_text_targets() call mandatory - or another way to enable text-based selection data may exist/be sufficient?

  • Has this enforcement been added in a very recent release of PyGTK (from the doc, it seems it has been introduced with v2.6, I’m using gtk v3.24.10), or would it be specific to the GTK backend (X11 vs. Quartz on macOS)?

Thanks,
Emmanuel.

To clarify, are you saying that calling Gtk.Widget.drag_source_add_text_targets() fixed the problem on Quartz?

Assuming I’m looking at the right code, you’re using Gtk.TreeView.enable_model_drag_source() with the targets as Constants.DND_TARGETS, which is:

[('STRING', Gtk.TargetFlags.SAME_APP, 0)]

There is a lot of Quartz-specific code in this area, and that code has native support for 'UTF8_STRING', so I would try changing to that (you ought to be using it anyway). 'STRING' should still work, but it’s possible that it doesn’t, and if _add_text_targets() does fix it, this might explain why. (_add_text_targets() adds 'UTF8_STRING' in addition to 'STRING' and several others.)

Unless you intend to support DnD from multiple sources, it probably makes sense to use the same targets for source and dest. Instead of calling _set_target_list(None) (AFAICT, this call is pointless anyway) and _add_text_targets(), just pass Constants.DND_TARGETS to drag_dest_set() instead of an empty list.

Hi Chris,

Assuming I’m looking at the right code

Yes I think you are (BlockTreeWindow.py as source, DrawingArea.py as destination).

I’m not sure the problem is related to Quartz vs. X11, or if it is some version of (py)GTK that would explain the different behavior. I’d bet on Quartz, but I still need to investigate.

I’m not even sure why Constants.DND_TARGETS is actually needed, as an empty list as used in the pygtk tutorial seems to work as well. I have a too limited knowledge about this topic to understand what is actually required.

just pass Constants.DND_TARGETS to drag_dest_set() instead of an empty list.

Well, it seems this leads to another question:
Constants.DND_TARGETS is defined as a list of tuple, not as a list of Gtk.TargetEntry. When drag_dest_set() is invoked with Constants.DND_TARGETS:

File ".../gnuradio/grc/gui/DrawingArea.py", line 76, in __init__
self.drag_dest_set(Gtk.DestDefaults.ALL, Constants.DND_TARGETS, Gdk.DragAction.COPY)
TypeError: Item 0: argument self: Expected Gtk.TargetEntry, but got tuple

Replacing the list as:

DND_TARGETS = [Gtk.TargetEntry.new('STRING', Gtk.TargetFlags.SAME_APP, 0),
               Gtk.TargetEntry.new('UTF8_STRING', Gtk.TargetFlags.SAME_APP, 1)]

seems to do the job. It is valid to write this?

  • as only text is conveyed through drag n’ drop, is it worth defining DND_TARGETS as the dual string entries (string vs. utf8_string) versus using an empty list and calling drag_source_add_text_targets?

  • Why is enable_model_drag_source accepting a List[Tuple[str, int, int]] as a List[Gtk.TargetEntry], but drag_dest_set does not and enforces the List[Tuple[str, int, int]] type?

Thanks for your help,
Emmanuel.

PyGObject has overrides to allow tuples for the TreeView methods, but not for drag_{source,dest}_set(). You can also pass tuples to _set_target_list(), but it’s perfectly fine to pass explicit Gtk.TargetEntry lists to any of these methods.

In any case, it doesn’t matter how you add targets as long as source and dest have at least one in common. _add_text_targets() seems mainly valuable for the case where you want to accept drags from outside your application that could be in any one of a number of text formats. For internal usage, I think UTF8_STRING alone is sufficient, but add _add_text_targets() should be safe since UTF8_STRING has the highest precedence of the targets it adds. However, I don’t see any way to set Gtk.TargetFlags.SAME_APP with that method.

Ok Chris,

Thanks for these insightful comments.

Emmanuel.