blob: d457af4608aca15a171a62ae3854131662e42c6f [file] [log] [blame]
/*
* 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);
// }
// }
}