001: /*
002: * Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package sun.awt;
027:
028: import java.awt.IllegalComponentStateException;
029: import java.util.Collections;
030: import java.util.Iterator;
031: import java.util.Map;
032: import java.util.Set;
033: import java.util.HashMap;
034: import java.util.WeakHashMap;
035: import sun.awt.DebugHelper;
036:
037: /**
038: * This class is used to aid in keeping track of DisplayChangedListeners and
039: * notifying them when a display change has taken place. DisplayChangedListeners
040: * are notified when the display's bit depth is changed, or when a top-level
041: * window has been dragged onto another screen.
042: *
043: * It is safe for a DisplayChangedListener to be added while the list is being
044: * iterated.
045: *
046: * The displayChanged() call is propagated after some occurrence (either
047: * due to user action or some other application) causes the display mode
048: * (e.g., depth or resolution) to change. All heavyweight components need
049: * to know when this happens because they need to create new surfaceData
050: * objects based on the new depth.
051: *
052: * displayChanged() is also called on Windows when they are moved from one
053: * screen to another on a system equipped with multiple displays.
054: */
055: public class SunDisplayChanger {
056: private static final DebugHelper dbg = DebugHelper
057: .create(SunDisplayChanger.class);
058:
059: // Create a new synchronizedMap with initial capacity of one listener.
060: // It is asserted that the most common case is to have one GraphicsDevice
061: // and one top-level Window.
062: private Map listeners = Collections
063: .synchronizedMap(new WeakHashMap(1));
064:
065: public SunDisplayChanger() {
066: }
067:
068: /*
069: * Add a DisplayChangeListener to this SunDisplayChanger so that it is
070: * notified when the display is changed.
071: */
072: public void add(DisplayChangedListener theListener) {
073: if (dbg.on) {
074: dbg.assertion(theListener != null);
075: }
076:
077: listeners.put(theListener, null);
078: }
079:
080: /*
081: * Remove the given DisplayChangeListener from this SunDisplayChanger.
082: */
083: public void remove(DisplayChangedListener theListener) {
084: if (dbg.on) {
085: dbg.assertion(theListener != null);
086: }
087:
088: listeners.remove(theListener);
089: }
090:
091: /*
092: * Notify our list of DisplayChangedListeners that a display change has
093: * taken place by calling their displayChanged() methods.
094: */
095: public void notifyListeners() {
096: // This method is implemented by making a clone of the set of listeners,
097: // and then iterating over the clone. This is because during the course
098: // of responding to a display change, it may be appropriate for a
099: // DisplayChangedListener to add or remove itself from a SunDisplayChanger.
100: // If the set itself were iterated over, rather than a clone, it is
101: // trivial to get a ConcurrentModificationException by having a
102: // DisplayChangedListener remove itself from its list.
103: // Because all display change handling is done on the event thread,
104: // synchronization provides no protection against modifying the listener
105: // list while in the middle of iterating over it. -bchristi 7/10/2001
106:
107: HashMap listClone;
108: Set cloneSet;
109:
110: synchronized (listeners) {
111: listClone = new HashMap(listeners);
112: }
113:
114: cloneSet = listClone.keySet();
115: Iterator itr = cloneSet.iterator();
116: while (itr.hasNext()) {
117: DisplayChangedListener current = (DisplayChangedListener) itr
118: .next();
119: try {
120: current.displayChanged();
121: } catch (IllegalComponentStateException e) {
122: // This DisplayChangeListener is no longer valid. Most
123: // likely, a top-level window was dispose()d, but its
124: // Java objects have not yet been garbage collected. In any
125: // case, we no longer need to track this listener, though we
126: // do need to remove it from the original list, not the clone.
127: listeners.remove(current);
128: }
129: }
130: }
131:
132: /*
133: * Notify our list of DisplayChangedListeners that a palette change has
134: * taken place by calling their paletteChanged() methods.
135: */
136: public void notifyPaletteChanged() {
137: // This method is implemented by making a clone of the set of listeners,
138: // and then iterating over the clone. This is because during the course
139: // of responding to a display change, it may be appropriate for a
140: // DisplayChangedListener to add or remove itself from a SunDisplayChanger.
141: // If the set itself were iterated over, rather than a clone, it is
142: // trivial to get a ConcurrentModificationException by having a
143: // DisplayChangedListener remove itself from its list.
144: // Because all display change handling is done on the event thread,
145: // synchronization provides no protection against modifying the listener
146: // list while in the middle of iterating over it. -bchristi 7/10/2001
147:
148: HashMap listClone;
149: Set cloneSet;
150:
151: synchronized (listeners) {
152: listClone = new HashMap(listeners);
153: }
154: cloneSet = listClone.keySet();
155: Iterator itr = cloneSet.iterator();
156: while (itr.hasNext()) {
157: DisplayChangedListener current = (DisplayChangedListener) itr
158: .next();
159: try {
160: current.paletteChanged();
161: } catch (IllegalComponentStateException e) {
162: // This DisplayChangeListener is no longer valid. Most
163: // likely, a top-level window was dispose()d, but its
164: // Java objects have not yet been garbage collected. In any
165: // case, we no longer need to track this listener, though we
166: // do need to remove it from the original list, not the clone.
167: listeners.remove(current);
168: }
169: }
170: }
171: }
|