|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package com.sun.java.accessibility.util; |
|
|
|
import java.util.*; |
|
import java.awt.*; |
|
import java.awt.event.*; |
|
import javax.accessibility.*; |
|
import java.security.AccessController; |
|
import java.security.PrivilegedAction; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
@jdk.Exported |
|
public class EventQueueMonitor |
|
implements AWTEventListener { |
|
|
|
// NOTE: All of the following properties are static. The reason |
|
// for this is that there may be multiple EventQueue instances |
|
// in use in the same VM. By making these properties static, |
|
// we can guarantee we get the information from all of the |
|
// EventQueue instances. |
|
|
|
// The stuff that is cached. |
|
|
|
static Vector topLevelWindows = new Vector(); |
|
static Window topLevelWindowWithFocus = null; |
|
static Point currentMousePosition = null; |
|
static Component currentMouseComponent = null; |
|
|
|
// Low-level listener interfaces |
|
|
|
static GUIInitializedListener guiInitializedListener = null; |
|
static TopLevelWindowListener topLevelWindowListener = null; |
|
static MouseMotionListener mouseMotionListener = null; |
|
|
|
/** |
|
* Class variable stating whether the assistive technologies have |
|
* been loaded yet or not. The assistive technologies won't be |
|
* loaded until the first event is posted to the EventQueue. This |
|
* gives the toolkit a chance to do all the necessary initialization |
|
* it needs to do. |
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
static boolean guiInitialized = false; |
|
|
|
|
|
|
|
*/ |
|
static EventQueueMonitorItem componentEventQueue = null; |
|
|
|
|
|
|
|
*/ |
|
static private ComponentEvtDispatchThread cedt = null; |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
static Object componentEventQueueLock = new Object(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public EventQueueMonitor() { |
|
if (cedt == null) { |
|
cedt = new ComponentEvtDispatchThread("EventQueueMonitor-ComponentEvtDispatch"); |
|
|
|
cedt.setDaemon(true); |
|
cedt.start(); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
static void queueComponentEvent(ComponentEvent e) { |
|
synchronized(componentEventQueueLock) { |
|
EventQueueMonitorItem eqi = new EventQueueMonitorItem(e); |
|
if (componentEventQueue == null) { |
|
componentEventQueue = eqi; |
|
} else { |
|
EventQueueMonitorItem q = componentEventQueue; |
|
while (true) { |
|
if (q.next != null) { |
|
q = q.next; |
|
} else { |
|
break; |
|
} |
|
} |
|
q.next = eqi; |
|
} |
|
componentEventQueueLock.notifyAll(); |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
public static void maybeInitialize() { |
|
if (cedt == null) { |
|
java.security.AccessController.doPrivileged( |
|
new java.security.PrivilegedAction() { |
|
public Object run() { |
|
try { |
|
long eventMask = AWTEvent.WINDOW_EVENT_MASK | |
|
AWTEvent.FOCUS_EVENT_MASK | |
|
AWTEvent.MOUSE_MOTION_EVENT_MASK; |
|
|
|
Toolkit.getDefaultToolkit().addAWTEventListener(new EventQueueMonitor(), eventMask); |
|
} catch (Exception e) { |
|
} |
|
return null; |
|
} |
|
} |
|
); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public void eventDispatched(AWTEvent theEvent) { |
|
processEvent(theEvent); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
static void maybeNotifyAssistiveTechnologies() { |
|
|
|
if (!guiInitialized) { |
|
guiInitialized = true; |
|
if (guiInitializedListener != null) { |
|
guiInitializedListener.guiInitialized(); |
|
} |
|
} |
|
|
|
} |
|
|
|
/********************************************************************/ |
|
/* */ |
|
/* Package Private Methods */ |
|
/* */ |
|
/********************************************************************/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
static void addTopLevelWindow(Component c) { |
|
Container parent; |
|
|
|
if (c == null) { |
|
return; |
|
} |
|
|
|
if (!(c instanceof Window)) { |
|
addTopLevelWindow(c.getParent()); |
|
return; |
|
} |
|
|
|
if ((c instanceof Dialog) || (c instanceof Window)) { |
|
parent = (Container) c; |
|
} else { |
|
parent = c.getParent(); |
|
if (parent != null) { |
|
addTopLevelWindow(parent); |
|
return; |
|
} |
|
} |
|
|
|
if (parent == null) { |
|
parent = (Container) c; |
|
} |
|
|
|
// Because this method is static, do not make it synchronized because |
|
// it can lock the whole class. Instead, just lock what needs to be |
|
// locked. |
|
|
|
synchronized (topLevelWindows) { |
|
if ((parent != null) && !topLevelWindows.contains(parent)) { |
|
topLevelWindows.addElement(parent); |
|
if (topLevelWindowListener != null) { |
|
topLevelWindowListener.topLevelWindowCreated((Window) parent); |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
static void removeTopLevelWindow(Window w) { |
|
|
|
// Because this method is static, do not make it synchronized because |
|
// it can lock the whole class. Instead, just lock what needs to be |
|
// locked. |
|
|
|
synchronized (topLevelWindows) { |
|
if (topLevelWindows.contains(w)) { |
|
topLevelWindows.removeElement(w); |
|
if (topLevelWindowListener != null) { |
|
topLevelWindowListener.topLevelWindowDestroyed(w); |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
static void updateCurrentMousePosition(MouseEvent mouseEvent) { |
|
Point oldMousePos = currentMousePosition; |
|
// Be careful here. The component in the event might be |
|
|
|
try { |
|
Point eventPoint = mouseEvent.getPoint(); |
|
currentMouseComponent = (Component) (mouseEvent.getSource()); |
|
currentMousePosition = currentMouseComponent.getLocationOnScreen(); |
|
currentMousePosition.translate(eventPoint.x,eventPoint.y); |
|
} catch (Exception e) { |
|
currentMousePosition = oldMousePos; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
static void processEvent(AWTEvent theEvent) { |
|
switch (theEvent.getID()) { |
|
case MouseEvent.MOUSE_MOVED: |
|
case MouseEvent.MOUSE_DRAGGED: |
|
case FocusEvent.FOCUS_GAINED: |
|
case WindowEvent.WINDOW_DEACTIVATED: |
|
queueComponentEvent((ComponentEvent) theEvent); |
|
break; |
|
|
|
case WindowEvent.WINDOW_ACTIVATED: |
|
// Dialogs fire WINDOW_ACTIVATED and FOCUS_GAINED events |
|
// before WINDOW_OPENED so we need to add topLevelListeners |
|
// for the dialog when it is first activated to get a |
|
|
|
if (theEvent instanceof ComponentEvent) { |
|
ComponentEvent ce = (ComponentEvent)theEvent; |
|
if (ce.getComponent() instanceof Window) { |
|
EventQueueMonitor.addTopLevelWindow(ce.getComponent()); |
|
EventQueueMonitor.maybeNotifyAssistiveTechnologies(); |
|
} else { |
|
EventQueueMonitor.maybeNotifyAssistiveTechnologies(); |
|
EventQueueMonitor.addTopLevelWindow(ce.getComponent()); |
|
} |
|
} |
|
queueComponentEvent((ComponentEvent) theEvent); |
|
break; |
|
|
|
|
|
case WindowEvent.WINDOW_OPENED: |
|
if (theEvent instanceof ComponentEvent) { |
|
ComponentEvent ce = (ComponentEvent)theEvent; |
|
if (ce.getComponent() instanceof Window) { |
|
EventQueueMonitor.addTopLevelWindow(ce.getComponent()); |
|
EventQueueMonitor.maybeNotifyAssistiveTechnologies(); |
|
} else { |
|
EventQueueMonitor.maybeNotifyAssistiveTechnologies(); |
|
EventQueueMonitor.addTopLevelWindow(ce.getComponent()); |
|
} |
|
} |
|
break; |
|
case WindowEvent.WINDOW_CLOSED: |
|
if (theEvent instanceof ComponentEvent) { |
|
ComponentEvent ce = (ComponentEvent)theEvent; |
|
EventQueueMonitor.removeTopLevelWindow((Window) (ce.getComponent())); |
|
} |
|
break; |
|
|
|
default: |
|
break; |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
static synchronized Component getShowingComponentAt(Container c, int x, int y) { |
|
if (!c.contains(x, y)) { |
|
return null; |
|
} |
|
int ncomponents = c.getComponentCount(); |
|
for (int i = 0 ; i < ncomponents ; i++) { |
|
Component comp = c.getComponent(i); |
|
if (comp != null && comp.isShowing()) { |
|
Point location = comp.getLocation(); |
|
if (comp.contains(x - location.x, y - location.y)) { |
|
return comp; |
|
} |
|
} |
|
} |
|
return c; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
static synchronized Component getComponentAt(Container c, Point p) { |
|
if (!c.isShowing()) { |
|
return null; |
|
} |
|
|
|
Component comp; |
|
Point containerLoc = c.getLocationOnScreen(); |
|
Point containerPoint = new Point(p.x - containerLoc.x, |
|
p.y - containerLoc.y); |
|
|
|
comp = getShowingComponentAt(c, containerPoint.x, containerPoint.y); |
|
|
|
if ((comp != c) && (comp instanceof Container)) { |
|
return getComponentAt((Container)comp,p); |
|
} else { |
|
return comp; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
static public Accessible getAccessibleAt(Point p) { |
|
Window w = getTopLevelWindowWithFocus(); |
|
Window[] wins = getTopLevelWindows(); |
|
Component c = null; |
|
|
|
// See if the point we're being asked about is the |
|
// currentMousePosition. If so, start with the component |
|
// that we know the currentMousePostion is over |
|
|
|
if (currentMousePosition == null) { |
|
return null; |
|
} |
|
if (currentMousePosition.equals(p)) { |
|
if (currentMouseComponent instanceof Container) { |
|
c = getComponentAt((Container) currentMouseComponent, p); |
|
} |
|
} |
|
|
|
// Try the window with focus next |
|
|
|
if (c == null && w != null) { |
|
c = getComponentAt(w,p); |
|
} |
|
|
|
|
|
if (c == null) { |
|
for (int i = 0; i < wins.length; i++) { |
|
c = getComponentAt(wins[i],p); |
|
if (c != null) { |
|
break; |
|
} |
|
} |
|
} |
|
|
|
if (c instanceof Accessible) { |
|
AccessibleContext ac = ((Accessible) c).getAccessibleContext(); |
|
if (ac != null) { |
|
AccessibleComponent acmp = ac.getAccessibleComponent(); |
|
if ((acmp != null) && (ac.getAccessibleChildrenCount() != 0)) { |
|
Point location = acmp.getLocationOnScreen(); |
|
location.move(p.x - location.x, p.y - location.y); |
|
return acmp.getAccessibleAt(location); |
|
} |
|
} |
|
return (Accessible) c; |
|
} else { |
|
return Translator.getAccessible(c); |
|
} |
|
} |
|
|
|
/********************************************************************/ |
|
/* */ |
|
/* Public Methods */ |
|
/* */ |
|
/********************************************************************/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
static public boolean isGUIInitialized() { |
|
maybeInitialize(); |
|
return guiInitialized; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
static public void addGUIInitializedListener(GUIInitializedListener l) { |
|
maybeInitialize(); |
|
guiInitializedListener = |
|
GUIInitializedMulticaster.add(guiInitializedListener,l); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
static public void removeGUIInitializedListener(GUIInitializedListener l) { |
|
guiInitializedListener = |
|
GUIInitializedMulticaster.remove(guiInitializedListener,l); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
static public void addTopLevelWindowListener(TopLevelWindowListener l) { |
|
topLevelWindowListener = |
|
TopLevelWindowMulticaster.add(topLevelWindowListener,l); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
static public void removeTopLevelWindowListener(TopLevelWindowListener l) { |
|
topLevelWindowListener = |
|
TopLevelWindowMulticaster.remove(topLevelWindowListener,l); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
static public Point getCurrentMousePosition() { |
|
return currentMousePosition; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
static public Window[] getTopLevelWindows() { |
|
|
|
// Because this method is static, do not make it synchronized because |
|
// it can lock the whole class. Instead, just lock what needs to be |
|
// locked. |
|
|
|
synchronized (topLevelWindows) { |
|
int count = topLevelWindows.size(); |
|
if (count > 0) { |
|
Window[] w = new Window[count]; |
|
for (int i = 0; i < count; i++) { |
|
w[i] = (Window)topLevelWindows.elementAt(i); |
|
} |
|
return w; |
|
} else { |
|
return new Window[0]; |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
static public Window getTopLevelWindowWithFocus() { |
|
return topLevelWindowWithFocus; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
class ComponentEvtDispatchThread extends Thread { |
|
public ComponentEvtDispatchThread(String name) { |
|
super(name); |
|
} |
|
public void run() { |
|
ComponentEvent ce = null; |
|
while (true) { |
|
synchronized(EventQueueMonitor.componentEventQueueLock) { |
|
while (EventQueueMonitor.componentEventQueue == null) { |
|
try { |
|
EventQueueMonitor.componentEventQueueLock.wait(); |
|
} catch (InterruptedException e) { |
|
} |
|
} |
|
ce = (ComponentEvent)EventQueueMonitor.componentEventQueue.event; |
|
EventQueueMonitor.componentEventQueue = |
|
EventQueueMonitor.componentEventQueue.next; |
|
} |
|
switch (ce.getID()) { |
|
case MouseEvent.MOUSE_MOVED: |
|
case MouseEvent.MOUSE_DRAGGED: |
|
EventQueueMonitor.updateCurrentMousePosition((MouseEvent) ce); |
|
break; |
|
case WindowEvent.WINDOW_ACTIVATED: |
|
EventQueueMonitor.maybeNotifyAssistiveTechnologies(); |
|
EventQueueMonitor.topLevelWindowWithFocus = ((WindowEvent) ce).getWindow(); |
|
break; |
|
|
|
default: |
|
break; |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
class EventQueueMonitorItem { |
|
AWTEvent event; |
|
EventQueueMonitorItem next; |
|
|
|
EventQueueMonitorItem(AWTEvent evt) { |
|
event = evt; |
|
next = null; |
|
} |
|
} |