Drag and drop: 'drag-motion' is triggered when GTK window regains focus on KDE Plasma Wayland
Cross posted at https://bugs.kde.org/show_bug.cgi?id=464196 for now until it's clear, if this is a GTK(3) bug or a Plasma Wayland issue.
Steps to reproduce
- Run the demo code below
- Drag and drop a file into the window
- When dragging the file over the window, a label saying '…drop it here' appears.
- After dropping, the label vanishes.
- Click in another window and then into the demo app again OR
- Click on a panel widget (e.g. clipboard, network, ...) to open it and click another time to close it.
Please also see the screen recording: https://bugs.kde.org/attachment.cgi?id=155237
Current behavior
When the demo app regains focus, the 'drag motion' event is triggered and the overlay becomes permanently displayed.
...
Drag Motion: time: 8271120 x: 770 y: 39
Drag Motion: time: 8271136 x: 769 y: 39
Drag Motion: time: 8271163 x: 769 y: 39
Drag Motion: time: 0 x: 769 y: 39
Drag Motion: time: 0 x: 769 y: 39
Interestingly the drop time is in this case always zero and drop position is the same as in step 2 from "Steps to reproduce".
Expected outcome
When the demo app regains focus, the 'drag motion' event is not triggered.
Version information
- GTK Version: 3.24.35
- GLib Version: 2.74.0
- Python 3.11.1
- Operating System: openSUSE Tumbleweed 20230110
- KDE Plasma Version: 5.26.5
- KDE Frameworks Version: 5.101.0
- Qt Version: 5.15.7
- Graphics Platform: Wayland
Demo Code
import gi
gi.require_version("Gtk", "3.0")
gi.require_version('Gdk', '3.0')
from gi.repository import Gdk
from gi.repository import Gtk
TARGET_TYPE_URI_LIST = 80
class MyWindow(Gtk.Window):
def __init__(self):
super().__init__(title="Hello World")
self.set_default_size(800, 600)
self._drop_area = Gtk.Box(
orientation=Gtk.Orientation.VERTICAL, spacing=18)
self._drop_area.set_no_show_all(True)
self._drop_area.add(Gtk.Label(label='…drop it here'))
overlay = Gtk.Overlay()
overlay.add_overlay(self._drop_area)
overlay.connect('drag-data-received', self._on_drag_data_received)
overlay.connect('drag-motion', self._on_drag_motion)
overlay.connect('drag-leave', self._on_drag_leave)
uri_entry = Gtk.TargetEntry.new(
'text/uri-list',
Gtk.TargetFlags.OTHER_APP,
TARGET_TYPE_URI_LIST)
dnd_list = [uri_entry,
Gtk.TargetEntry.new(
'OBJECT_DROP',
Gtk.TargetFlags.SAME_APP,
0)]
dst_targets = Gtk.TargetList.new([uri_entry])
dst_targets.add_text_targets(0)
overlay.drag_dest_set(
Gtk.DestDefaults.ALL,
dnd_list,
Gdk.DragAction.COPY | Gdk.DragAction.MOVE)
overlay.drag_dest_set_target_list(dst_targets)
self.add(overlay)
self.show_all()
def _on_drag_data_received(self,
_widget: Gtk.Widget,
_context: Gdk.DragContext,
_x_coord: int,
_y_coord: int,
selection: Gtk.SelectionData,
target_type: int,
_timestamp: int
) -> None:
pass
def _on_drag_leave(self,
_widget: Gtk.Widget,
_context: Gdk.DragContext,
_time: int
) -> None:
self._drop_area.set_no_show_all(True)
self._drop_area.hide()
def _on_drag_motion(self,
_widget: Gtk.Widget,
_context: Gdk.DragContext,
_x_coord: int,
_y_coord: int,
_time: int
) -> bool:
self._drop_area.set_no_show_all(False)
self._drop_area.show_all()
print(f"Drag Motion: time: {_time} x: {_x_coord} y: {_y_coord}")
return True
win = MyWindow()
Gtk.main()
Edited by A D