Yet another attempt at correct global mouse popup behavior

This commit is contained in:
dragonmacher 2025-05-14 19:08:37 -04:00
parent 717cb2a0ce
commit 4eced86c09

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -21,9 +21,10 @@ import java.awt.event.*;
import javax.swing.*;
import org.apache.commons.lang3.ArrayUtils;
import docking.action.DockingActionIf;
import ghidra.util.CascadedDropTarget;
import ghidra.util.HelpLocation;
import ghidra.util.*;
import help.HelpService;
/**
@ -150,6 +151,10 @@ public class DockableComponent extends JPanel implements ContainerListener {
return;
}
if (!e.isPopupTrigger()) {
return;
}
Component component = e.getComponent();
if (component == null) {
return; // not sure this can happen
@ -162,11 +167,31 @@ public class DockableComponent extends JPanel implements ContainerListener {
}
Point point = e.getPoint();
boolean withinBounds = bounds.contains(point);
if (e.isPopupTrigger() && withinBounds) {
if (!bounds.contains(point)) {
return;
}
//
// Consume the event so that Java UI listeners do not process it. This fixes issues with
// UI classes (e.g., listeners change table selection). We want to run this code later to
// allow trailing application mouse listeners to have a chance to update the context. If
// the delayed nature causes any timing issues, then we will need a more robust way of
// registering mouse listeners to work around this issue.
//
e.consume();
Swing.runLater(() -> {
MenuSelectionManager msm = MenuSelectionManager.defaultManager();
MenuElement[] selectedPath = msm.getSelectedPath();
if (!ArrayUtils.isEmpty(selectedPath)) {
// This means that a menu is open. This can happen if a mouse listener further down
// the listener list has shown a popup. In that case, do not show the context menu.
return;
}
PopupMenuContext popupContext = new PopupMenuContext(e);
actionMgr.showPopupMenu(placeholder, popupContext);
}
});
}
@Override
@ -328,8 +353,27 @@ public class DockableComponent extends JPanel implements ContainerListener {
}
if (comp.isFocusable()) {
comp.removeMouseListener(popupListener);
comp.addMouseListener(popupListener);
installPopupListenerFirst(comp);
}
}
/**
* Remove and re-add all mouse listeners so our popup listener can go first. This allows our
* popup listener to consume the event, preventing Java UI listeners from changing the table
* selection when the user is performing a Ctrl-Mouse click on the Mac.
*
* @param comp the component
*/
private void installPopupListenerFirst(Component comp) {
comp.removeMouseListener(popupListener);
MouseListener[] listeners = comp.getMouseListeners();
for (MouseListener l : listeners) {
comp.removeMouseListener(l);
}
comp.addMouseListener(popupListener);
for (MouseListener l : listeners) {
comp.addMouseListener(l);
}
}