ghidra
ghidra copied to clipboard
Graph Viewer shows Context Popup on incorrect (virtual) desktop
Describe the bug
The popup showing the fields of a graph node is displayed on the virtual desktop containing the CodeBrowser Tool main window instead of the virtual desktop containing the graph viewer window.
To Reproduce Steps to reproduce the behavior:
- Run any script resulting in a graph, e.g.
GraphASTScript - Separate the resulting frame into a new window
- Move the window to a separate virtual desktop [0]
- Hover the cursor over a graph node
- Popup disappears in wrong location (specifically nowhere close to the actual cursor or node)
[0] Maybe a separate physical monitor is enough to trigger the bug, but in the i3 window manager those are also always separate virtual desktops
Expected behavior I'd expect the context/info window to be shown on the same monitor that the graph window is opened (and the mouse is located)
Screenshots
Example of the context window rendering correctly:
Demonstration of the bug:
Environment (please complete the following information):
- OS: Arch Linux, specifically with i3 on Xorg
- Java Version: 17.0.9
- Ghidra Version: 10.4, though this bug has always been present in the Graph viewer as far as I remember
- Ghidra Origin: Github
Additional context
The grey rectangles visible in the screenshot are leftovers from previous popups. They overlay anything else on the same virtual desktops and can be dragged around. They only seem to appear after a context popup is shown on a virtual desktop that isn't currently being shown on any monitor, so I suspect this is a bug related to the bug I opened this issue for.
If you have the ability to change our source code, I can offer a snippet for you to try that would help us debug the issue.
Yep, I can fairly easily test out some custom patch.
Great! I'm curios to see if our window placement algorithm is broken for your case. To rule that out, inside of Docking/src/main/java/docking/widgets/PopupWindow.java, inside of the method doShowPopup(), change
popup.setBounds(placement)
(for me at line 285) to be:
Point point = e.getPoint();
popup.setLocation(point);
Thanks, will test this tomorrow morning, it's already fairly late already here in Europe.
This does not seem to fix it, and also seems to break the placement in the case where the graph window is still part of the tool window
I don't think it's the placement itself, the location of the popup typically seems correct relative to the monitor the actual window is open on. I think the problem is that the popup is simply shown on the wrong "virtual desktop" (the i3 term for this being "workspace"). For example, a different variation of this bug also happens in a single monitor setup with i3, if using multiple workspaces:
- if I have the Ghidra CodeBrowser tool open on workspace 4
- but the graph window is open on workspace 1
- both workspaces are assigned to the same physical monitor (this also happens the same way on a single physical monitor setup, no second monitor is necessary to trigger this IIRC)
- if I hover over a node in the graph window while being on workspace 1
- then I will get a window manager alert that a new window opened on workspace 4 and if I switch over there using the keyboard shortcut, the Popup will be there, in exactly right position relative to my (unmoved) mouse cursor.
This is also the source of the other bug with the grey leftover windows: If I hover over a node, wait for the alert that a popup opened on a different workspace, but then move the cursor away again, the alert disappears (indicating that the window closed again already), but there will be one of those empty grey boxes in the position that the popup would have appeared in.
This problem feels vaguely familiar. I think we ran into some other issues relating to focus and virtual desktops.
Do you see this issue for any other detached windows? If this is specific to the graph window, then this should be something we can fix.
Well, I'm sorry for wasting your time, it turns out this was mostly my fault :grimacing: After writing up my theories of why this could happen in a comment here, I suddenly realized that I never technically made sure if the popups always showed up on the same virtual desktop as the CodeBrowser. I just verified that they always open on workspace 4 where my CodeBrowser tool just always to be by default ... because at some point long ago I configured my desktop environment to move Ghidra windows to workspace 4 on creation... If I move the CodeBrowser to workspace 1 (so that workspace 4 is entirely empty) popups will still appear on workspace 4...
This means the underlying issue is that Ghidra popups are created in some way that a desktop environment like i3 treats as a new window and then any rules get applied to this (like moving them to a specific workspace...). This does not happen with other tools like e.g. IntelliJ (for which I have the same kind of rule, just for a different workspace number). Even if I move IntelliJ/PyCharm/etc to a different workspace than the rule configured one, the popup still shows on the same workspace as the window.
I just double checked this with xprop, the IntelliJ popups have the same window class set as the main window, which is the property I'm matching for the window assignment. This means that IntelliJ is somehow creating the window in a way that doesn't trigger these rules.
The xprop result for the IntelliJ popup is:
_NET_WM_USER_TIME(CARDINAL) = 0
_NET_WM_WINDOW_TYPE(ATOM) = _NET_WM_WINDOW_TYPE_DIALOG
_MOTIF_DRAG_RECEIVER_INFO(_MOTIF_DRAG_RECEIVER_INFO) = 0x6c, 0x0, 0x5, 0x0, 0x63, 0x32, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0
XdndAware(ATOM) = BITMAP
_NET_WM_STATE(ATOM) = _NET_WM_STATE_SKIP_TASKBAR
WM_HINTS(WM_HINTS):
Client accepts input or input focus: False
window id # of group leader: 0x300004c
WM_TRANSIENT_FOR(WINDOW): window id # 0x300004c
_NET_WM_PID(CARDINAL) = 84154
WM_CLIENT_MACHINE(STRING) = "monolith"
WM_PROTOCOLS(ATOM): protocols
_MOTIF_WM_HINTS(_MOTIF_WM_HINTS) = 0x3, 0x0, 0x0, 0x0, 0x0
WM_NORMAL_HINTS(WM_SIZE_HINTS):
program specified location: 2969, 1584
program specified size: 864 by 168
window gravity: NorthWest
WM_CLASS(STRING) = "jetbrains-idea", "jetbrains-idea"
WM_CLIENT_LEADER(WINDOW): window id # 0x3000030
_NET_WM_NAME(UTF8_STRING) = "win47"
WM_NAME(STRING) = "win47"
and for the Ghidra popup:
_NET_WM_DESKTOP(CARDINAL) = 4
WM_STATE(WM_STATE):
window state: Normal
icon window: 0x0
I3_FLOATING_WINDOW(CARDINAL) = 1
_NET_WM_WINDOW_TYPE(ATOM) = _NET_WM_WINDOW_TYPE_DIALOG
_NET_WM_STATE(ATOM) = _NET_WM_STATE_SKIP_TASKBAR, _NET_WM_STATE_FOCUSED
WM_HINTS(WM_HINTS):
Client accepts input or input focus: False
window id # of group leader: 0x4c00095
WM_TRANSIENT_FOR(WINDOW): window id # 0x4c00095
_NET_WM_PID(CARDINAL) = 335976
WM_CLIENT_MACHINE(STRING) = "monolith"
WM_PROTOCOLS(ATOM): protocols
_MOTIF_WM_HINTS(_MOTIF_WM_HINTS) = 0x3, 0x0, 0x0, 0x0, 0x0
WM_NORMAL_HINTS(WM_SIZE_HINTS):
program specified location: 3856, 1749
program specified size: 227 by 205
window gravity: NorthWest
WM_CLASS(STRING) = "java-lang-Thread", "java-lang-Thread"
WM_CLIENT_LEADER(WINDOW): window id # 0x4c00008
_NET_WM_NAME(UTF8_STRING) = "win57"
WM_NAME(STRING) = "win57"
I don't know which detail makes the difference for i3 here so that the assign rule doesn't get applied to the IntelliJ popup,
If you consider it relevant, we can still treat this as an issue that the Ghidra popups are somehow not treated the same as other popups in some desktop environments, leading to obscure edge cases like mine.
Thanks for the detailed information. I don't have any strong opinions on this behavior, since this is not something I use. It's not clear from this info whether any unexpected behavior is caused by Ghidra or is related to how the JVM/Swing manage windows.
A quick check of the Swing docs yields a dedicated Popup class, which Ghidra doesn't seem to use. Ghidra's PopupWindow instead creates a JWindow internally:
https://github.com/NationalSecurityAgency/ghidra/blob/7c9aa58aaf92c98842ade725113aa9e49a76d9f4/Ghidra/Framework/Docking/src/main/java/docking/widgets/PopupWindow.java#L103-L112
Do you know anything about why the Swing Popup wasn't used here? My hypothesis is that the Swing Popup handles these kinds of edge cases around window management correctly, but I have not confirmed this yet.
Do you know anything about why the Swing Popup wasn't used here?
Our popup window is more complicated, adding custom widgets inside of the popup, such as a preview interactive Listing for references.
Now that you mention this, I may have taken you in the wrong direction earlier. I believe the popup context menu you showed in your example is not our PopupWindow class being used. Our popup window is essentially a new window top-level Java window. The context menu is Swing's JPopupMenu menu class.
I'm getting a bit confused about the terminology here, and it seems to matter because different things that could be called "popup" or "context menu" behave differently: There is something crucially different about the window being opened if I right click something vs if I hover over specific items. Some windows that are being created by hovering are moved to workspace 4, while the context menus created by right clicking stay on the same workspace they were being triggered.
I was about to write "all windows that are being created by hovering" but then I double checked on it's not all windows created by hovering over something:
Affected (matched by the rule in my DE config and being moved):
- Addresses in the Listing Window
- static strings in the Decompiler window
- graph node popups
Unaffected:
- Items in the Datatype Manager
- Items in the Symbol Tree
- any kind of help text shown if hovering over menu bar icons
I'm getting a bit confused about the terminology here, and it seems to matter because different things that could be called "popup" or "context menu" behave differently:
This can certainly be confusing. Your clarifications are helpful. Most if not all hovers in the Listing, Function Graph and Decompiler will use Ghidra's PopupWindow class. This is the way we show custom popups for more complicated use cases. The Data Type Manager, the Symbol Tree, Ghidra toolbar buttons and most Java widgets will use Java's JToolTip class to show context-specific hover information.
The JPopupMenu is used specifically when right-clicking.
Based on what you mentioned most recently, it appears as though our PopupWindow is misbehaving. Does the right-click popup menu work as expected?
Yes, all right-click Popup menus I have encountered or deliberately tested have behaved correctly.