on_drag event in Canvas not triggered when Num Lock is active (Ubuntu 24.04)
Closed this issue · 6 comments
Describe the bug
In the example https://github.com/beeware/toga/blob/main/examples/canvas/canvas/app.py the, the on_drag event is never triggered if Num Lock is on. It seems to work normally when Num Lock is off.
Steps to reproduce
- Run the example https://github.com/beeware/toga/blob/main/examples/canvas/canvas/app.py with Num Lock off
- Try to drag the text
- Switch on Num Lock
- Try to drag the text
To make it easier, I slightly changed the code to print "on_press", "on_release", "on_drag" when entering in the corresponding methods. I also added a print of the Num Lock status within the on_press method. I attached the corresponding code here.
Expected behavior
It will be impossible to drag the text when Num Lock is on, while Num Lock on/off should not affect the on_drag event.
Screenshots
Environment
- Operating System: 24.04.2 LTS (Noble Numbat)
- Python version: 3.12.3
- Software versions:
- Briefcase: 0.3.24
- toga-core: 0.5.2
- toga-gtk: 0.5.2
Logs
Additional context
No response
Thanks for the report.
It appears that this is being cause because numlock is being treated as a modifier key by GTK. The on-drag (and on-alt-drag) handlers in GTK's Canvas implementation are currently looking for unmodified drag events (i.e., event.state == Gdk.ModifierType.BUTTON1_MASK); if these are modified to look for a mask (i.e., `event.state | Gdk.ModifierType.BUTTON1_MASK), then the numlock won't alter detection of the mouse event.
For bonus points, the mouse press/move events could be extended to also include keyboard modifier - however, that would be a feature addition that would also need modifications on other platforms.
Hi, thank you for your quick answer.
Are you willing to change the current implementation to fix this? Otherwise, the simpliest/temporary solution is probably to mention this somewhere in the documentation.
However, I'm a little bit confused because I'm not familiar with this, and I'm not sure if I understand that correctlty:
If event.state and Gdk.ModifierType.BUTTON1_MASK are binary strings. Then, event.state | Gdk.ModifierType.BUTTON1_MASK will always be True, even when event.state has no bits set to 1? So, you would use & instead of |, to make the statement True only if event.state == Gdk.ModifierType.BUTTON1_MASK | something_else (where something_else is not the alt thing)?
Are you willing to change the current implementation to fix this? Otherwise, the simpliest/temporary solution is probably to mention this somewhere in the documentation.
Yes - this is clearly a bug, which is why I've invited you to submit a fix for the bug.
However, I'm a little bit confused because I'm not familiar with this, and I'm not sure if I understand that correctlty: If event.state and Gdk.ModifierType.BUTTON1_MASK are binary strings. Then,
event.state | Gdk.ModifierType.BUTTON1_MASKwill always be True, even whenevent.statehas no bits set to 1? So, you would use&instead of|, to make the statement True only ifevent.state == Gdk.ModifierType.BUTTON1_MASK | something_else(wheresomething_elseis not the alt thing)?
My apologies - I shouldn't answer questions before my morning coffee has taken effect :-) You're completely correct - & is the operator needed here.
Okay, I'll try to do a PR to fix that in the next few days.
Hi @freakboy3742,
I prepared the PR, however, running the tests on the main branch with tox was leading to an error:
coverageplatform: FAIL code error: Multiple top-level packages discovered in a flat-layout: ['web', 'gtk', 'iOS', 'toga', 'core', 'demo', 'dummy', 'cocoa', 'changes', 'testbed', 'android', 'textual', 'winforms', 'positron', 'travertino']..
I don't really know why this is happening as I simply followed https://toga.readthedocs.io/en/stable/how-to/contribute/code.html and had the failure when arriving at the tests. Any tip to fix that before making the PR?
@Ydrnan Thanks for letting us know - looks like a recent refactor of our tox configuration has a 1 character bug that slipped through testing (the final target on line 2 of tox.ini should read coverage{,-trav}-platform, not coverage{,-trav}platform).
The fix for this is in #3670; in the meantime, you can use:
tox -m test
to run the test suite and get a coverage report. This tox target will only run on 1 python version, rather than on every python version - but that's more than enough for local testing in almost every case, and is a lot faster as well.