Ticket UUID: | 855ec435ef50de090e6eea98f6ff829d7faed7ce | |||
Title: | BWidget Drag & Drop no longer works with Tk 9.1a0 on Aqua | |||
Type: | Bug | Version: | trunk | |
Submitter: | nemethi | Created on: | 2025-04-06 11:26:45 | |
Subsystem: | 66. Aqua Window Operations | Assigned To: | marc_culler | |
Priority: | 5 Medium | Severity: | Important | |
Status: | Closed | Last Modified: | 2025-04-11 17:30:21 | |
Resolution: | Fixed | Closed By: | nemethi | |
Closed on: | 2025-04-11 17:30:21 | |||
Description: |
The attached simple script uses the Drag & Drop functionality of BWidget. It works as expected with all Tk releases, including 9.0.0 and 9.0.1. However, if Tk built from the current trunk is being used on Aqua then after a drag operation the left mouse button gets insensitive: neither a second drag, nor a click into the listbox has any effect. This holds true regardless of whether the drag was terminated by a drop into the listbox widget (registered as drop target) or by releasing the mouse button outside the listbox. After clicking anywhere outside the GUI and then on the GUI itself, the mouse works again as expected, but only until repeating the drag. For the test with Tcl/Tk 9 one needs the most recent BWidget version 1.10.1, which can be downloaded from https://sourceforge.net/projects/tcllib/files/BWidget/1.10.1 | |||
User Comments: |
nemethi (claiming to be Csaba Nemethi) added on 2025-04-11 17:30:21:
Yes, only macOS is affected by this issue. marc_culler (claiming to be Marc Culler) added on 2025-04-11 17:22:47: Thanks, Csaba. > BTW: I have just found out that the issue regarding the insensitivity > of the mouse after a drag with TkDND was introduced in Tk 8.6.13. That was a while ago. Do you know if it is only macOS that is affected? I think I will treat that as a different problem, and close this ticket. nemethi (claiming to be Csaba Nemethi) added on 2025-04-11 16:56:48: Many thanks Marc, the test script with BWidget still works as expected for me, too. The test script witk TkDND behaves exactly as before. BTW: I have just found out that the issue regarding the insensitivity of the mouse after a drag with TkDND was introduced in Tk 8.6.13. marc_culler (claiming to be Marc Culler) added on 2025-04-11 16:05:21: I moved the code which updates the TkEventTarget into the NSApp method windowActivation, which gets called whenever an NSWindow accepts or rejects the role of keyWindow. I think that will be more robust, because any call to [NSWindow makeKeyAndOrderFront] will result in a correct assignment of the current TkEventTarget. The test script still works for me. Csaba, if you have a moment to test the new tip of the bugfix branch it would be appreciated. Thanks. marc_culler (claiming to be Marc Culler) added on 2025-04-11 13:00:35: Thanks, Csaba. The code that was involved here was trying to reassign focus to the top remaining window when a window is destroyed. The window being destroyed is thr small window containing a drag icon. It gets destroyed on the drop. The code was resetting the macOS KeyWindow, but it was not correctly notifying Tk that a new Tk window should receive the focus. It is not sufficient to call [NSWindow makeKeyAndOrderFront], it seems. I don't understand why not. There is a callback that Apple calls when a new window becomes the KeyWindow. It should handle that job. So I think I need to investigate a little further and see if I can make the fix more robust. Maybe that will fix tkdnd as well. I think it is a similar issue, just at the C level. nemethi (claiming to be Csaba Nemethi) added on 2025-04-11 09:38:48: Many thanks Marc, your bugfix works for me like a charm! One more detail regarding the similar issue with TkDND (i.e., that after a terminated drag one must click somewhere on the GUI to make the mouse sensitive again): This problem is much older than Tk 9.1a0. It was already present in Tk 9.0.0, possibly even in earlier Tk versions. marc_culler (claiming to be Marc Culler) added on 2025-04-10 21:18:19: The BWidget issue seems to be fixed in the new bugfix branch bug-855ec435ef. The tkdnd issue is not fixed in that branch. In spite of having very similar (but not quite identical) symptoms these must be two different problems. The bug appeared in commit [d9df72b3], the first commit to the branch aqua_key_window on 2025-03-12. Would you please test the bugfix branch? Thanks. nemethi (claiming to be Csaba Nemethi) added on 2025-04-10 17:11:36: Yet another remark: It is true that after a terminated drag the mouse becomes insensitive not only with BWidget, but also with TkDND. OTOH, the way to make it work again, is not exactly the same: With BWidget the user has to click somwhere outside the GUI and then on the GUI itself. With TkDND it is sufficient to click on the GUI (w/o having first klicked somewhere outside it). marc_culler (claiming to be Marc Culler) added on 2025-04-10 17:05:06: Well, I didn't quite do what I said. I couldn't abandon the TkDND issue so fast. I can now confirm that Nicolas' TkDndTest.tcl script can be fixed (.i.e. that the indicator is shown correctly during the drag operation) by simply adding a call to update idletasks at the ends of the procs onDropEnterOrPos and onDropLeave. I definitely am not interested in adding an expensive inner event loop inside of updateLayer to solve a problem that is easily fixed by calling update idletasks, which is equivalent to running the inner event loop: while(Tcl_DoOneEvent(TCL_IDLE_EVENTS)){} It is a fact of life that sometimes it is necessary to call update or update idletasks to make Tk behave as expected. This is just one of those times. I will move on to the BWidgets issue (which is also arising with the TkDndTest.tcl script and probably has the same cause). I will start as usual by doing bisection to find which commit first showed the problem. Csaba says it was after the release of 9.0.1. nemethi (claiming to be Csaba Nemethi) added on 2025-04-10 16:52:06:
The "target indicator" is just a way ("invented" by me) to indicate where the drop will insert the dragged data. The fact that no insertion after the last listbox element takes place is due exclusively to the simplicity of the test script and has nothing to do with TkDND. With some additional code, the test script could also append the data to the listbox rather than insert it before the last element. The test script works as you observed mainly because it uses the marc_culler (claiming to be Marc Culler) added on 2025-04-10 16:30:55: I have another question unrelated to event loops and the like. When I run the tkdnd test script it is not possible to insert an item at the end of the list. When the event loop is re-enabled, and the indicator is drawn, it never gets drawn after the last element, and doing the drop below the last line in the listbox inserts the item in the second-to-last position not at the end. QUESTION: Is this expected behavior from tkdnd? Why? marc_culler (claiming to be Marc Culler) added on 2025-04-10 16:26:41: I can confirm that adding the event loop does make the indicator appear as expected with the tkdnd demo script. I suspect that the best way to fix this would be for tkdnd to run its own event loop, rather than expecting Tk to do it. So far there are 0 known cases where the event loop is needed for the Tk core and 1 case where one particular extension needs it. Having the extension provide its own event loop seems like a better alternative than slowing down the updateLayer method for every drawing operation in the Tk core, whether or not that extension is in use. I see that one idle task gets processed by the loop, presumably the display proc for the indicator. So another fix might involve adding a call to update idletasks at an appropriate place in the listbox tcl code. I will look into this. But first I will focus on the BWidget issue and see if I can figure out what is going on there. I don't think it is a coincidence that the exact same problem with the mouse button occurs for the pure tcl BWidget script and for the pure C tkdnd implementation. Surely the two identical problems in those two wildly different contexts have the same underlying cause. (And restoring the inner event loop does not fix the problem that the second drag-and-drop action ignores the mouse drag.) marc_culler (claiming to be Marc Culler) added on 2025-04-10 15:57:43: I'd like to explain why I am reluctant to restore the inner event loop, i.e the call: while(Tcl_DoOneEvent(TCL_IDLE_EVENTS)){} which is involved in the change that Nicolas suggests. That event loop was running inside the updateLayer method, which is the method that swaps the NSView CGImage backing store with one which has the latest drawing operations rendered. The number of calls to updateLayer is huge. That method needs to be as efficient as possible. Transferring control to the Tcl event loop to process an arbitrary number of idle tasks every time that updateLayer is called is pretty far from efficient. It was clear that the event loop needed to run when a window was first opened, but otherwise I could find no evidence that it was ever needed. It has been gone for quite a while, and this subtle issue with tkdnd is the first indication of any bad side effect from making updateLayer more efficient. Rather than restore the extra event loop to run for every call to updateLayer, I would prefer to understand why this is happening. Blindly inserting event loops here and there whenever there is a small graphics issue is not a good way of doing things. nemethi (claiming to be Csaba Nemethi) added on 2025-04-10 15:16:18: This ticket in about a behavior related to Drag & Drop via BWidget: After a terminated drag the left mouse button becomes insensitive. This happens only with the current trunk version of Tk. I have tested that the attached sample script works as expected with Tk 9.0.0 and 9.0.1, but behaves as described above with the current trunk. All the 3 tests were run on macOs Sequoia 15.3.2, which seems to contradict your assumption that the issue might be related to an OS change. The other problem, reported to you by Nicolas in a private mail, is related to Drag & Drop via TkDND: During a drag the target indicator remains invisible. The target indicator is a thin frame place'd before the nearest item of the tablelist widget registered as drop target, or before the nearest element of the listbox registered as drop target. AFAIK, Nicolas has forwarded to you a test script involving tablelist widgets and later a very simple one independent from Tablelist. I suggest you to take a closer look at the second test script, because it is really quite simple and will help you understand what he target indicator is. With Tk 9.0.0 and 9.0.1 the target indicator is displayed as expected, but with the current trunk version it remains invisible. The change proposed by Nicolas fixes this issue. nab added on 2025-04-10 14:57:21: Hi Marc, here I'm running macOS15 with the latest script I sent you (TkDndTest.tcl), when you click on drag source, maintain the click and drag to the listbox, you should see a line that indicate where insertion will occur. this is the 'target indicator' with Tk's code as it is you don't see it. with change in tkMacOSXWindowEvent.c, you can see it ++ marc_culler (claiming to be Marc Culler) added on 2025-04-10 14:03:22: Well, restoring a hack which should never have been necessary is not exactly what I think of as a solution. And I am not sure it works. But I would like to understand both examples. I need some help. They both seem to show the same behavior to me. Can you explain to me what the "target indicator" is? In both cases I see when I similar behavior when I "instrument" the code. It has to do with an aspect of mouse events which has always been tricky. Namely, when a mouse drag occurs Apple does not send the equivalent of a motion event with an indication that a mouse button is pressed. Instead they send an NSLeftMouseDragged event if the mouse motion is done while the left button is pressed and an NSMousedMoved event if the mouse is moved without the button being pressed. It is up to Tk to track the information about which buttons are pressed. That would be easy if Apple sent, say, an NSLeftMouseDown event when the left mouse button is pressed and an NSLeftMouseUp event when the left mouse button is released. But they don't. At least no consistently. The XXXMouseDown and XXXMouseUp events are not paired in the way that you would expect. Often the XXXMouseUp is not sent and Tk must somehow deduce that the mouse button was released from the event stream. This is why I said it might be related to an OS change. For that reason it would be helpful to know which OS version people are using when they see these glitches. nemethi (claiming to be Csaba Nemethi) added on 2025-04-10 09:00:02:
As mentioneed by Harald, this ticket is about the Drag & Drop functionality of BWidget. The two test scripts that I sent to Nicolas are about a different issue, namely that the target indicator is not visible when running TkDND with Tk built from trunk (and Nicolas seems to have found the place in tkMacOSXWindowEvent.c which causes that problem). marc_culler (claiming to be Marc Culler) added on 2025-04-09 23:38:59: The fact that two completely different dnd implementations fail the same way is a big hint suggesting that there is a simple explanation. (E.g. the Tk button state is not being maintained correctly, causing Tk to think that the mouse button is still pressed after it is released.) marc_culler (claiming to be Marc Culler) added on 2025-04-09 21:10:43: I have a different test script, from Nicolas Bats via Csaba, which does not require BWidgets to demonstrate the problem. oehhar added on 2025-04-09 19:01:06: Thanks, Marc, great that you look into this. Just for the wording: Csaba reports about bwidgets, not tkdnd. Those are two distinct extensions. TkDnD is a C extension interfacing with sources/targets outside of Tk. BWidget only handles DnD within Tk widgets. Harald marc_culler (claiming to be Marc Culler) added on 2025-04-09 18:44:23: This appears to be a bug in tkdnd. I suspect that tkdnd is designed to steal all NSLeftMouseDragged events during a DND operation, and not pass them on to Tk. Perhaps they are setting up their own modal event loop to handle those events. When tkdnd appears to be working correctly, Tk only receives about 5 NSLeftMouseDragged events, even during a very long drag. (There should be one of those events generated each time that the mouse moves during the drag.) When tkdnd is misbehaving on the second DND operation, Tk receives all of the NSLeftMouseDragged events. This probably means that tkdnd does not see any of those events and so it doesn't know when the drag started or when the drop happened. Perhaps tkdnd is not able to start its private modal event loop on the second DND because it did not correctly terminate the previous loop when the drop happened. It is possible that there was a change in macOS which caused this to stop working. nemethi (claiming to be [email protected]) added on 2025-04-07 15:30:59: Unfortunately, I cannot tell you which commit introduced the issue, because it has been just a few days ago that after several years I tested the Drag & Drop again. marc_culler (claiming to be Marc Culler) added on 2025-04-07 14:52:23: Thanks Csaba. I see the issue. I am investigating. Do you happen to know which commit first showed this issue? |
Attachments:
- BWidgetDnd.tcl [download] added by nemethi on 2025-04-06 11:27:45. [details]