Opened 3 years ago

Closed 3 years ago

#9068 closed defect (fixed)

qtconsole receives QContextMenuEvents when volume data context menu used

Reported by: Zach Pearson Owned by: Tom Goddard
Priority: low Milestone:
Component: UI Version:
Keywords: Cc: Eric Pettersen
Blocked By: Blocking:
Notify when closed: Platform: all
Project: ChimeraX

Description

To reproduce:

Open one of the RIDER Lung CTs (I used series 8), right click the volume menu, enable the bounding box, then try to launch the shell from the command line with "ui tool show shell<enter>" -- this can either be a remembered command or one you typed.

Does not reproduce when using the ribbon to turn on the bounding box, or the Tool menu to launch the shell.

Change History (8)

comment:1 by Eric Pettersen, 3 years ago

Cc: Eric Pettersen added
Owner: set to Tom Goddard
Status: newassigned
Summary: qtconsole receives QContextMenuEvents when bounding box enabledqtconsole receives QContextMenuEvents when volume data context menu used

This happens only when using the context menu obtained by right-clicking over the volume histogram (including simply dismissing that menu by clicking outside it), followed by bringing up the Python shell by any means. It does not happen by using the normal context menu for a tool (including Volume Viewer's own "normal" context menu), so whatever code produces the volume-data context menu somehow causes this. Perhaps that code needs to use session.ui.post_context_menu()?

comment:2 by Tom Goddard, 3 years ago

It is useful to include the error in a bug report. Mousing over the shell after using the Volume Viewer histogram context menu produces a stream of this traceback.

Traceback (most recent call last):
  File "/Users/goddard/ucsf/chimerax/ChimeraX.app/Contents/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/qtconsole/console_widget.py", line 482, in eventFilter
    pos = event.globalPosition().toPoint()
AttributeError: 'QContextMenuEvent' object has no attribute 'globalPosition'

AttributeError: 'QContextMenuEvent' object has no attribute 'globalPosition'

File "/Users/goddard/ucsf/chimerax/ChimeraX.app/Contents/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/qtconsole/console_widget.py", line 482, in eventFilter
pos = event.globalPosition().toPoint()

comment:3 by Tom Goddard, 3 years ago

This seems like a Qt or PyQt bug. The qtconsole shell code gets a QContextMenuEvent e that has e.type() == QEvent.MouseMove. Such an event is supposed to have e.type() == QEvent.ContextMenu. Every mouse move in the shell window triggers this error.

To generate the error it only requires posting the Volume Viewer histogram context menu, and then clicking outside the menu to dismiss it. It does not require clicking any menu entry.

The volume viewer code that creates the menu creates callbacks which reference the event that posted the memory. I changed the code so it does not keep any reference to the posting event and then the error does not happen when the menu is simply posted. But it still happens when the "Show outline box" menu entry is clicked!

I changed posting the menu so it uses the same call (ui.post_context_menu()) used by all our Tool context menus. That made no difference. That code cast menu.exec() which starts some event subloop processing that does not return until the menu is unposted.

Commenting out the callback (action.triggered.connect(cb)) line for the 4 volume menu entries avoids the problem even if the menu entries are used. Or if I still connect the callbacks but have then simply return, there is no problem. If I put a try/except around the callbacks so they raise no error I still get the problem.

Commenting out just the logging of the command in the show outline box menu callback avoids the error.

It could be a reference count problem. I tried keeping the QActions alive and the callbacks, still get the error.

The histogram has its own context menu. If I instead make it the tool context menu get the same problem.

I'm baffled. The other tool context menus tend to do simpler things in their callbacks. On the other hand, it doesn't even require clicking any of the menu entries in the original code if the callbacks simply hold onto a reference to the post event. The same error occurs even if the callbacks are never called!

comment:4 by Tom Goddard, 3 years ago

This bug happens in ChimeraX 1.6.1 on Mac. It only requires posting the Volume Viewer histogram context menu, then clicking outside the menu to dismiss it, then click in the shell window. If I simply comment out registering the menu entry callbacks (line action.trigger.connect(cb)), then the error no longer happens. So even though the callbacks are never called, merely registering them leads to the error. This suggests it is an object lifetime problem. The callbacks do hold a reference to the posting QEvent instance and tests show that alone will cause this error. That seems like a PyQt bug that holding a reference to the posting event would cause later errors in the shell.

comment:5 by Tom Goddard, 3 years ago

My best guess is that this PyQt/Qt bug happens when the posting QEvent is kept alive too long. There is no call to delete a QEvent in Qt. (QEvent.accept() did not fix anything.) It seems that even the somewhat more complicated callbacks of the volume histogram code which might generate more Qt events somehow keep the event alive triggering the bug. Maybe setting the event = None before posting the menu would delete it and avoid the bug. Yes, that worked.

ChimeraX 1.5 and 1.4 have the same bug. ChimeraX 1.3 which used Qt 5 does not have the bug.

comment:6 by Eric Pettersen, 3 years ago

Seems not too hard to work around though. Three of the callbacks hold a reference to the event. One doesn't even use it. The other two could be passed the event's xy coordinates instead of the event instance itself.

comment:7 by Tom Goddard, 3 years ago

I made your suggested change at the start of my debugging and it does not solve the problem. But doing that and setting "event = None" before posting the menu so the code does not hold onto any reference to the event at the time the menu gets posted works around it. So that is what I am going with. Already wasted 3 hours. I am not a fan of Qt/PyQt.

comment:8 by Tom Goddard, 3 years ago

Resolution: fixed
Status: assignedclosed

Fixed.

Worked around the Qt/PyQt bug by removing all references to the posting QEvent instance before posting the menu.

Note: See TracTickets for help on using tickets.