001 /*
002 * Created on Oct 8, 2007
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
005 * the License. You may obtain a copy of the License at
006 *
007 * http://www.apache.org/licenses/LICENSE-2.0
008 *
009 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
010 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
011 * specific language governing permissions and limitations under the License.
012 *
013 * Copyright @2007-2010 the original author or authors.
014 */
015 package org.fest.swing.monitor;
016
017 import static org.fest.swing.edt.GuiActionRunner.execute;
018
019 import java.awt.*;
020 import java.util.Collection;
021
022 import org.fest.swing.annotation.RunsInCurrentThread;
023 import org.fest.swing.annotation.RunsInEDT;
024 import org.fest.swing.edt.GuiQuery;
025 import org.fest.util.VisibleForTesting;
026
027 /**
028 * Understands a monitor that keeps track of all known root windows (showing, hidden, closed.)
029 *
030 * @author Alex Ruiz
031 */
032 public class WindowMonitor {
033
034 private final Context context;
035 private final ContextMonitor contextMonitor;
036 private final Windows windows;
037 private final WindowStatus windowStatus;
038 private final WindowAvailabilityMonitor windowAvailabilityMonitor;
039
040 /**
041 * Create an instance of WindowTracker which will track all windows coming and going on the current and subsequent
042 * <code>AppContext</code>s.
043 * <p>
044 * <strong>WARNING:</strong> if an applet loads this class, it will only ever see stuff in its own
045 * <code>AppContext</code>.
046 * </p>
047 * @param toolkit the <code>Toolkit</code> to use.
048 */
049 @RunsInCurrentThread
050 WindowMonitor(Toolkit toolkit) {
051 this(toolkit, new Context(toolkit), new WindowStatus(new Windows()));
052 }
053
054 @VisibleForTesting
055 @RunsInCurrentThread
056 WindowMonitor(Toolkit toolkit, Context context, WindowStatus windowStatus) {
057 this.context = context;
058 this.windowStatus = windowStatus;
059 windows = windowStatus.windows();
060 contextMonitor = new ContextMonitor(context, windows);
061 contextMonitor.attachTo(toolkit);
062 windowAvailabilityMonitor = new WindowAvailabilityMonitor(windows);
063 windowAvailabilityMonitor.attachTo(toolkit);
064 populateExistingWindows();
065 }
066
067 private void populateExistingWindows() {
068 for (Frame f : Frame.getFrames()) examine(f);
069 }
070
071 @RunsInCurrentThread
072 private void examine(Window w) {
073 windows.attachNewWindowVisibilityMonitor(w);
074 for (Window owned : w.getOwnedWindows()) examine(owned);
075 windows.markExisting(w);
076 context.addContextFor(w);
077 }
078
079 /**
080 * Returns whether the window is ready to receive OS-level event input. A window's "isShowing" flag may be set
081 * <code>true</code> before the <code>WINDOW_OPENED</code> event is generated, and even after the
082 * <code>WINDOW_OPENED</code> is sent the window peer is not guaranteed to be ready.
083 * @param w the given window.
084 * @return whether the window is ready to receive OS-level event input.
085 */
086 public boolean isWindowReady(Window w) {
087 if (windows.isReady(w)) return true;
088 windowStatus.checkIfReady(w);
089 return false;
090 }
091
092 /**
093 * Returns the event queue corresponding to the given component. In most cases, this is the same as
094 * <code>Component.getToolkit().getSystemEventQueue()</code>, but in the case of applets will bypass the
095 * <code>AppContext</code> and provide the real event queue.
096 * @param c the given component.
097 * @return the event queue corresponding to the given component.
098 */
099 public EventQueue eventQueueFor(Component c) {
100 return context.eventQueueFor(c);
101 }
102
103 /**
104 * Returns all known event queues.
105 * @return all known event queues.
106 */
107 public Collection<EventQueue> allEventQueues() {
108 return context.allEventQueues();
109 }
110
111 /**
112 * Return all available root windows. A root window is one that has a null parent. Nominally this means a list similar
113 * to that returned by <code>{@link Frame#getFrames() Frame.getFrames()}</code>, but in the case of an
114 * <code>{@link java.applet.Applet}</code> may return a few dialogs as well.
115 * @return all available root windows.
116 */
117 public Collection<Window> rootWindows() {
118 return context.rootWindows();
119 }
120
121 /**
122 * Returns the singleton instance of this class.
123 * @return the singleton instance of this class.
124 */
125 @RunsInEDT
126 public static WindowMonitor instance() {
127 return SingletonLazyLoader.INSTANCE;
128 }
129
130 @RunsInEDT
131 private static class SingletonLazyLoader {
132 static final WindowMonitor INSTANCE = execute(new GuiQuery<WindowMonitor>() {
133 protected WindowMonitor executeInEDT() throws Throwable {
134 return new WindowMonitor(Toolkit.getDefaultToolkit());
135 }
136 });
137 }
138 }