267 handler.handleOpenApp(); |
269 handler.handleOpenApp(); |
268 } |
270 } |
269 } |
271 } |
270 |
272 |
271 class _AppReOpenedDispatcher extends _AppEventMultiplexor<AppReOpenedListener> { |
273 class _AppReOpenedDispatcher extends _AppEventMultiplexor<AppReOpenedListener> { |
272 void performOnListeners(final List<AppReOpenedListener> listeners, final _NativeEvent event) { |
274 void performOnListener(AppReOpenedListener listener, final _NativeEvent event) { |
273 final AppReOpenedEvent e = new AppReOpenedEvent(); |
275 final AppReOpenedEvent e = new AppReOpenedEvent(); |
274 for (final AppReOpenedListener listener : listeners) { |
276 listener.appReOpened(e); |
275 listener.appReOpened(e); |
|
276 } |
|
277 } |
277 } |
278 } |
278 } |
279 |
279 |
280 class _AppForegroundDispatcher extends _BooleanAppEventMultiplexor<AppForegroundListener, AppForegroundEvent> { |
280 class _AppForegroundDispatcher extends _BooleanAppEventMultiplexor<AppForegroundListener, AppForegroundEvent> { |
281 AppForegroundEvent createEvent(final boolean isTrue) { return new AppForegroundEvent(); } |
281 AppForegroundEvent createEvent(final boolean isTrue) { return new AppForegroundEvent(); } |
413 return (T)args[i]; |
413 return (T)args[i]; |
414 } |
414 } |
415 } |
415 } |
416 |
416 |
417 abstract class _AppEventMultiplexor<L> { |
417 abstract class _AppEventMultiplexor<L> { |
418 final List<L> _listeners = new ArrayList<L>(0); |
418 private final Map<L, AppContext> listenerToAppContext = |
|
419 new IdentityHashMap<L, AppContext>(); |
419 boolean nativeListenerRegistered; |
420 boolean nativeListenerRegistered; |
420 |
421 |
421 // called from AppKit Thread-0 |
422 // called from AppKit Thread-0 |
422 void dispatch(final _NativeEvent event, final Object... args) { |
423 void dispatch(final _NativeEvent event, final Object... args) { |
423 // grab a local ref to the listeners |
424 // grab a local ref to the listeners and its contexts as an array of the map's entries |
424 final List<L> localListeners; |
425 final ArrayList<Map.Entry<L, AppContext>> localEntries; |
425 synchronized (this) { |
426 synchronized (this) { |
426 if (_listeners.size() == 0) return; |
427 if (listenerToAppContext.size() == 0) { |
427 localListeners = new ArrayList<L>(_listeners); |
428 return; |
428 } |
|
429 |
|
430 EventQueue.invokeLater(new Runnable() { |
|
431 public void run() { |
|
432 performOnListeners(localListeners, event); |
|
433 } |
429 } |
434 }); |
430 localEntries = new ArrayList<Map.Entry<L, AppContext>>(listenerToAppContext.size()); |
|
431 localEntries.addAll(listenerToAppContext.entrySet()); |
|
432 } |
|
433 |
|
434 for (final Map.Entry<L, AppContext> e : localEntries) { |
|
435 final L listener = e.getKey(); |
|
436 final AppContext listenerContext = e.getValue(); |
|
437 SunToolkit.invokeLaterOnAppContext(listenerContext, new Runnable() { |
|
438 public void run() { |
|
439 performOnListener(listener, event); |
|
440 } |
|
441 }); |
|
442 } |
435 } |
443 } |
436 |
444 |
437 synchronized void addListener(final L listener) { |
445 synchronized void addListener(final L listener) { |
|
446 setListenerContext(listener, AppContext.getAppContext()); |
|
447 |
438 if (!nativeListenerRegistered) { |
448 if (!nativeListenerRegistered) { |
439 registerNativeListener(); |
449 registerNativeListener(); |
440 nativeListenerRegistered = true; |
450 nativeListenerRegistered = true; |
441 } |
451 } |
442 _listeners.add(listener); |
|
443 } |
452 } |
444 |
453 |
445 synchronized void removeListener(final L listener) { |
454 synchronized void removeListener(final L listener) { |
446 _listeners.remove(listener); |
455 listenerToAppContext.remove(listener); |
447 } |
456 } |
448 |
457 |
449 abstract void performOnListeners(final List<L> listeners, final _NativeEvent event); |
458 abstract void performOnListener(L listener, final _NativeEvent event); |
450 void registerNativeListener() { } |
459 void registerNativeListener() { } |
|
460 |
|
461 private void setListenerContext(L listener, AppContext listenerContext) { |
|
462 if (listenerContext == null) { |
|
463 throw new RuntimeException( |
|
464 "Attempting to add a listener from a thread group without AppContext"); |
|
465 } |
|
466 listenerToAppContext.put(listener, AppContext.getAppContext()); |
|
467 } |
451 } |
468 } |
452 |
469 |
453 abstract class _BooleanAppEventMultiplexor<L, E> extends _AppEventMultiplexor<L> { |
470 abstract class _BooleanAppEventMultiplexor<L, E> extends _AppEventMultiplexor<L> { |
454 @Override |
471 @Override |
455 void performOnListeners(final List<L> listeners, final _NativeEvent event) { |
472 void performOnListener(L listener, final _NativeEvent event) { |
456 final boolean isTrue = Boolean.TRUE.equals(event.get(0)); |
473 final boolean isTrue = Boolean.TRUE.equals(event.get(0)); |
457 final E e = createEvent(isTrue); |
474 final E e = createEvent(isTrue); |
458 if (isTrue) { |
475 if (isTrue) { |
459 for (final L listener : listeners) performTrueEventOn(listener, e); |
476 performTrueEventOn(listener, e); |
460 } else { |
477 } else { |
461 for (final L listener : listeners) performFalseEventOn(listener, e); |
478 performFalseEventOn(listener, e); |
462 } |
479 } |
463 } |
480 } |
464 |
481 |
465 abstract E createEvent(final boolean isTrue); |
482 abstract E createEvent(final boolean isTrue); |
466 abstract void performTrueEventOn(final L listener, final E e); |
483 abstract void performTrueEventOn(final L listener, final E e); |
477 * |
494 * |
478 * User code is not (and should not be) run under any synchronized lock. |
495 * User code is not (and should not be) run under any synchronized lock. |
479 */ |
496 */ |
480 abstract class _AppEventDispatcher<H> { |
497 abstract class _AppEventDispatcher<H> { |
481 H _handler; |
498 H _handler; |
|
499 AppContext handlerContext; |
482 |
500 |
483 // called from AppKit Thread-0 |
501 // called from AppKit Thread-0 |
484 void dispatch(final _NativeEvent event) { |
502 void dispatch(final _NativeEvent event) { |
485 EventQueue.invokeLater(new Runnable() { |
503 // grab a local ref to the handler |
486 public void run() { |
504 final H localHandler; |
487 // grab a local ref to the handler |
505 final AppContext localHandlerContext; |
488 final H localHandler; |
506 synchronized (_AppEventDispatcher.this) { |
489 synchronized (_AppEventDispatcher.this) { |
507 localHandler = _handler; |
490 localHandler = _handler; |
508 localHandlerContext = handlerContext; |
491 } |
509 } |
492 |
510 |
493 // invoke the handler outside of the synchronized block |
511 if (localHandler == null) { |
494 if (localHandler == null) { |
512 performDefaultAction(event); |
495 performDefaultAction(event); |
513 } else { |
496 } else { |
514 SunToolkit.invokeLaterOnAppContext(localHandlerContext, new Runnable() { |
|
515 public void run() { |
497 performUsing(localHandler, event); |
516 performUsing(localHandler, event); |
498 } |
517 } |
499 } |
518 }); |
500 }); |
519 } |
501 } |
520 } |
502 |
521 |
503 synchronized void setHandler(final H handler) { |
522 synchronized void setHandler(final H handler) { |
504 this._handler = handler; |
523 this._handler = handler; |
|
524 |
|
525 setHandlerContext(AppContext.getAppContext()); |
505 |
526 |
506 // if a new handler is installed, block addition of legacy ApplicationListeners |
527 // if a new handler is installed, block addition of legacy ApplicationListeners |
507 if (handler == legacyHandler) return; |
528 if (handler == legacyHandler) return; |
508 legacyHandler.blockLegacyAPI(); |
529 legacyHandler.blockLegacyAPI(); |
509 } |
530 } |
510 |
531 |
511 void performDefaultAction(final _NativeEvent event) { } // by default, do nothing |
532 void performDefaultAction(final _NativeEvent event) { } // by default, do nothing |
512 abstract void performUsing(final H handler, final _NativeEvent event); |
533 abstract void performUsing(final H handler, final _NativeEvent event); |
|
534 |
|
535 protected void setHandlerContext(AppContext ctx) { |
|
536 if (ctx == null) { |
|
537 throw new RuntimeException( |
|
538 "Attempting to set a handler from a thread group without AppContext"); |
|
539 } |
|
540 |
|
541 handlerContext = ctx; |
|
542 } |
513 } |
543 } |
514 |
544 |
515 abstract class _QueuingAppEventDispatcher<H> extends _AppEventDispatcher<H> { |
545 abstract class _QueuingAppEventDispatcher<H> extends _AppEventDispatcher<H> { |
516 List<_NativeEvent> queuedEvents = new LinkedList<_NativeEvent>(); |
546 List<_NativeEvent> queuedEvents = new LinkedList<_NativeEvent>(); |
517 |
547 |