1 /*
2  * Copyright (c) 2007, 2013, 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 sun.java2d.pipe.hw;
27 
28 import java.util.Collections;
29 import java.util.HashMap;
30 import java.util.Iterator;
31 import java.util.Map;
32 import java.util.Set;
33 import java.lang.annotation.Native;
34 
35 
36 /**
37  * This class is used to notify listeners about accelerated device's
38  * events such as device reset or dispose that are about to occur.
39  */
40 public class AccelDeviceEventNotifier {
41 
42     private static AccelDeviceEventNotifier theInstance;
43 
44     /**
45      * A device is about to be reset. The listeners have to release all
46      * resources associated with the device which are required for the device
47      * to be reset.
48      */
49     @Native public static final int DEVICE_RESET = 0;
50 
51     /**
52      * A device is about to be disposed. The listeners have to release all
53      * resources associated with the device.
54      */
55     @Native public static final int DEVICE_DISPOSED = 1;
56 
57     private final Map<AccelDeviceEventListener, Integer> listeners;
58 
AccelDeviceEventNotifier()59     private AccelDeviceEventNotifier() {
60         listeners = Collections.synchronizedMap(
61             new HashMap<AccelDeviceEventListener, Integer>(1));
62     }
63 
64     /**
65      * Returns a singleton of AccelDeviceEventNotifier if it exists. If the
66      * passed boolean is false and singleton doesn't exist yet, null is
67      * returned. If the passed boolean is {@code true} and singleton doesn't
68      * exist it will be created and returned.
69      *
70      * @param create whether to create a singleton instance if doesn't yet
71      * exist
72      * @return a singleton instance or null
73      */
74     private static synchronized
getInstance(boolean create)75         AccelDeviceEventNotifier getInstance(boolean create)
76     {
77         if (theInstance == null && create) {
78             theInstance = new AccelDeviceEventNotifier();
79         }
80         return theInstance;
81     }
82 
83     /**
84      * Called to indicate that a device event had occurred.
85      * If a singleton exists, the listeners (those associated with
86      * the device) will be notified.
87      *
88      * @param screen a screen number of the device which is a source of
89      * the event
90      * @param eventType a type of the event
91      * @see #DEVICE_DISPOSED
92      * @see #DEVICE_RESET
93      */
eventOccured(int screen, int eventType)94     public static final void eventOccured(int screen, int eventType) {
95         AccelDeviceEventNotifier notifier = getInstance(false);
96         if (notifier != null) {
97             notifier.notifyListeners(eventType, screen);
98         }
99     }
100 
101     /**
102      * Adds the listener associated with a device on particular screen.
103      *
104      * Note: the listener must be removed as otherwise it will forever
105      * be referenced by the notifier.
106      *
107      * @param l the listener
108      * @param screen the screen number indicating which device the listener is
109      * interested in.
110      */
addListener(AccelDeviceEventListener l,int screen)111     public static final void addListener(AccelDeviceEventListener l,int screen){
112         getInstance(true).add(l, screen);
113     }
114 
115     /**
116      * Removes the listener.
117      *
118      * @param l the listener
119      */
removeListener(AccelDeviceEventListener l)120     public static final void removeListener(AccelDeviceEventListener l) {
121         getInstance(true).remove(l);
122     }
123 
add(AccelDeviceEventListener theListener, int screen)124     private final void add(AccelDeviceEventListener theListener, int screen) {
125         listeners.put(theListener, screen);
126     }
remove(AccelDeviceEventListener theListener)127     private final void remove(AccelDeviceEventListener theListener) {
128         listeners.remove(theListener);
129     }
130 
131     /**
132      * Notifies the listeners associated with the screen's device about the
133      * event.
134      *
135      * Implementation note: the current list of listeners is first duplicated
136      * which allows the listeners to remove themselves during the iteration.
137      *
138      * @param screen a screen number with which the device which is a source of
139      * the event is associated with
140      * @param eventType a type of the event
141      * @see #DEVICE_DISPOSED
142      * @see #DEVICE_RESET
143      */
notifyListeners(int deviceEventType, int screen)144     private final void notifyListeners(int deviceEventType, int screen) {
145         HashMap<AccelDeviceEventListener, Integer> listClone;
146         Set<AccelDeviceEventListener> cloneSet;
147 
148         synchronized(listeners) {
149             listClone =
150                 new HashMap<AccelDeviceEventListener, Integer>(listeners);
151         }
152 
153         cloneSet = listClone.keySet();
154         Iterator<AccelDeviceEventListener> itr = cloneSet.iterator();
155         while (itr.hasNext()) {
156             AccelDeviceEventListener current = itr.next();
157             Integer i = listClone.get(current);
158             // only notify listeners which are interested in this device
159             if (i != null && i.intValue() != screen) {
160                 continue;
161             }
162             if (deviceEventType == DEVICE_RESET) {
163                 current.onDeviceReset();
164             } else if (deviceEventType == DEVICE_DISPOSED) {
165                 current.onDeviceDispose();
166             }
167         }
168     }
169 }
170