OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [classpath/] [java/] [awt/] [EventQueue.java] - Blame information for rev 771

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 771 jeremybenn
/* EventQueue.java --
2
   Copyright (C) 1999, 2000, 2001, 2002, 2003, 2005  Free Software Foundation
3
 
4
This file is part of GNU Classpath.
5
 
6
GNU Classpath is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 2, or (at your option)
9
any later version.
10
 
11
GNU Classpath is distributed in the hope that it will be useful, but
12
WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
General Public License for more details.
15
 
16
You should have received a copy of the GNU General Public License
17
along with GNU Classpath; see the file COPYING.  If not, write to the
18
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
02110-1301 USA.
20
 
21
Linking this library statically or dynamically with other modules is
22
making a combined work based on this library.  Thus, the terms and
23
conditions of the GNU General Public License cover the whole
24
combination.
25
 
26
As a special exception, the copyright holders of this library give you
27
permission to link this library with independent modules to produce an
28
executable, regardless of the license terms of these independent
29
modules, and to copy and distribute the resulting executable under
30
terms of your choice, provided that you also meet, for each linked
31
independent module, the terms and conditions of the license of that
32
module.  An independent module is a module which is not derived from
33
or based on this library.  If you modify this library, you may extend
34
this exception to your version of the library, but you are not
35
obligated to do so.  If you do not wish to do so, delete this
36
exception statement from your version. */
37
 
38
 
39
package java.awt;
40
 
41
import gnu.java.awt.LowPriorityEvent;
42
import gnu.java.awt.peer.NativeEventLoopRunningEvent;
43
 
44
import java.awt.event.ActionEvent;
45
import java.awt.event.InputEvent;
46
import java.awt.event.InputMethodEvent;
47
import java.awt.event.InvocationEvent;
48
import java.awt.event.PaintEvent;
49
import java.awt.peer.ComponentPeer;
50
import java.awt.peer.LightweightPeer;
51
import java.lang.reflect.InvocationTargetException;
52
import java.util.EmptyStackException;
53
 
54
/* Written using on-line Java 2 Platform Standard Edition v1.3 API
55
 * Specification, as well as "The Java Class Libraries", 2nd edition
56
 * (Addison-Wesley, 1998).
57
 * Status:  Believed complete, but untested.
58
 */
59
 
60
/**
61
 * This class manages a queue of <code>AWTEvent</code> objects that
62
 * are posted to it.  The AWT system uses only one event queue for all
63
 * events.
64
 *
65
 * @author Bryce McKinlay
66
 * @author Aaron M. Renn (arenn@urbanophile.com)
67
 */
68
public class EventQueue
69
{
70
  /**
71
   * Indicates events that are processed with normal priority. This is normally
72
   * all events except PaintEvents.
73
   */
74
  private static final int NORM_PRIORITY = 0;
75
 
76
  /**
77
   * Indicates events that are processed with lowes priority. This is normally
78
   * all PaintEvents and LowPriorityEvents.
79
   */
80
  private static final int LOW_PRIORITY = 1;
81
 
82
  /**
83
   * Implements the actual queue. EventQueue has 2 internal queues for
84
   * different priorities:
85
   * 1 PaintEvents are always dispatched with low priority.
86
   * 2. All other events are dispatched with normal priority.
87
   *
88
   * This makes sure that the actual painting (output) is performed _after_ all
89
   * available input has been processed and that the paint regions are
90
   * coalesced as much as possible.
91
   */
92
  private class Queue
93
  {
94
    /**
95
     * The first item in the queue. This is where events are popped from.
96
     */
97
    AWTEvent queueHead;
98
 
99
    /**
100
     * The last item. This is where events are posted to.
101
     */
102
    AWTEvent queueTail;
103
  }
104
 
105
  /**
106
   * The three internal event queues.
107
   *
108
   * @see Queue
109
   */
110
  private Queue[] queues;
111
 
112
  private EventQueue next;
113
  private EventQueue prev;
114
  private AWTEvent currentEvent;
115
  private long lastWhen = System.currentTimeMillis();
116
 
117
  private EventDispatchThread dispatchThread = new EventDispatchThread(this);
118
  private boolean nativeLoopRunning = false;
119
 
120
  private boolean isShutdown ()
121
  {
122
    // This is the exact self-shutdown condition specified in J2SE:
123
    // http://java.sun.com/j2se/1.4.2/docs/api/java/awt/doc-files/AWTThreadIssues.html
124
 
125
    if (nativeLoopRunning)
126
      return false;
127
 
128
    if (peekEvent() != null)
129
      return false;
130
 
131
    if (Frame.hasDisplayableFrames())
132
      return false;
133
 
134
    return true;
135
  }
136
 
137
  /**
138
   * Initializes a new instance of <code>EventQueue</code>.
139
   */
140
  public EventQueue()
141
  {
142
    queues = new Queue[2];
143
    queues[NORM_PRIORITY] = new Queue();
144
    queues[LOW_PRIORITY] = new Queue();
145
  }
146
 
147
  /**
148
   * Returns the next event in the queue.  This method will block until
149
   * an event is available or until the thread is interrupted.
150
   *
151
   * @return The next event in the queue.
152
   *
153
   * @exception InterruptedException If this thread is interrupted while
154
   * waiting for an event to be posted to the queue.
155
   */
156
  public synchronized AWTEvent getNextEvent()
157
    throws InterruptedException
158
  {
159
    if (next != null)
160
      return next.getNextEvent();
161
 
162
    AWTEvent res = getNextEventImpl(true);
163
 
164
    while (res == null)
165
      {
166
        if (isShutdown())
167
          {
168
            // Explicitly set dispathThread to null.  If we don't do
169
            // this, there is a race condition where dispatchThread
170
            // can be != null even after the event dispatch thread has
171
            // stopped running.  If that happens, then the
172
            // dispatchThread == null check in postEventImpl will
173
            // fail, and a new event dispatch thread will not be
174
            // created, leaving invokeAndWaits waiting indefinitely.
175
            dispatchThread = null;
176
 
177
            // Interrupt the event dispatch thread.
178
            throw new InterruptedException();
179
          }
180
 
181
        wait();
182
        res = getNextEventImpl(true);
183
      }
184
 
185
    return res;
186
  }
187
 
188
  /**
189
   * Fetches and possibly removes the next event from the internal queues.
190
   * This method returns immediately. When all queues are empty, this returns
191
   * <code>null</code>:
192
   *
193
   * @param remove <true> when the event should be removed from the queue,
194
   *        <code>false</code> otherwise
195
   *
196
   * @return the next event or <code>null</code> when all internal queues
197
   *         are empty
198
   */
199
  private AWTEvent getNextEventImpl(boolean remove)
200
  {
201
    AWTEvent next = null;
202
    for (int i = 0; i < queues.length && next == null; i++)
203
      {
204
        Queue q = queues[i];
205
        if (q.queueHead != null)
206
          {
207
            // Got an event, remove it.
208
            next = q.queueHead;
209
            if (remove)
210
              {
211
                // Unlink event from the queue.
212
                q.queueHead = next.queueNext;
213
                if (q.queueHead == null)
214
                  q.queueTail = null;
215
                next.queueNext = null;
216
              }
217
          }
218
      }
219
    return next;
220
  }
221
 
222
  /**
223
   * Returns the next event in the queue without removing it from the queue.
224
   * This method will block until an event is available or until the thread
225
   * is interrupted.
226
   *
227
   * @return The next event in the queue.
228
   * @specnote Does not block. Returns null if there are no events on the
229
   *            queue.
230
   */
231
  public synchronized AWTEvent peekEvent()
232
  {
233
    if (next != null)
234
      return next.peekEvent();
235
 
236
    return getNextEventImpl(false);
237
  }
238
 
239
  /**
240
   * Returns the next event in the queue that has the specified id
241
   * without removing it from the queue.
242
   * This method will block until an event is available or until the thread
243
   * is interrupted.
244
   *
245
   * @param id The event id to return.
246
   *
247
   * @return The next event in the queue.
248
   *
249
   * @specnote Does not block. Returns null if there are no matching events
250
   *            on the queue.
251
   */
252
  public synchronized AWTEvent peekEvent(int id)
253
  {
254
    if (next != null)
255
      return next.peekEvent(id);
256
 
257
    AWTEvent evt = null;
258
    for (int i = 0; i < queues.length && evt == null; i++)
259
      {
260
        Queue q = queues[i];
261
        evt = q.queueHead;
262
        while (evt != null && evt.id != id)
263
          evt = evt.queueNext;
264
        // At this point we either have found an event (evt != null -> exit
265
        // for loop), or we have found no event (evt == null -> search next
266
        // internal queue).
267
      }
268
    return evt;
269
  }
270
 
271
  /**
272
   * Posts a new event to the queue.
273
   *
274
   * @param evt The event to post to the queue.
275
   *
276
   * @exception NullPointerException If event is null.
277
   */
278
  public void postEvent(AWTEvent evt)
279
  {
280
    postEventImpl(evt);
281
  }
282
 
283
  /**
284
   * Sorts events to their priority and calls
285
   * {@link #postEventImpl(AWTEvent, int)}.
286
   *
287
   * @param evt the event to post
288
   */
289
  private synchronized final void postEventImpl(AWTEvent evt)
290
  {
291
    int priority = NORM_PRIORITY;
292
    if (evt instanceof PaintEvent || evt instanceof LowPriorityEvent)
293
      priority = LOW_PRIORITY;
294
    // TODO: Maybe let Swing RepaintManager events also be processed with
295
    // low priority.
296
    if (evt instanceof NativeEventLoopRunningEvent)
297
      {
298
        nativeLoopRunning = ((NativeEventLoopRunningEvent) evt).isRunning();
299
        notify();
300
        return;
301
      }
302
    postEventImpl(evt, priority);
303
  }
304
 
305
  /**
306
   * Actually performs the event posting. This is needed because the
307
   * RI doesn't use the public postEvent() method when transferring events
308
   * between event queues in push() and pop().
309
   *
310
   * @param evt the event to post
311
   * @param priority the priority of the event
312
   */
313
  private final void postEventImpl(AWTEvent evt, int priority)
314
  {
315
    if (evt == null)
316
      throw new NullPointerException();
317
 
318
    if (next != null)
319
      {
320
        next.postEvent(evt);
321
        return;
322
      }
323
 
324
    Object source = evt.getSource();
325
 
326
    Queue q = queues[priority];
327
    if (source instanceof Component)
328
      {
329
        // For PaintEvents, ask the ComponentPeer to coalesce the event
330
        // when the component is heavyweight.
331
        Component comp = (Component) source;
332
        ComponentPeer peer = comp.peer;
333
        if (peer != null && evt instanceof PaintEvent
334
            && ! (peer instanceof LightweightPeer))
335
          peer.coalescePaintEvent((PaintEvent) evt);
336
 
337
        // Check for any events already on the queue with the same source
338
        // and ID.
339
        AWTEvent previous = null;
340
        for (AWTEvent qevt = q.queueHead; qevt != null; qevt = qevt.queueNext)
341
          {
342
            Object src = qevt.getSource();
343
            if (qevt.id == evt.id && src == comp)
344
              {
345
                // If there are, call coalesceEvents on the source component
346
                // to see if they can be combined.
347
                Component srccmp = (Component) src;
348
                AWTEvent coalescedEvt = srccmp.coalesceEvents(qevt, evt);
349
                if (coalescedEvt != null)
350
                  {
351
                    // Yes. Replace the existing event with the combined event.
352
                    if (qevt != coalescedEvt)
353
                      {
354
                        if (previous != null)
355
                          {
356
                            assert previous.queueNext == qevt;
357
                            previous.queueNext = coalescedEvt;
358
                          }
359
                        else
360
                          {
361
                            assert q.queueHead == qevt;
362
                            q.queueHead = coalescedEvt;
363
                          }
364
                        coalescedEvt.queueNext = qevt.queueNext;
365
                        if (q.queueTail == qevt)
366
                          q.queueTail = coalescedEvt;
367
                        qevt.queueNext = null;
368
                      }
369
                    return;
370
                  }
371
              }
372
            previous = qevt;
373
          }
374
      }
375
 
376
    if (q.queueHead == null)
377
      {
378
        // We have an empty queue. Set this event both as head and as tail.
379
        q.queueHead = evt;
380
        q.queueTail = evt;
381
      }
382
    else
383
      {
384
        // Note: queueTail should not be null here.
385
        q.queueTail.queueNext = evt;
386
        q.queueTail = evt;
387
      }
388
 
389
    if (dispatchThread == null || !dispatchThread.isAlive())
390
      {
391
        dispatchThread = new EventDispatchThread(this);
392
        dispatchThread.start();
393
      }
394
 
395
    notify();
396
  }
397
 
398
  /**
399
   * Causes runnable to have its run method called in the dispatch thread of the
400
   * EventQueue. This will happen after all pending events are processed. The
401
   * call blocks until this has happened. This method will throw an Error if
402
   * called from the event dispatcher thread.
403
   *
404
   * @exception InterruptedException If another thread has interrupted
405
   * this thread.
406
   * @exception InvocationTargetException If an exception is thrown when running
407
   * runnable.
408
   *
409
   * @since 1.2
410
   */
411
  public static void invokeAndWait(Runnable runnable)
412
    throws InterruptedException, InvocationTargetException
413
  {
414
    if (isDispatchThread ())
415
      throw new Error("Can't call invokeAndWait from event dispatch thread");
416
 
417
    EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue();
418
    Object notifyObject = new Object();
419
 
420
    InvocationEvent ie =
421
      new InvocationEvent(eq, runnable, notifyObject, true);
422
 
423
    synchronized (notifyObject)
424
      {
425
        eq.postEvent(ie);
426
        notifyObject.wait();
427
      }
428
 
429
    Exception exception;
430
 
431
    if ((exception = ie.getException()) != null)
432
      throw new InvocationTargetException(exception);
433
  }
434
 
435
  /**
436
   * This arranges for runnable to have its run method called in the
437
   * dispatch thread of the EventQueue.  This will happen after all
438
   * pending events are processed.
439
   *
440
   * @since 1.2
441
   */
442
  public static void invokeLater(Runnable runnable)
443
  {
444
    EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue();
445
 
446
    InvocationEvent ie =
447
      new InvocationEvent(eq, runnable, null, false);
448
 
449
    eq.postEvent(ie);
450
  }
451
 
452
  /**
453
   * Return true if the current thread is the current AWT event dispatch
454
   * thread.
455
   */
456
  public static boolean isDispatchThread()
457
  {
458
    EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue();
459
 
460
    /* Find last EventQueue in chain */
461
    while (eq.next != null)
462
      eq = eq.next;
463
 
464
    return (Thread.currentThread() == eq.dispatchThread);
465
  }
466
 
467
  /**
468
   * Return the event currently being dispatched by the event
469
   * dispatch thread.  If the current thread is not the event
470
   * dispatch thread, this method returns null.
471
   *
472
   * @since 1.4
473
   */
474
  public static AWTEvent getCurrentEvent()
475
  {
476
    EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue();
477
    Thread ct = Thread.currentThread();
478
 
479
    /* Find out if this thread is the dispatch thread for any of the
480
       EventQueues in the chain */
481
    while (ct != eq.dispatchThread)
482
      {
483
        // Try next EventQueue, if any
484
        if (eq.next == null)
485
           return null;  // Not an event dispatch thread
486
        eq = eq.next;
487
      }
488
 
489
    return eq.currentEvent;
490
  }
491
 
492
  /**
493
   * Allows a custom EventQueue implementation to replace this one.
494
   * All pending events are transferred to the new queue. Calls to postEvent,
495
   * getNextEvent, and peekEvent and others are forwarded to the pushed queue
496
   * until it is removed with a pop().
497
   *
498
   * @exception NullPointerException if newEventQueue is null.
499
   */
500
  public synchronized void push(EventQueue newEventQueue)
501
  {
502
    if (newEventQueue == null)
503
      throw new NullPointerException ();
504
 
505
    /* Make sure we are at the top of the stack because callers can
506
       only get a reference to the one at the bottom using
507
       Toolkit.getDefaultToolkit().getSystemEventQueue() */
508
    if (next != null)
509
      {
510
        next.push (newEventQueue);
511
        return;
512
      }
513
 
514
    /* Make sure we have a live dispatch thread to drive the queue */
515
    if (dispatchThread == null)
516
      dispatchThread = new EventDispatchThread(this);
517
 
518
    synchronized (newEventQueue)
519
      {
520
        // The RI transfers the events without calling the new eventqueue's
521
        // push(), but using getNextEvent().
522
        while (peekEvent() != null)
523
          {
524
            try
525
              {
526
                newEventQueue.postEventImpl(getNextEvent());
527
              }
528
            catch (InterruptedException ex)
529
              {
530
                // What should we do with this?
531
                ex.printStackTrace();
532
              }
533
          }
534
        newEventQueue.prev = this;
535
      }
536
 
537
    next = newEventQueue;
538
  }
539
 
540
  /** Transfer any pending events from this queue back to the parent queue that
541
    * was previously push()ed. Event dispatch from this queue is suspended.
542
    *
543
    * @exception EmptyStackException If no previous push was made on this
544
    * EventQueue.
545
    */
546
  protected void pop() throws EmptyStackException
547
  {
548
    /* The order is important here, we must get the prev lock first,
549
       or deadlock could occur as callers usually get here following
550
       prev's next pointer, and thus obtain prev's lock before trying
551
       to get this lock. */
552
    EventQueue previous = prev;
553
    if (previous == null)
554
      throw new EmptyStackException();
555
    synchronized (previous)
556
      {
557
        synchronized (this)
558
          {
559
            EventQueue nextQueue = next;
560
            if (nextQueue != null)
561
              {
562
                nextQueue.pop();
563
              }
564
            else
565
              {
566
                previous.next = null;
567
 
568
                // The RI transfers the events without calling the new eventqueue's
569
                // push(), so this should be OK and most effective.
570
                while (peekEvent() != null)
571
                  {
572
                    try
573
                      {
574
                        previous.postEventImpl(getNextEvent());
575
                      }
576
                    catch (InterruptedException ex)
577
                      {
578
                        // What should we do with this?
579
                        ex.printStackTrace();
580
                      }
581
                  }
582
                prev = null;
583
                // Tell our EventDispatchThread that it can end
584
                // execution.
585
                if (dispatchThread != null)
586
                  {
587
                    dispatchThread.interrupt();
588
                    dispatchThread = null;
589
                  }
590
              }
591
          }
592
      }
593
  }
594
 
595
  /**
596
   * Dispatches an event. The manner in which the event is dispatched depends
597
   * upon the type of the event and the type of the event's source object.
598
   *
599
   * @exception NullPointerException If event is null.
600
   */
601
  protected void dispatchEvent(AWTEvent evt)
602
  {
603
    currentEvent = evt;
604
 
605
    if (evt instanceof InputEvent)
606
      lastWhen = ((InputEvent) evt).getWhen();
607
    else if (evt instanceof ActionEvent)
608
      lastWhen = ((ActionEvent) evt).getWhen();
609
    else if (evt instanceof InvocationEvent)
610
      lastWhen = ((InvocationEvent) evt).getWhen();
611
 
612
    if (evt instanceof ActiveEvent)
613
      {
614
        ActiveEvent active_evt = (ActiveEvent) evt;
615
        active_evt.dispatch();
616
      }
617
    else
618
      {
619
        Object source = evt.getSource();
620
 
621
        if (source instanceof Component)
622
          {
623
            Component srccmp = (Component) source;
624
            srccmp.dispatchEvent(evt);
625
          }
626
        else if (source instanceof MenuComponent)
627
          {
628
            MenuComponent srccmp = (MenuComponent) source;
629
            srccmp.dispatchEvent(evt);
630
          }
631
      }
632
  }
633
 
634
  /**
635
   * Returns the timestamp of the most recent event that had a timestamp, or
636
   * the initialization time of the event queue if no events have been fired.
637
   * At present, only <code>InputEvent</code>s, <code>ActionEvent</code>s,
638
   * <code>InputMethodEvent</code>s, and <code>InvocationEvent</code>s have
639
   * timestamps, but this may be added to other events in future versions.
640
   * If this is called by the event dispatching thread, it can be any
641
   * (sequential) value, but to other threads, the safest bet is to return
642
   * System.currentTimeMillis().
643
   *
644
   * @return the most recent timestamp
645
   * @see InputEvent#getWhen()
646
   * @see ActionEvent#getWhen()
647
   * @see InvocationEvent#getWhen()
648
   * @see InputMethodEvent#getWhen()
649
   * @since 1.4
650
   */
651
  public static long getMostRecentEventTime()
652
  {
653
    EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue();
654
    if (Thread.currentThread() != eq.dispatchThread)
655
      return System.currentTimeMillis();
656
    return eq.lastWhen;
657
  }
658
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.