Merge remote-tracking branch 'origin/GP-1-dragonmacher-mouse-listener-fix--SQUASHED' into Ghidra_11.4

This commit is contained in:
Ryan Kurtz 2025-05-13 07:54:00 -04:00
commit 04bb0fa5a7

View file

@ -18,12 +18,15 @@ package docking;
import java.awt.*; import java.awt.*;
import java.awt.dnd.*; import java.awt.dnd.*;
import java.awt.event.*; import java.awt.event.*;
import java.util.List;
import javax.swing.*; import javax.swing.*;
import docking.action.DockingActionIf; import docking.action.DockingActionIf;
import ghidra.util.*; import ghidra.util.CascadedDropTarget;
import ghidra.util.HelpLocation;
import help.HelpService; import help.HelpService;
import util.CollectionUtils;
/** /**
* Wrapper class for user components. Adds the title, local toolbar and provides the drag target * Wrapper class for user components. Adds the title, local toolbar and provides the drag target
@ -169,18 +172,9 @@ public class DockableComponent extends JPanel implements ContainerListener {
return; 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(); e.consume();
Swing.runLater(() -> {
PopupMenuContext popupContext = new PopupMenuContext(e); PopupMenuContext popupContext = new PopupMenuContext(e);
actionMgr.showPopupMenu(placeholder, popupContext); actionMgr.showPopupMenu(placeholder, popupContext);
});
} }
@Override @Override
@ -342,30 +336,46 @@ public class DockableComponent extends JPanel implements ContainerListener {
} }
if (comp.isFocusable()) { if (comp.isFocusable()) {
installPopupListenerFirst(comp); installPopupListener(comp);
} }
} }
/** /**
* Remove and re-add all mouse listeners so our popup listener can go first. This allows our * Remove, reorder and re-add all mouse listeners so Java listeners go last. This allows our
* popup listener to consume the event, preventing Java UI listeners from changing the table * 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. * selection when the user is performing a Ctrl-Mouse click on the Mac.
* *
* @param comp the component * @param comp the component
*/ */
private void installPopupListenerFirst(Component comp) { private void installPopupListener(Component comp) {
comp.removeMouseListener(popupListener);
MouseListener[] listeners = comp.getMouseListeners(); // remove and add the listeners according to the sorted order so that will be installed as
// they are ordered in the list
List<MouseListener> listeners = createOrderedListeners(comp);
for (MouseListener l : listeners) { for (MouseListener l : listeners) {
comp.removeMouseListener(l); comp.removeMouseListener(l);
}
comp.addMouseListener(popupListener);
for (MouseListener l : listeners) {
comp.addMouseListener(l); comp.addMouseListener(l);
} }
} }
private List<MouseListener> createOrderedListeners(Component comp) {
// Get the current listeners, add the popup mouse listener for this class, then move any
// Java listeners to the back of the list by removing them and re-adding them.
MouseListener[] listeners = comp.getMouseListeners();
List<MouseListener> orderedListeners = CollectionUtils.asList(listeners);
orderedListeners.add(popupListener);
for (MouseListener l : listeners) {
String name = l.getClass().getName();
if (name.startsWith("javax.") || name.startsWith("sun.")) {
orderedListeners.remove(l);
orderedListeners.add(l);
}
}
return orderedListeners;
}
private void deinitializeComponents(Component comp) { private void deinitializeComponents(Component comp) {
if (comp instanceof CellRendererPane) { if (comp instanceof CellRendererPane) {
return; return;