KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > java > awt > SequencedEvent


1 /*
2  * @(#)SequencedEvent.java 1.10 03/12/19
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package java.awt;
9
10 import java.awt.AWTEvent JavaDoc;
11 import java.awt.ActiveEvent JavaDoc;
12 import java.util.LinkedList JavaDoc;
13 import sun.awt.AppContext;
14 import sun.awt.SunToolkit;
15
16 /**
17  * A mechanism for ensuring that a series of AWTEvents are executed in a
18  * precise order, even across multiple AppContexts. The nested events will be
19  * dispatched in the order in which their wrapping SequencedEvents were
20  * constructed. The only exception to this rule is if the peer of the target of
21  * the nested event was destroyed (with a call to Component.removeNotify)
22  * before the wrapping SequencedEvent was able to be dispatched. In this case,
23  * the nested event is never dispatched.
24  *
25  * @version 1.10, 12/19/03
26  * @author David Mendenhall
27  */

28 class SequencedEvent extends AWTEvent JavaDoc implements ActiveEvent JavaDoc {
29     private static final int ID =
30     java.awt.event.FocusEvent.FOCUS_LAST + 1;
31     private static final LinkedList JavaDoc list = new LinkedList JavaDoc();
32
33     private final AWTEvent JavaDoc nested;
34     private AppContext appContext;
35     private boolean disposed;
36
37     /**
38      * Constructs a new SequencedEvent which will dispatch the specified
39      * nested event.
40      *
41      * @param nested the AWTEvent which this SequencedEvent's dispatch()
42      * method will dispatch
43      */

44     public SequencedEvent(AWTEvent JavaDoc nested) {
45     super(nested.getSource(), ID);
46     this.nested = nested;
47     synchronized (SequencedEvent JavaDoc.class) {
48         list.add(this);
49     }
50     }
51
52     /**
53      * Dispatches the nested event after all previous nested events have been
54      * dispatched or disposed. If this method is invoked before all previous nested events
55      * have been dispatched, then this method blocks until such a point is
56      * reached.
57      * While waiting disposes nested events to disposed AppContext
58      *
59      * NOTE: Locking protocol. Since dispose() can get EventQueue lock,
60      * dispatch() shall never call dispose() while holding the lock on the list,
61      * as EventQueue lock is held during dispatching. The locks should be acquired
62      * in the same order.
63      */

64     public final void dispatch() {
65         try {
66             appContext = AppContext.getAppContext();
67
68             if (getFirst() != this) {
69                 if (EventQueue.isDispatchThread()) {
70                     EventDispatchThread JavaDoc edt = (EventDispatchThread JavaDoc)
71                         Thread.currentThread();
72                     edt.pumpEvents(SentEvent.ID, new Conditional JavaDoc() {
73                         public boolean evaluate() {
74                             return !SequencedEvent.this.isFirstOrDisposed();
75                         }
76                     });
77                 } else {
78                     while(!isFirstOrDisposed()) {
79                         synchronized (SequencedEvent JavaDoc.class) {
80                             try {
81                                 SequencedEvent JavaDoc.class.wait(1000);
82                             } catch (InterruptedException JavaDoc e) {
83                                 break;
84                             }
85                         }
86                     }
87                 }
88             }
89
90             if (!disposed) {
91                 KeyboardFocusManager.getCurrentKeyboardFocusManager().
92                     setCurrentSequencedEvent(this);
93                 Toolkit.getEventQueue().dispatchEvent(nested);
94             }
95         } finally {
96             dispose();
97         }
98     }
99    
100     /**
101      * true only if event exists and nested source appContext is disposed.
102      */

103     private final static boolean isOwnerAppContextDisposed(SequencedEvent JavaDoc se) {
104         if (se != null) {
105             Object JavaDoc target = se.nested.getSource();
106             if (target instanceof Component JavaDoc) {
107                 return ((Component JavaDoc)target).appContext.isDisposed();
108             }
109         }
110         return false;
111     }
112
113     /**
114      * Sequenced events are dispatched in order, so we cannot dispatch
115      * until we are the first sequenced event in the queue (i.e. it's our
116      * turn). But while we wait for our turn to dispatch, the event
117      * could have been disposed for a number of reasons.
118      */

119     public final boolean isFirstOrDisposed() {
120         if (disposed) {
121             return true;
122         }
123         // getFirstWithContext can dispose this
124
return this == getFirstWithContext() || disposed;
125     }
126
127     private final synchronized static SequencedEvent JavaDoc getFirst() {
128         return (SequencedEvent JavaDoc)list.getFirst();
129     }
130
131     /* Disposes all events from disposed AppContext
132      * return first valid event
133      */

134     private final static SequencedEvent JavaDoc getFirstWithContext() {
135         SequencedEvent JavaDoc first = getFirst();
136         while(isOwnerAppContextDisposed(first)) {
137             first.dispose();
138             first = getFirst();
139         }
140         return first;
141     }
142
143     /**
144      * Disposes of this instance. This method is invoked once the nested event
145      * has been dispatched and handled, or when the peer of the target of the
146      * nested event has been disposed with a call to Component.removeNotify.
147      *
148      * NOTE: Locking protocol. Since SunToolkit.postEvent can get EventQueue lock,
149      * it shall never be called while holding the lock on the list,
150      * as EventQueue lock is held during dispatching and dispatch() will get
151      * lock on the list. The locks should be acquired in the same order.
152      */

153     final void dispose() {
154       synchronized (SequencedEvent JavaDoc.class) {
155             if (disposed) {
156                 return;
157             }
158             if (KeyboardFocusManager.getCurrentKeyboardFocusManager().
159                     getCurrentSequencedEvent() == this) {
160                 KeyboardFocusManager.getCurrentKeyboardFocusManager().
161                     setCurrentSequencedEvent(null);
162             }
163             disposed = true;
164         }
165         // Wake myself up
166
if (appContext != null) {
167             SunToolkit.postEvent(appContext, new SentEvent JavaDoc());
168         }
169         
170         SequencedEvent JavaDoc next = null;
171         
172         synchronized (SequencedEvent JavaDoc.class) {
173           SequencedEvent JavaDoc.class.notifyAll();
174
175           if (list.getFirst() == this) {
176               list.removeFirst();
177
178               if (!list.isEmpty()) {
179                     next = (SequencedEvent JavaDoc)list.getFirst();
180               }
181           } else {
182               list.remove(this);
183           }
184       }
185         // Wake up waiting threads
186
if (next != null && next.appContext != null) {
187             SunToolkit.postEvent(next.appContext, new SentEvent JavaDoc());
188         }
189     }
190 }
191
Popular Tags