/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @author Michael Danilov, Dmitry A. Durnev * @version $Revision$ */ package java.awt; import java.awt.event.ComponentEvent; import java.awt.event.FocusEvent; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import java.awt.event.PaintEvent; import java.awt.event.WindowEvent; import org.apache.harmony.awt.internal.nls.Messages; import org.apache.harmony.awt.wtk.NativeEvent; import org.apache.harmony.awt.wtk.NativeWindow; /** * Helper package-private class for managing lightweight components & * dispatching events from heavyweight source */ class Dispatcher { //???AWT: final PopupDispatcher popupDispatcher = new PopupDispatcher(); //???AWT: final FocusDispatcher focusDispatcher; final MouseGrabManager mouseGrabManager = new MouseGrabManager(); final MouseDispatcher mouseDispatcher; private final ComponentDispatcher componentDispatcher = new ComponentDispatcher(); private final KeyDispatcher keyDispatcher = new KeyDispatcher(); private final Toolkit toolkit; int clickInterval = 250; /** * @param toolkit - AWT toolkit */ Dispatcher(Toolkit toolkit) { this.toolkit = toolkit; //???AWT: focusDispatcher = new FocusDispatcher(toolkit); mouseDispatcher = new MouseDispatcher(mouseGrabManager, toolkit); } /** * Dispatch native event: produce appropriate AWT events, * update component's fields when needed * @param event - native event to dispatch * @return - true means default processing by OS is not needed */ public boolean onEvent(NativeEvent event) { int eventId = event.getEventId(); if (eventId == NativeEvent.ID_CREATED) { return toolkit.onWindowCreated(event.getWindowId()); } else if (eventId == NativeEvent.ID_MOUSE_GRAB_CANCELED) { return mouseGrabManager.onGrabCanceled(); //???AWT // } else if (popupDispatcher.onEvent(event)) { // return false; } else { Component src = toolkit.getComponentById(event.getWindowId()); if (src != null) { if (((eventId >= ComponentEvent.COMPONENT_FIRST) && (eventId <= ComponentEvent.COMPONENT_LAST)) || ((eventId >= WindowEvent.WINDOW_FIRST) && (eventId <= WindowEvent.WINDOW_LAST)) || (eventId == NativeEvent.ID_INSETS_CHANGED) || (eventId == NativeEvent.ID_BOUNDS_CHANGED) || (eventId == NativeEvent.ID_THEME_CHANGED)) { return componentDispatcher.dispatch(src, event); } else if ((eventId >= MouseEvent.MOUSE_FIRST) && (eventId <= MouseEvent.MOUSE_LAST)) { return mouseDispatcher.dispatch(src, event); } else if (eventId == PaintEvent.PAINT) { //???AWT: src.redrawManager.addPaintRegion(src, event.getClipRects()); return true; } } if ((eventId >= FocusEvent.FOCUS_FIRST) && (eventId <= FocusEvent.FOCUS_LAST)) { //???AWT: return focusDispatcher.dispatch(src, event); return false; } else if ((eventId >= KeyEvent.KEY_FIRST) && (eventId <= KeyEvent.KEY_LAST)) { return keyDispatcher.dispatch(src, event); } } return false; } /** * The dispatcher of native events that affect * component's state or bounds */ final class ComponentDispatcher { /** * Handle native event that affects component's state or bounds * @param src - the component updated by the event * @param event - the native event * @return - as in Dispatcher.onEvent() * @see Dispatcher#onEvent(NativeEvent) */ boolean dispatch(Component src, NativeEvent event) { int id = event.getEventId(); if ((id == NativeEvent.ID_INSETS_CHANGED) || (id == NativeEvent.ID_THEME_CHANGED)) { return dispatchInsets(event, src); } else if ((id >= WindowEvent.WINDOW_FIRST) && (id <= WindowEvent.WINDOW_LAST)) { return dispatchWindow(event, src); } else { return dispatchPureComponent(event, src); } } /** * Handle the change of top-level window's native decorations * @param event - the native event * @param src - the component updated by the event * @return - as in Dispatcher.onEvent() * @see Dispatcher#onEvent(NativeEvent) */ boolean dispatchInsets(NativeEvent event, Component src) { //???AWT /* if (src instanceof Window) { ((Window) src).setNativeInsets(event.getInsets()); } */ return false; } /** * Handle the change of top-level window's state * @param event - the native event * @param src - the component updated by the event * @return - as in Dispatcher.onEvent() * @see Dispatcher#onEvent(NativeEvent) */ boolean dispatchWindow(NativeEvent event, Component src) { //???AWT /* Window window = (Window) src; int id = event.getEventId(); if (id == WindowEvent.WINDOW_CLOSING) { toolkit.getSystemEventQueueImpl().postEvent( new WindowEvent(window, WindowEvent.WINDOW_CLOSING)); return true; } else if (id == WindowEvent.WINDOW_STATE_CHANGED) { if (window instanceof Frame) { ((Frame) window) .updateExtendedState(event.getWindowState()); } } */ return false; } /** * Handle the change of component's size and/or position * @param event - the native event * @param src - the component updated by the event * @return - as in Dispatcher.onEvent() * @see Dispatcher#onEvent(NativeEvent) */ private boolean dispatchPureComponent(NativeEvent event, Component src) { Rectangle rect = event.getWindowRect(); Point loc = rect.getLocation(); int mask; switch (event.getEventId()) { case NativeEvent.ID_BOUNDS_CHANGED: mask = 0; break; case ComponentEvent.COMPONENT_MOVED: mask = NativeWindow.BOUNDS_NOSIZE; break; case ComponentEvent.COMPONENT_RESIZED: mask = NativeWindow.BOUNDS_NOMOVE; break; default: // awt.12E=Unknown component event id. throw new RuntimeException(Messages.getString("awt.12E")); //$NON-NLS-1$ } //???AWT /* if (!(src instanceof Window)) { Component compTo = src.getParent(); Component compFrom = src.getHWAncestor(); if ((compTo != null) && (compFrom != null)) { loc = MouseDispatcher.convertPoint(compFrom, loc, compTo); } } else { int windowState = event.getWindowState(); if ((windowState >= 0) && (src instanceof Frame)) { ((Frame) src).updateExtendedState(windowState); } } src.setBounds(loc.x, loc.y, rect.width, rect.height, mask, false); */ return false; } } /** * The dispatcher of the keyboard events */ final class KeyDispatcher { /** * Handle the keyboard event using the KeyboardFocusManager * @param src - the component receiving the event * @param event - the native event * @return - as in Dispatcher.onEvent() * @see Dispatcher#onEvent(NativeEvent) */ boolean dispatch(Component src, NativeEvent event) { int id = event.getEventId(); int modifiers = event.getInputModifiers(); int location = event.getKeyLocation(); int code = event.getVKey(); StringBuffer chars = event.getKeyChars(); int charsLength = chars.length(); long time = event.getTime(); char keyChar = event.getLastChar(); //???AWT /* if (src == null) { //retarget focus proxy key events to focusOwner: Window focusProxyOwner = toolkit.getFocusProxyOwnerById(event .getWindowId()); if (focusProxyOwner == null) { return false; } src = KeyboardFocusManager.actualFocusOwner; } */ EventQueue eventQueue = toolkit.getSystemEventQueueImpl(); if (src != null) { eventQueue.postEvent(new KeyEvent(src, id, time, modifiers, code, keyChar, location)); // KEY_TYPED goes after KEY_PRESSED if (id == KeyEvent.KEY_PRESSED) { for (int i = 0; i < charsLength; i++) { keyChar = chars.charAt(i); if (keyChar != KeyEvent.CHAR_UNDEFINED) { eventQueue.postEvent(new KeyEvent(src, KeyEvent.KEY_TYPED, time, modifiers, KeyEvent.VK_UNDEFINED, keyChar, KeyEvent.KEY_LOCATION_UNKNOWN)); } } } } return false; } } /** * Retargets the mouse events to the grab owner when mouse is grabbed, * grab and ungrab mouse when mouse buttons are pressed and released */ static final class MouseGrabManager { /** * The top-level window holding the mouse grab * that was explicitly started by startGrab() method */ //???AWT: private Window nativeGrabOwner = null; /** * The component that owns the synthetic * mouse grab while at least one of the * mouse buttons is pressed */ private Component syntheticGrabOwner = null; /** * Previous value of syntheticGrabOwner */ private Component lastSyntheticGrabOwner = null; /** * Number of mouse buttons currently pressed */ private int syntheticGrabDepth = 0; /** * The callback to be called when the explicit mouse grab ends */ private Runnable whenCanceled; /** * Explicitly start the mouse grab * @param grabWindow - the window that will own the grab * @param whenCanceled - the callback to call when the grab ends. * This parameter can be null */ //???AWT /* void startGrab(Window grabWindow, Runnable whenCanceled) { if (nativeGrabOwner != null) { // awt.12F=Attempt to start nested mouse grab throw new RuntimeException(Messages.getString("awt.12F")); //$NON-NLS-1$ } NativeWindow win = grabWindow.getNativeWindow(); if (win == null) { // awt.130=Attempt to grab mouse in not displayable window throw new RuntimeException(Messages.getString("awt.130")); //$NON-NLS-1$ } nativeGrabOwner = grabWindow; this.whenCanceled = whenCanceled; win.grabMouse(); } */ /** * Ends the explicit mouse grab. If the non-null callback was provided * in the startGrab() method, this callback is called */ void endGrab() { //???AWT /* if (nativeGrabOwner == null) { return; } Window grabWindow = nativeGrabOwner; nativeGrabOwner = null; NativeWindow win = grabWindow.getNativeWindow(); if (win != null) { win.ungrabMouse(); if (whenCanceled != null) { whenCanceled.run(); whenCanceled = null; } } */ } /** * Ends both explicit and synthetic grans * @return - always returns false */ boolean onGrabCanceled() { endGrab(); resetSyntheticGrab(); return false; } /** * Starts the synthetic mouse grab, increases the counter * of currently pressed mouse buttons * @param source - the component where mouse press event occured * @return - the component that owns the synthetic grab */ Component onMousePressed(Component source) { if (syntheticGrabDepth == 0) { syntheticGrabOwner = source; lastSyntheticGrabOwner = source; } syntheticGrabDepth++; return syntheticGrabOwner; } /** * Decreases the counter of currently pressed mouse buttons, * ends the synthetic mouse grab, when this counter becomes zero * @param source - the component where mouse press event occured * @return - the component that owns the synthetic grab, * or source parameter if mouse grab was released */ Component onMouseReleased(Component source) { Component ret = source; //???AWT /* if (syntheticGrabOwner != null && nativeGrabOwner == null) { ret = syntheticGrabOwner; } */ syntheticGrabDepth--; if (syntheticGrabDepth <= 0) { resetSyntheticGrab(); lastSyntheticGrabOwner = null; } return ret; } /** * Update the state of synthetic ouse gram * when the mouse is moved/dragged * @param event - the native event */ void preprocessEvent(NativeEvent event) { int id = event.getEventId(); switch (id) { case MouseEvent.MOUSE_MOVED: if (syntheticGrabOwner != null) { syntheticGrabOwner = null; syntheticGrabDepth = 0; } if (lastSyntheticGrabOwner != null) { lastSyntheticGrabOwner = null; } case MouseEvent.MOUSE_DRAGGED: if (syntheticGrabOwner == null && lastSyntheticGrabOwner != null) { syntheticGrabOwner = lastSyntheticGrabOwner; syntheticGrabDepth = 0; int mask = event.getInputModifiers(); syntheticGrabDepth += (mask & InputEvent.BUTTON1_DOWN_MASK) != 0 ? 1 : 0; syntheticGrabDepth += (mask & InputEvent.BUTTON2_DOWN_MASK) != 0 ? 1 : 0; syntheticGrabDepth += (mask & InputEvent.BUTTON3_DOWN_MASK) != 0 ? 1 : 0; } } } /** * @return the component that currently owns the synthetic grab */ Component getSyntheticGrabOwner() { return syntheticGrabOwner; } /** * ends synthetic grab */ private void resetSyntheticGrab() { syntheticGrabOwner = null; syntheticGrabDepth = 0; } } /** * Dispatches native events related to the pop-up boxes * (the non-component windows such as menus and drop lists) */ // final class PopupDispatcher { // // private PopupBox activePopup; // // private PopupBox underCursor; // // private final MouseGrab grab = new MouseGrab(); // // /** // * Handles the mouse grab for pop-up boxes // */ // private final class MouseGrab { // private int depth; // // private PopupBox owner; // // private final Point start = new Point(); // // /** // * Starts the grab when mouse is pressed // * @param src - the pop-up box where mouse event has occured // * @param where - the mouse pointer location // * @return - the grab owner // */ // PopupBox mousePressed(PopupBox src, Point where) { // if (depth == 0) { // owner = src; // start.setLocation(where); // } // depth++; // return owner; // } // // /** // * Ends the grab when all mousebuttons are released // * @param src - the pop-up box where mouse event has occured // * @param where - the mouse pointer location // * @return - the grab owner, or src parameter if the grab has ended // */ // PopupBox mouseReleased(PopupBox src, Point where) { // PopupBox ret = (owner != null) ? owner : src; // if (depth == 0) { // return ret; // } // depth--; // if (depth == 0) { // PopupBox tgt = owner; // owner = null; // if (tgt != null && src == null) { // Point a = new Point(start); // Point b = new Point(where); // Point pos = tgt.getScreenLocation(); // a.translate(-pos.x, -pos.y); // b.translate(-pos.x, -pos.y); // if (tgt.closeOnUngrab(a, b)) { // return null; // } // } // } // return ret; // } // // /** // * Set the grab owner to null // */ // void reset() { // depth = 0; // owner = null; // start.setLocation(0, 0); // } // // /** // * @return - the pop-up box currently owning the grab // */ // public PopupBox getOwner() { // return owner; // } // } // // /** // * Call the mouse event handler of the pop-up box // * @param src - the pop-up box where the mouse event occured // * @param eventId - the event ID, one of MouseEvent.MOUSE_* constants // * @param where - the mouse pointer location // * @param event - native event // */ // private void mouseEvent(PopupBox src, int eventId, Point where, // NativeEvent event) { // Point pos = src.getScreenLocation(); // pos.setLocation(where.x - pos.x, where.y - pos.y); // // src.onMouseEvent(eventId, pos, event.getMouseButton(), event // .getTime(), event.getInputModifiers(), event // .getWheelRotation()); // } // // /** // * Handle the native event targeted by a pop-up box. This could be // * paint event, mouse or keyboard event. // * @param event - the native event // * @return - false if the event was handled and doesn't // * need the further processing; true when the further // * processing is needed // */ // boolean onEvent(NativeEvent event) { // PopupBox src = toolkit.getPopupBoxById(event.getWindowId()); // int id = event.getEventId(); // // if ((id == PaintEvent.PAINT)) { // if (src != null) { // src.paint(event.getClipRects()); // return true; // } // Component c = toolkit.getComponentById(event.getWindowId()); // if ((c != null) && (c instanceof Frame)) { // ((Frame) c).paintMenuBar(event.getClipRects()); // } // return false; // } // // if ((id >= MouseEvent.MOUSE_FIRST) && (id <= MouseEvent.MOUSE_LAST)) { // Point where = event.getScreenPos(); // // if (src != underCursor) { // if (underCursor != null) { // mouseEvent(underCursor, MouseEvent.MOUSE_EXITED, where, // event); // } // underCursor = src; // if (underCursor != null) { // mouseEvent(underCursor, MouseEvent.MOUSE_ENTERED, // where, event); // underCursor.setDefaultCursor(); // } // } // if (id == MouseEvent.MOUSE_EXITED) { // underCursor = null; // } // // if ((activePopup == null) && (src == null || !src.isMenuBar())) { // return false; // } // // if (id == MouseEvent.MOUSE_PRESSED) { // src = grab.mousePressed(src, where); // } else if (id == MouseEvent.MOUSE_RELEASED) { // src = grab.mouseReleased(src, where); // } else if (src == null) { // src = grab.getOwner(); // } // // PopupBox wasActive = activePopup; // // if (src != null) { // mouseEvent(src, id, where, event); // return src.isMenu() || src.contains(where); // } // // if (wasActive != null && activePopup == null) { // return wasActive.isMenu(); // } // // if ((id == MouseEvent.MOUSE_PRESSED) // || (id == MouseEvent.MOUSE_RELEASED)) { // boolean isMenu = activePopup.isMenu(); // deactivateAll(); // return !isMenu; // } // return true; // } // // if (activePopup == null) { // return false; // } // // if ((id >= KeyEvent.KEY_FIRST) && (id <= KeyEvent.KEY_LAST)) { // boolean isMenu = activePopup.isMenu(); // activePopup.dispatchKeyEvent(id, event.getVKey(), event // .getTime(), event.getInputModifiers()); // // return isMenu; // } // // return false; // } // // /** // * Remember the pop-up as active and grab the mouse on it // * @param popup - the pop-up box to activate // */ // void activate(final PopupBox popup) { // if (activePopup == null) { // // activePopup = popup; // mouseGrabManager.startGrab(popup.getOwner(), new Runnable() { // public void run() { // deactivate(popup); // } // }); // } // } // // /** // * Deactivate the currently active pop-up box // */ // void deactivateAll() { // deactivate(activePopup); // } // // /** // * Deactivate the pop-up box, end the mouse grab // */ // void deactivate(PopupBox popup) { // grab.reset(); // // if (activePopup != null && activePopup == popup) { // activePopup = null; // mouseGrabManager.endGrab(); // popup.hide(); // underCursor = null; // } // } // // /** // * Check that the pop-up box is currently active // * @param popup - the pop-up box to check // * @return - true if active // */ // boolean isActive(PopupBox popup) { // return (popup == activePopup) && (popup != null); // } // } }