History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/java/awt/SequencedEvent.java (1 of 18352 files). Show all

Unified · Split

java/pkg/java/awt/SequencedEvent.java+213−0
@@ -0,0 +1,213 @@
1/*
2 * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package java.awt;
27
28import java.util.LinkedList;
29import sun.awt.AppContext;
30import sun.awt.SunToolkit;
31
32/**
33 * A mechanism for ensuring that a series of AWTEvents are executed in a
34 * precise order, even across multiple AppContexts. The nested events will be
35 * dispatched in the order in which their wrapping SequencedEvents were
36 * constructed. The only exception to this rule is if the peer of the target of
37 * the nested event was destroyed (with a call to Component.removeNotify)
38 * before the wrapping SequencedEvent was able to be dispatched. In this case,
39 * the nested event is never dispatched.
40 *
41 * @author David Mendenhall
42 */
43class SequencedEvent extends AWTEvent implements ActiveEvent {
44 /*
45 * serialVersionUID
46 */
47 private static final long serialVersionUID = 547742659238625067L;
48
49 private static final int ID =
50 java.awt.event.FocusEvent.FOCUS_LAST + 1;
51 private static final LinkedList list = new LinkedList();
52
53 private final AWTEvent nested;
54 private AppContext appContext;
55 private boolean disposed;
56
57 /**
58 * Constructs a new SequencedEvent which will dispatch the specified
59 * nested event.
60 *
61 * @param nested the AWTEvent which this SequencedEvent's dispatch()
62 * method will dispatch
63 */
64 public SequencedEvent(AWTEvent nested) {
65 super(nested.getSource(), ID);
66 this.nested = nested;
67 // All AWTEvents that are wrapped in SequencedEvents are (at
68 // least currently) implicitly generated by the system
69 SunToolkit.setSystemGenerated(nested);
70 synchronized (SequencedEvent.class) {
71 list.add(this);
72 }
73 }
74
75 /**
76 * Dispatches the nested event after all previous nested events have been
77 * dispatched or disposed. If this method is invoked before all previous nested events
78 * have been dispatched, then this method blocks until such a point is
79 * reached.
80 * While waiting disposes nested events to disposed AppContext
81 *
82 * NOTE: Locking protocol. Since dispose() can get EventQueue lock,
83 * dispatch() shall never call dispose() while holding the lock on the list,
84 * as EventQueue lock is held during dispatching. The locks should be acquired
85 * in the same order.
86 */
87 public final void dispatch() {
88 try {
89 appContext = AppContext.getAppContext();
90
91 if (getFirst() != this) {
92 if (EventQueue.isDispatchThread()) {
93 EventDispatchThread edt = (EventDispatchThread)
94 Thread.currentThread();
95 edt.pumpEvents(SentEvent.ID, new Conditional() {
96 public boolean evaluate() {
97 return !SequencedEvent.this.isFirstOrDisposed();
98 }
99 });
100 } else {
101 while(!isFirstOrDisposed()) {
102 synchronized (SequencedEvent.class) {
103 try {
104 SequencedEvent.class.wait(1000);
105 } catch (InterruptedException e) {
106 break;
107 }
108 }
109 }
110 }
111 }
112
113 if (!disposed) {
114 KeyboardFocusManager.getCurrentKeyboardFocusManager().
115 setCurrentSequencedEvent(this);
116 Toolkit.getEventQueue().dispatchEvent(nested);
117 }
118 } finally {
119 dispose();
120 }
121 }
122
123 /**
124 * true only if event exists and nested source appContext is disposed.
125 */
126 private final static boolean isOwnerAppContextDisposed(SequencedEvent se) {
127 if (se != null) {
128 Object target = se.nested.getSource();
129 if (target instanceof Component) {
130 return ((Component)target).appContext.isDisposed();
131 }
132 }
133 return false;
134 }
135
136 /**
137 * Sequenced events are dispatched in order, so we cannot dispatch
138 * until we are the first sequenced event in the queue (i.e. it's our
139 * turn). But while we wait for our turn to dispatch, the event
140 * could have been disposed for a number of reasons.
141 */
142 public final boolean isFirstOrDisposed() {
143 if (disposed) {
144 return true;
145 }
146 // getFirstWithContext can dispose this
147 return this == getFirstWithContext() || disposed;
148 }
149
150 private final synchronized static SequencedEvent getFirst() {
151 return (SequencedEvent)list.getFirst();
152 }
153
154 /* Disposes all events from disposed AppContext
155 * return first valid event
156 */
157 private final static SequencedEvent getFirstWithContext() {
158 SequencedEvent first = getFirst();
159 while(isOwnerAppContextDisposed(first)) {
160 first.dispose();
161 first = getFirst();
162 }
163 return first;
164 }
165
166 /**
167 * Disposes of this instance. This method is invoked once the nested event
168 * has been dispatched and handled, or when the peer of the target of the
169 * nested event has been disposed with a call to Component.removeNotify.
170 *
171 * NOTE: Locking protocol. Since SunToolkit.postEvent can get EventQueue lock,
172 * it shall never be called while holding the lock on the list,
173 * as EventQueue lock is held during dispatching and dispatch() will get
174 * lock on the list. The locks should be acquired in the same order.
175 */
176 final void dispose() {
177 synchronized (SequencedEvent.class) {
178 if (disposed) {
179 return;
180 }
181 if (KeyboardFocusManager.getCurrentKeyboardFocusManager().
182 getCurrentSequencedEvent() == this) {
183 KeyboardFocusManager.getCurrentKeyboardFocusManager().
184 setCurrentSequencedEvent(null);
185 }
186 disposed = true;
187 }
188 // Wake myself up
189 if (appContext != null) {
190 SunToolkit.postEvent(appContext, new SentEvent());
191 }
192
193 SequencedEvent next = null;
194
195 synchronized (SequencedEvent.class) {
196 SequencedEvent.class.notifyAll();
197
198 if (list.getFirst() == this) {
199 list.removeFirst();
200
201 if (!list.isEmpty()) {
202 next = (SequencedEvent)list.getFirst();
203 }
204 } else {
205 list.remove(this);
206 }
207 }
208 // Wake up waiting threads
209 if (next != null && next.appContext != null) {
210 SunToolkit.postEvent(next.appContext, new SentEvent());
211 }
212 }
213}