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+
26+package java.awt;
27+
28+import java.util.LinkedList;
29+import sun.awt.AppContext;
30+import 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+ */
43+class 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+}