| /* Copyright (C) 2000 Free Software Foundation |
| |
| This file is part of libgcj. |
| |
| This software is copyrighted work licensed under the terms of the |
| Libgcj License. Please consult the file "LIBGCJ_LICENSE" for |
| details. */ |
| |
| package gnu.awt; |
| |
| import java.awt.AWTEvent; |
| import java.awt.AWTError; |
| import java.awt.Component; |
| import java.awt.Container; |
| import java.awt.event.MouseEvent; |
| import java.awt.event.InputEvent; |
| |
| /** |
| * Encapsulates the logic required to dispatch events to the correct |
| * component in a component tree that may contain lightweight |
| * components. Toolkits typically only identify heavyweight components |
| * as the source of events. This class redirects the events to the |
| * appropriate lightweight children of the heavyweight component. |
| */ |
| public class LightweightRedirector |
| { |
| final static int LAST_BUTTON_NUMBER = 3; |
| |
| /* We sacrifice one array element to allow the button number to |
| match the index of this array. */ |
| Component[] releaseTargets = new Component[LAST_BUTTON_NUMBER+1]; |
| |
| /** |
| * |
| * Modifies or replaces the given event with an event that has been |
| * properly redirected. State of button presses are kept so that |
| * button releases can be redirected to the same component as the |
| * button press. It is required that all events are sent through |
| * this method in chronological order. |
| */ |
| public AWTEvent redirect(AWTEvent event) |
| { |
| if (event instanceof MouseEvent) |
| return redirectMouse((MouseEvent) event); |
| |
| /* In case we don't know how to redirect the event, simply return |
| the event unchanged. */ |
| return event; |
| } |
| |
| MouseEvent redirectMouse(MouseEvent event) |
| { |
| int button = getButtonNumber(event); |
| int id = event.getID(); |
| |
| Component heavySource = (Component) event.getSource(); |
| Component source = heavySource; |
| int x = event.getX(); |
| int y = event.getY(); |
| |
| if (id == MouseEvent.MOUSE_RELEASED) |
| { |
| Component target = releaseTargets[button]; |
| |
| if (target != null) |
| { |
| releaseTargets[button] = null; |
| source = target; |
| |
| Component child = source; |
| while (child != heavySource) |
| { |
| x -= child.getX(); |
| y -= child.getY(); |
| child = child.getParent(); |
| if (child == null) |
| System.err.println("warning, orphaned release target"); |
| } |
| } |
| } |
| else |
| { |
| /* Find real component, and adjust source, x and y |
| accordingly. */ |
| |
| while (true) |
| { |
| Component parent = source; |
| |
| Component child = parent.getComponentAt(x, y); |
| |
| if (parent == child) |
| break; |
| |
| // maybe ignoring would be better? |
| if (child == null) |
| { |
| String msg = "delivered event not within component. " + |
| "Heavyweight source was " + heavySource + ". " + |
| "Component was " + parent; |
| throw new AWTError(msg); |
| } |
| if (child.isLightweight()) |
| { |
| // descend down to child |
| source = child; |
| x -= child.getX(); |
| y -= child.getY(); |
| } |
| else |
| { |
| System.err.println("warning: event delivered to wrong " + |
| "heavyweight component. Was " + |
| "delivered to " + source + ". " + |
| "Should have been delivered to " + |
| child + ". Maybe the native window " + |
| "system is bubbling events up the " + |
| "containment hierarchy."); |
| break; |
| } |
| } |
| |
| /* ensure that the release event is delivered to the same |
| component as the press event. For most toolkits this is |
| only necessary for lightweight components, since the |
| underlying windowing system takes care of its heavyweight |
| components. */ |
| if (id == MouseEvent.MOUSE_PRESSED) |
| releaseTargets[button] = source; |
| } |
| |
| |
| if (source == heavySource) |
| return event; // no change in event |
| |
| // print warning for heavyweights |
| /* this warning can safely be removed if a toolkit that |
| needs heavyweight redirection support is ever created. */ |
| if (!source.isLightweight()) |
| System.err.println("warning: redirecting to heavyweight"); |
| |
| MouseEvent redirected = new MouseEvent(source, event.getID(), |
| event.getWhen(), |
| event.getModifiersEx(), |
| x, y, |
| event.getClickCount(), |
| event.isPopupTrigger()); |
| |
| return redirected; |
| } |
| |
| /** |
| * Identifies the button number for an input event. |
| * |
| * @returns the button number, or 0 if no button modifier was set |
| * for the event. |
| */ |
| int getButtonNumber(InputEvent event) |
| { |
| int modifiers = event.getModifiersEx(); |
| |
| modifiers &= |
| InputEvent.BUTTON1_DOWN_MASK | |
| InputEvent.BUTTON2_DOWN_MASK | |
| InputEvent.BUTTON3_DOWN_MASK; |
| |
| switch (modifiers) |
| { |
| case InputEvent.BUTTON1_DOWN_MASK: |
| return 1; |
| case InputEvent.BUTTON2_DOWN_MASK: |
| return 2; |
| case InputEvent.BUTTON3_DOWN_MASK: |
| return 3; |
| case 0: |
| return 0; |
| |
| default: |
| System.err.println("FIXME: multibutton event"); |
| return 0; |
| } |
| } |
| } |