001: /*
002: *
003: *
004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: */
026:
027: package com.sun.midp.lcdui;
028:
029: import com.sun.midp.events.EventTypes;
030: import com.sun.midp.events.Event;
031: import com.sun.midp.events.EventListener;
032: import com.sun.midp.events.EventQueue;
033:
034: import com.sun.midp.security.Permissions;
035: import com.sun.midp.security.SecurityToken;
036:
037: import javax.microedition.lcdui.Display;
038:
039: /**
040: * This class performs all of the repaint event handling.
041: */
042: public class RepaintEventProducer implements EventListener {
043:
044: /** Cached reference to the MIDP event queue. */
045: private EventQueue eventQueue;
046:
047: /** Repaint event free for reuse. */
048: private RepaintEvent pooledEvent1;
049: /** Repaint event free for reuse. */
050: private RepaintEvent pooledEvent2;
051: /** Repaint event free for reuse. */
052: private RepaintEvent pooledEvent3;
053:
054: /**
055: * Repaint event in the queue or waiting to be moved to the processed
056: * slot. Events are rotated to different slots in
057: * <code>preprocessRepaints</code>.
058: */
059: private RepaintEvent queuedEvent;
060:
061: /**
062: * Repaint event being processed (queue has event also) or
063: * has been processed (no event in the queue).
064: */
065: private RepaintEvent eventInProcess;
066:
067: /**
068: * The constructor LCDUI repaint events handler.
069: *
070: * @param theEventQueue the event queue
071: */
072: public RepaintEventProducer(EventQueue theEventQueue) {
073:
074: eventQueue = theEventQueue;
075:
076: pooledEvent1 = RepaintEvent.createRepaintEvent(null, 0, 0, 0,
077: 0, null);
078: pooledEvent2 = RepaintEvent.createRepaintEvent(null, 0, 0, 0,
079: 0, null);
080: pooledEvent3 = RepaintEvent.createRepaintEvent(null, 0, 0, 0,
081: 0, null);
082:
083: eventQueue
084: .registerEventListener(EventTypes.REPAINT_EVENT, this );
085: }
086:
087: /**
088: * Called to schedule a repaint of the current Displayable
089: * as soon as possible.
090: *
091: * @param d The Display
092: * @param x The x coordinate of the origin of the repaint rectangle
093: * @param y The y coordinate of the origin of the repaint rectangle
094: * @param w The width of the repaint rectangle
095: * @param h The height of the repaint rectangle
096: * @param target An optional target Object, which may have been the
097: * original requestor for the repaint
098: */
099: public void scheduleRepaint(DisplayEventConsumer d, int x, int y,
100: int w, int h, Object target) {
101: RepaintEvent freeEvent;
102:
103: synchronized (this ) {
104: freeEvent = pooledEvent1;
105:
106: freeEvent.setRepaintFields(d, x, y, w, h, target);
107:
108: if (queuedEvent == null) {
109: /*
110: * Since the queue does not lock posting during event
111: * processing, we need to rotate 3 repaint events for reuse.
112: *
113: * 1 for the queued event, 1 for the event begin processed
114: * and 1 for temporary use when merging a new event with
115: * a queued event.
116: *
117: * Event pooling is done because game can generate upto 15
118: * repaints a second and cause a lot garbage collection if
119: * we created new repaint every time.
120: */
121: pooledEvent1 = pooledEvent2;
122: pooledEvent2 = pooledEvent3;
123: pooledEvent3 = freeEvent;
124:
125: queuedEvent = freeEvent;
126:
127: eventQueue.post(queuedEvent);
128: } else if (queuedEvent.display != d) {
129: /*
130: * A new display has come to the foreground so don't
131: * bother paint the display in the queued event.
132: *
133: * Overwrite this fields in queue event with new values.
134: */
135: queuedEvent.setRepaintFields(d, x, y, w, h, target);
136: } else {
137: /*
138: * When there is a pending repaint
139: * union the dirty regions into one event
140: */
141: if (queuedEvent.paintX1 > freeEvent.paintX1) {
142: queuedEvent.paintX1 = freeEvent.paintX1;
143: }
144:
145: if (queuedEvent.paintY1 > freeEvent.paintY1) {
146: queuedEvent.paintY1 = freeEvent.paintY1;
147: }
148:
149: if (queuedEvent.paintX2 < freeEvent.paintX2) {
150: queuedEvent.paintX2 = freeEvent.paintX2;
151: }
152:
153: if (queuedEvent.paintY2 < freeEvent.paintY2) {
154: queuedEvent.paintY2 = freeEvent.paintY2;
155: }
156:
157: queuedEvent.paintTarget = null;
158: }
159: }
160: }
161:
162: /**
163: * Preprocess an event that is being posted to the event queue.
164: *
165: * @param event event being posted
166: *
167: * @param waitingEvent previous event of this type waiting in the
168: * queue to be processed
169: *
170: * @return true to allow the post to continue, false to not post the
171: * event to the queue
172: */
173: public boolean preprocess(Event event, Event waitingEvent) {
174: /*
175: * Because of the needs of serviceRepaints the preprocessing
176: * is done in scheduleRepaint.
177: */
178: return true;
179: }
180:
181: /**
182: * Process an event.
183: *
184: * @param genericEvent event to process
185: */
186: public void process(Event genericEvent) {
187: RepaintEvent event = (RepaintEvent) genericEvent;
188:
189: synchronized (this ) {
190: queuedEvent = null;
191: eventInProcess = event;
192: }
193:
194: /*
195: * Target DisplayEventConsumer is obtained directly from event field.
196: * Assumed that target consumer is not null.
197: */
198: event.display.handleRepaintEvent(event.paintX1, event.paintY1,
199: event.paintX2, event.paintY2, event.paintTarget);
200:
201: synchronized (this ) {
202: /* Change the ID here to signal waitForRepaint. */
203: eventInProcess.perUseID++;
204:
205: eventInProcess = null;
206:
207: // ServiceRepaints may be blocking.
208: notifyAll();
209: }
210: }
211:
212: /**
213: * Called to block the calling MIDlet until the the pending repaint
214: * operation is performed.
215: * <p>
216: * Does not return until the pending repaint (if any)
217: * has been processed.</p>
218: *
219: */
220: public void serviceRepaints() {
221: if (EventQueue.isDispatchThread()) {
222: Event event;
223:
224: if (eventInProcess != null) {
225: /*
226: * We are in the midst of a calling the application's
227: * paint method, avoid recursion, simply return
228: */
229: return;
230: }
231:
232: /*
233: * Since we are in the dispatch thread, at this point
234: * there can only one repaint in the queue so remove it
235: * from the queue and process it.
236: */
237: event = eventQueue.remove(EventTypes.REPAINT_EVENT);
238:
239: /* Do not hold a lock when calling out to the application */
240: if (event != null) {
241: process(event);
242: }
243: } else {
244: /*
245: * We only want paint events to be process in the dispatch
246: * to avoid deadlocks. So wait for the repaint event to occur.
247: */
248: waitForCurrentRepaintEvents();
249: }
250: }
251:
252: /**
253: * Wait for the event queue to process all of the events currently
254: * in the queue but not any new ones after the start of this
255: * method.
256: */
257: private void waitForCurrentRepaintEvents() {
258: RepaintEvent eventToWaitFor = null;
259: int currentEventUseID;
260:
261: synchronized (this ) {
262: if (queuedEvent != null) {
263: eventToWaitFor = queuedEvent;
264: } else if (eventInProcess != null) {
265: eventToWaitFor = eventInProcess;
266: } else {
267: /* Nothing to wait for, done. */
268: return;
269: }
270:
271: currentEventUseID = eventToWaitFor.perUseID;
272: while (eventToWaitFor.perUseID == currentEventUseID) {
273: try {
274: wait();
275: } catch (InterruptedException ie) {
276: /* The application wants this thread to unblock */
277: break;
278: }
279: }
280:
281: }
282: }
283: }
|