Package java.awt

Source Code of java.awt.Dispatcher$MouseGrabManager

/*
*  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
*/
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 {

    final PopupDispatcher popupDispatcher = new PopupDispatcher();

    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;

        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();
        } 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) {
                    src.redrawManager.addPaintRegion(src, event.getClipRects());
                    return true;
                }
            }
            if ((eventId >= FocusEvent.FOCUS_FIRST)
                    && (eventId <= FocusEvent.FOCUS_LAST)) {

                return focusDispatcher.dispatch(src, event);
            } 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) {
            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) {
            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$
            }

            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();

            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
         */
        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
         */
        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() {
            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;

            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);
        }
    }

}
TOP

Related Classes of java.awt.Dispatcher$MouseGrabManager

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.