Prevent drop to first row of TreeView

I am trying to prevent drops to the first line of a treeview. My code is basically working, but I would like for the drag icon to change when I move over the first line to indicate that a drop is not permitted there. I set action to “0 to indicate that a drop will not be accepted” (as per documentation), but that setting does not affect the icon. Any suggestions?

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk

class DragWindow(Gtk.Window):
    def __init__(self):
        super().__init__()
        self.set_default_size(300, 200)
        self.connect('destroy', Gtk.main_quit)

        hbox = Gtk.Box()
        hbox.set_orientation(Gtk.Orientation.HORIZONTAL)

        button = Gtk.Button.new_with_label('Label')
        hbox.pack_start(button, False, False, 0)

        model = Gtk.ListStore.new([str])
        treeview = Gtk.TreeView.new_with_model(model)
        model.append(('row 1',))
        model.append(('row 2',))

        label = Gtk.Label.new('drop in this column')
        label.show()

        renderer = Gtk.CellRendererText()
        renderer.set_alignment(0.5, 0.5)

        col = Gtk.TreeViewColumn('', renderer, text=0)
        col.set_widget(label)
        col.set_alignment(0.5)
        treeview.append_column(col)

        hbox.pack_end(treeview, True, True, 0)
        self.add(hbox)
        self.show_all()

        button.drag_source_set(
                Gdk.ModifierType.BUTTON1_MASK,
                [Gtk.TargetEntry.new('button', Gtk.TargetFlags.SAME_APP, 0)],
                Gdk.DragAction.COPY)
        treeview.enable_model_drag_dest(
                [Gtk.TargetEntry.new('button', Gtk.TargetFlags.SAME_APP, 0)],
                Gdk.DragAction.COPY)

        treeview.connect('drag-data-received', self.on_drag_data_received)
        treeview.connect('drag-motion', self.on_drag_motion)

    def on_drag_motion(self, treeview, context, x, y, time):
        dest_row = treeview.get_dest_row_at_pos(x, y)
        if dest_row is not None:
            path, position = dest_row
            if path == Gtk.TreePath.new_first() \
                    and position != Gtk.TreeViewDropPosition.AFTER:
                print('invalid position')
                Gdk.drag_status(context, 0, time)
                return False
            else:
                print('valid position')
                Gdk.drag_status(context, Gdk.DragAction.COPY, time)
                return True
        else:
            print('not in treeview')
            Gdk.drag_status(context, Gdk.DragAction.COPY, time)
            return True

    def on_drag_data_received(self, treeview, context, x, y, data, info, time):
        selection = treeview.get_selection()
        model = treeview.get_model()
        new_row = ('data',)
        dest_row = treeview.get_dest_row_at_pos(x, y)
        if dest_row is not None:
            path, position = dest_row
            if path == Gtk.TreePath.new_first() \
                    and position != Gtk.TreeViewDropPosition.AFTER:
                return

            dest_iter = model.get_iter(path)
            if position == Gtk.TreeViewDropPosition.BEFORE:
                drop_iter = model.insert_before(dest_iter, new_row)
            else:
                drop_iter = model.insert_after(dest_iter, new_row)
        else:
            drop_iter = model.append(new_row)

        selection.select_iter(drop_iter)


dragwindow = DragWindow()
Gtk.main()

I found playqueue_treeview.set_drag_dest_row(path, position). It highlights the row of the current drop position. Documentation says that I should set path to None to remove the highlight. Unfortunately, the row below the drag remains highlighted. Is this feature broken, or am I doing something wrong?

One other question: When I reject a drop to the first position, how do I trigger the animation for an unsuccessful drop? context.finish(False, False, time) does not do it.

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