src/macosx/classes/sun/lwawt/macosx/LWCToolkit.java

Print this page




  47 
  48 class NamedCursor extends Cursor {
  49     NamedCursor(String name) {
  50         super(name);
  51     }
  52 }
  53 
  54 /**
  55  * Mac OS X Cocoa-based AWT Toolkit.
  56  */
  57 public class LWCToolkit extends LWToolkit {
  58     // While it is possible to enumerate all mouse devices
  59     // and query them for the number of buttons, the code
  60     // that does it is rather complex. Instead, we opt for
  61     // the easy way and just support up to 5 mouse buttons,
  62     // like Windows.
  63     private static final int BUTTONS = 5;
  64 
  65     private static native void initIDs();
  66 
  67     // On Mac OS we don't need to actually start the new event loop since there is
  68     // a mechanic that allows us to just reschedule the next event in a native event loop
  69     // for immediate execution and because this method is being called repeatedly we just
  70     // executing one such event every time we call this method
  71     static native void startNativeNestedEventLoop();
  72 
  73     // Since we don't start an additional event loop this method is a no-op
  74     // and shouldn't be called, left only for the better understanding of the concept on
  75     // other OS'es
  76     static native void stopNativeNestedEventLoop();
  77 
  78     private static CInputMethodDescriptor sInputMethodDescriptor;
  79 
  80     static {
  81         System.err.flush();
  82         java.security.AccessController.doPrivileged(new java.security.PrivilegedAction<Object>() {
  83             public Object run() {
  84                 System.loadLibrary("awt");
  85                 System.loadLibrary("fontmanager");
  86                 return null;
  87             }
  88         });
  89         if (!GraphicsEnvironment.isHeadless()) {
  90             initIDs();
  91         }
  92     }
  93 
  94     public LWCToolkit() {
  95         SunToolkit.setDataTransfererClassName("sun.lwawt.macosx.CDataTransferer");
  96 
  97         areExtraMouseButtonsEnabled = Boolean.parseBoolean(System.getProperty("sun.awt.enableExtraMouseButtons", "true"));


 488     static final String nsImagePrefix = "NSImage://";
 489     protected Image checkForNSImage(final String imageName) {
 490         if (imageName == null) return null;
 491         if (!imageName.startsWith(nsImagePrefix)) return null;
 492         return CImage.getCreator().createImageFromName(imageName.substring(nsImagePrefix.length()));
 493     }
 494 
 495     // Thread-safe Object.equals() called from native
 496     public static boolean doEquals(final Object a, final Object b, Component c) {
 497         if (a == b) return true;
 498 
 499         final boolean[] ret = new boolean[1];
 500 
 501         try {  invokeAndWait(new Runnable() { public void run() { synchronized(ret) {
 502             ret[0] = a.equals(b);
 503         }}}, c); } catch (Exception e) { e.printStackTrace(); }
 504 
 505         synchronized(ret) { return ret[0]; }
 506     }
 507 
 508     /**
 509      * Just a wrapper for LWCToolkit.invokeAndWait. Posts an empty event to the
 510      * appropriate event queue and waits for it to finish.
 511      */
 512     public static void flushPendingEventsOnAppkit(final Component component) {
 513         try {
 514             invokeAndWait(new Runnable() {
 515                 @Override
 516                 public void run() {
 517                 }
 518             }, component);
 519         } catch (Exception e) {
 520             e.printStackTrace();
 521         }
 522     }
 523 
 524     // Kicks an event over to the appropriate eventqueue and waits for it to finish
 525     // To avoid deadlocking, we manually run the NSRunLoop while waiting
 526     // Any selector invoked using ThreadUtilities performOnMainThread will be processed in doAWTRunLoop
 527     // The CInvocationEvent will call LWCToolkit.stopAWTRunLoop() when finished, which will stop our manual runloop
 528     public static void invokeAndWait(Runnable event, Component component) throws InterruptedException, InvocationTargetException {
 529         invokeAndWait(event, component, true);
 530     }
 531 
 532     public static <T> T invokeAndWait(final Callable<T> callable, Component component) throws Exception {
 533         final CallableWrapper<T> wrapper = new CallableWrapper<T>(callable);
 534         invokeAndWait(wrapper, component);
 535         return wrapper.getResult();
 536     }
 537 
 538     static final class CallableWrapper<T> implements Runnable {
 539         final Callable<T> callable;
 540         T object;
 541         Exception e;
 542 
 543         public CallableWrapper(final Callable<T> callable) {
 544             this.callable = callable;
 545         }
 546 
 547         public void run() {
 548             try {
 549                 object = callable.call();
 550             } catch (final Exception e) {
 551                 this.e = e;
 552             }
 553         }
 554 
 555         public T getResult() throws Exception {
 556             if (e != null) throw e;
 557             return object;
 558         }
 559     }
 560 
 561     public static void invokeAndWait(Runnable event, Component component, boolean detectDeadlocks) throws InterruptedException, InvocationTargetException {
 562         long mediator = createAWTRunLoopMediator();





 563 
 564         InvocationEvent invocationEvent = new CPeerEvent(event, mediator);












 565 
 566         if (component != null) {
 567             AppContext appContext = SunToolkit.targetToAppContext(component);
 568             SunToolkit.postEvent(appContext, invocationEvent);
 569 
 570             // 3746956 - flush events from PostEventQueue to prevent them from getting stuck and causing a deadlock
 571             sun.awt.SunToolkitSubclass.flushPendingEvents(appContext);
 572         } else {
 573             // This should be the equivalent to EventQueue.invokeAndWait
 574             ((LWCToolkit)Toolkit.getDefaultToolkit()).getSystemEventQueueForInvokeAndWait().postEvent(invocationEvent);
 575         }
 576 
 577         doAWTRunLoop(mediator, true, detectDeadlocks);
 578 
 579         Throwable eventException = invocationEvent.getException();
 580         if (eventException != null) {
 581             if (eventException instanceof UndeclaredThrowableException) {
 582                 eventException = ((UndeclaredThrowableException)eventException).getUndeclaredThrowable();
 583             }
 584             throw new InvocationTargetException(eventException);
 585         }
 586     }
 587 
 588     public static void invokeLater(Runnable event, Component component) throws InvocationTargetException {
 589         final InvocationEvent invocationEvent = new CPeerEvent(event, 0);

 590 
 591         if (component != null) {
 592             final AppContext appContext = SunToolkit.targetToAppContext(component);
 593             SunToolkit.postEvent(appContext, invocationEvent);
 594 
 595             // 3746956 - flush events from PostEventQueue to prevent them from getting stuck and causing a deadlock
 596             sun.awt.SunToolkitSubclass.flushPendingEvents(appContext);
 597         } else {
 598             // This should be the equivalent to EventQueue.invokeAndWait
 599             ((LWCToolkit)Toolkit.getDefaultToolkit()).getSystemEventQueueForInvokeAndWait().postEvent(invocationEvent);
 600         }
 601 
 602         final Throwable eventException = invocationEvent.getException();
 603         if (eventException == null) return;
 604 
 605         if (eventException instanceof UndeclaredThrowableException) {
 606             throw new InvocationTargetException(((UndeclaredThrowableException)eventException).getUndeclaredThrowable());
 607         }
 608         throw new InvocationTargetException(eventException);
 609     }


 674         return InputEvent.CTRL_MASK | InputEvent.ALT_MASK;
 675     }
 676 
 677     /**
 678      * Tests whether specified key modifiers mask can be used to enter a printable
 679      * character.
 680      */
 681     @Override
 682     public boolean isPrintableCharacterModifiersMask(int mods) {
 683         return ((mods & (InputEvent.META_MASK | InputEvent.CTRL_MASK)) == 0);
 684     }
 685 
 686     /**
 687      * Returns whether popup is allowed to be shown above the task bar.
 688      */
 689     @Override
 690     public boolean canPopupOverlapTaskBar() {
 691         return false;
 692     }
 693 
 694     // Extends PeerEvent because we want to pass long an ObjC mediator object and because we want these events to be posted early
 695     // Typically, rather than relying on the notifier to call notifyAll(), we use the mediator to stop the runloop
 696     public static class CPeerEvent extends PeerEvent {
 697         private long _mediator = 0;
 698 
 699         public CPeerEvent(Runnable runnable, long mediator) {
 700             super(Toolkit.getDefaultToolkit(), runnable, null, true, 0);
 701             _mediator = mediator;
 702         }
 703 
 704         public void dispatch() {
 705             try {
 706                 super.dispatch();
 707             } finally {
 708                 if (_mediator != 0) {
 709                     LWCToolkit.stopAWTRunLoop(_mediator);
 710                 }
 711             }
 712         }
 713     }
 714 
 715     // Call through to native methods
 716     public static void doAWTRunLoop(long mediator, boolean awtMode) { doAWTRunLoop(mediator, awtMode, true); }
 717     public static void doAWTRunLoop(long mediator) { doAWTRunLoop(mediator, true); }
 718 
 719     private static Boolean sunAwtDisableCALayers = null;
 720 
 721     /**
 722      * Returns the value of "sun.awt.disableCALayers" property. Default
 723      * value is {@code false}.
 724      */
 725     public synchronized static boolean getSunAwtDisableCALayers() {
 726         if (sunAwtDisableCALayers == null) {
 727             sunAwtDisableCALayers = AccessController.doPrivileged(
 728                 new GetBooleanAction("sun.awt.disableCALayers"));
 729         }
 730         return sunAwtDisableCALayers.booleanValue();
 731     }
 732 
 733 
 734     /*
 735      * Returns true if the application (one of its windows) owns keyboard focus.
 736      */
 737     public native boolean isApplicationActive();
 738 
 739     /************************
 740      * Native methods section
 741      ************************/
 742 
 743     // These are public because they are accessed from WebKitPluginObject in JavaDeploy
 744     // Basic usage:
 745     // createAWTRunLoopMediator. Start client code on another thread. doAWTRunLoop. When client code is finished, stopAWTRunLoop.
 746     public static native long createAWTRunLoopMediator();
 747     public static native void doAWTRunLoop(long mediator, boolean awtMode, boolean detectDeadlocks);
 748     public static native void stopAWTRunLoop(long mediator);








 749 
 750     private native boolean nativeSyncQueue(long timeout);
 751 
 752     @Override
 753     public Clipboard createPlatformClipboard() {
 754         return new CClipboard("System");
 755     }
 756 
 757     @Override
 758     public boolean isModalExclusionTypeSupported(Dialog.ModalExclusionType exclusionType) {
 759         return (exclusionType == null) ||
 760             (exclusionType == Dialog.ModalExclusionType.NO_EXCLUDE) ||
 761             (exclusionType == Dialog.ModalExclusionType.APPLICATION_EXCLUDE) ||
 762             (exclusionType == Dialog.ModalExclusionType.TOOLKIT_EXCLUDE);
 763     }
 764 
 765     @Override
 766     public boolean isModalityTypeSupported(Dialog.ModalityType modalityType) {
 767         //TODO: FileDialog blocks excluded windows...
 768         //TODO: Test: 2 file dialogs, separate AppContexts: a) Dialog 1 blocked, shouldn't be. Frame 4 blocked (shouldn't be).




  47 
  48 class NamedCursor extends Cursor {
  49     NamedCursor(String name) {
  50         super(name);
  51     }
  52 }
  53 
  54 /**
  55  * Mac OS X Cocoa-based AWT Toolkit.
  56  */
  57 public class LWCToolkit extends LWToolkit {
  58     // While it is possible to enumerate all mouse devices
  59     // and query them for the number of buttons, the code
  60     // that does it is rather complex. Instead, we opt for
  61     // the easy way and just support up to 5 mouse buttons,
  62     // like Windows.
  63     private static final int BUTTONS = 5;
  64 
  65     private static native void initIDs();
  66 











  67     private static CInputMethodDescriptor sInputMethodDescriptor;
  68 
  69     static {
  70         System.err.flush();
  71         java.security.AccessController.doPrivileged(new java.security.PrivilegedAction<Object>() {
  72             public Object run() {
  73                 System.loadLibrary("awt");
  74                 System.loadLibrary("fontmanager");
  75                 return null;
  76             }
  77         });
  78         if (!GraphicsEnvironment.isHeadless()) {
  79             initIDs();
  80         }
  81     }
  82 
  83     public LWCToolkit() {
  84         SunToolkit.setDataTransfererClassName("sun.lwawt.macosx.CDataTransferer");
  85 
  86         areExtraMouseButtonsEnabled = Boolean.parseBoolean(System.getProperty("sun.awt.enableExtraMouseButtons", "true"));


 477     static final String nsImagePrefix = "NSImage://";
 478     protected Image checkForNSImage(final String imageName) {
 479         if (imageName == null) return null;
 480         if (!imageName.startsWith(nsImagePrefix)) return null;
 481         return CImage.getCreator().createImageFromName(imageName.substring(nsImagePrefix.length()));
 482     }
 483 
 484     // Thread-safe Object.equals() called from native
 485     public static boolean doEquals(final Object a, final Object b, Component c) {
 486         if (a == b) return true;
 487 
 488         final boolean[] ret = new boolean[1];
 489 
 490         try {  invokeAndWait(new Runnable() { public void run() { synchronized(ret) {
 491             ret[0] = a.equals(b);
 492         }}}, c); } catch (Exception e) { e.printStackTrace(); }
 493 
 494         synchronized(ret) { return ret[0]; }
 495     }
 496 
























 497     public static <T> T invokeAndWait(final Callable<T> callable, Component component) throws Exception {
 498         final CallableWrapper<T> wrapper = new CallableWrapper<T>(callable);
 499         invokeAndWait(wrapper, component);
 500         return wrapper.getResult();
 501     }
 502 
 503     static final class CallableWrapper<T> implements Runnable {
 504         final Callable<T> callable;
 505         T object;
 506         Exception e;
 507 
 508         public CallableWrapper(final Callable<T> callable) {
 509             this.callable = callable;
 510         }
 511 
 512         public void run() {
 513             try {
 514                 object = callable.call();
 515             } catch (final Exception e) {
 516                 this.e = e;
 517             }
 518         }
 519 
 520         public T getResult() throws Exception {
 521             if (e != null) throw e;
 522             return object;
 523         }
 524     }
 525 
 526     // Kicks an event over to the appropriate eventqueue and waits for it to finish
 527     // To avoid deadlocking, we manually run the NSRunLoop while waiting
 528     // Any selector invoked using ThreadUtilities performOnMainThread will be processed in doAWTRunLoop
 529     // The InvocationEvent will call LWCToolkit.stopAWTRunLoop() when finished, which will stop our manual runloop
 530     // Does not dispatch native events while in the loop
 531     public static void invokeAndWait(Runnable event, Component component) throws InterruptedException, InvocationTargetException {
 532         final long mediator = createAWTRunLoopMediator();
 533 
 534         InvocationEvent invocationEvent =
 535                 new InvocationEvent(component != null ? component : Toolkit.getDefaultToolkit(), event) {
 536                     @Override
 537                     public void dispatch() {
 538                         try {
 539                             super.dispatch();
 540                         } finally {
 541                             if (mediator != 0) {
 542                                 stopAWTRunLoop(mediator);
 543                             }
 544                         }
 545                     }
 546                 };
 547 
 548         if (component != null) {
 549             AppContext appContext = SunToolkit.targetToAppContext(component);
 550             SunToolkit.postEvent(appContext, invocationEvent);
 551 
 552             // 3746956 - flush events from PostEventQueue to prevent them from getting stuck and causing a deadlock
 553             sun.awt.SunToolkitSubclass.flushPendingEvents(appContext);
 554         } else {
 555             // This should be the equivalent to EventQueue.invokeAndWait
 556             ((LWCToolkit)Toolkit.getDefaultToolkit()).getSystemEventQueueForInvokeAndWait().postEvent(invocationEvent);
 557         }
 558 
 559         doAWTRunLoop(mediator, false);
 560 
 561         Throwable eventException = invocationEvent.getException();
 562         if (eventException != null) {
 563             if (eventException instanceof UndeclaredThrowableException) {
 564                 eventException = ((UndeclaredThrowableException)eventException).getUndeclaredThrowable();
 565             }
 566             throw new InvocationTargetException(eventException);
 567         }
 568     }
 569 
 570     public static void invokeLater(Runnable event, Component component) throws InvocationTargetException {
 571         final InvocationEvent invocationEvent =
 572                 new InvocationEvent(component != null ? component : Toolkit.getDefaultToolkit(), event);
 573 
 574         if (component != null) {
 575             final AppContext appContext = SunToolkit.targetToAppContext(component);
 576             SunToolkit.postEvent(appContext, invocationEvent);
 577 
 578             // 3746956 - flush events from PostEventQueue to prevent them from getting stuck and causing a deadlock
 579             sun.awt.SunToolkitSubclass.flushPendingEvents(appContext);
 580         } else {
 581             // This should be the equivalent to EventQueue.invokeAndWait
 582             ((LWCToolkit)Toolkit.getDefaultToolkit()).getSystemEventQueueForInvokeAndWait().postEvent(invocationEvent);
 583         }
 584 
 585         final Throwable eventException = invocationEvent.getException();
 586         if (eventException == null) return;
 587 
 588         if (eventException instanceof UndeclaredThrowableException) {
 589             throw new InvocationTargetException(((UndeclaredThrowableException)eventException).getUndeclaredThrowable());
 590         }
 591         throw new InvocationTargetException(eventException);
 592     }


 657         return InputEvent.CTRL_MASK | InputEvent.ALT_MASK;
 658     }
 659 
 660     /**
 661      * Tests whether specified key modifiers mask can be used to enter a printable
 662      * character.
 663      */
 664     @Override
 665     public boolean isPrintableCharacterModifiersMask(int mods) {
 666         return ((mods & (InputEvent.META_MASK | InputEvent.CTRL_MASK)) == 0);
 667     }
 668 
 669     /**
 670      * Returns whether popup is allowed to be shown above the task bar.
 671      */
 672     @Override
 673     public boolean canPopupOverlapTaskBar() {
 674         return false;
 675     }
 676 

























 677     private static Boolean sunAwtDisableCALayers = null;
 678 
 679     /**
 680      * Returns the value of "sun.awt.disableCALayers" property. Default
 681      * value is {@code false}.
 682      */
 683     public synchronized static boolean getSunAwtDisableCALayers() {
 684         if (sunAwtDisableCALayers == null) {
 685             sunAwtDisableCALayers = AccessController.doPrivileged(
 686                 new GetBooleanAction("sun.awt.disableCALayers"));
 687         }
 688         return sunAwtDisableCALayers.booleanValue();
 689     }
 690 
 691 
 692     /*
 693      * Returns true if the application (one of its windows) owns keyboard focus.
 694      */
 695     public native boolean isApplicationActive();
 696 
 697     /************************
 698      * Native methods section
 699      ************************/
 700 
 701     static native long createAWTRunLoopMediator();
 702     /**
 703      * Method to run a nested run-loop. The nested loop is spinned in the javaRunLoop mode, so selectors sent
 704      * by [JNFRunLoop performOnMainThreadWaiting] are processed.
 705      * @param mediator a native pointer to the mediator object created by createAWTRunLoopMediator
 706      * @param processEvents if true - dispatches event while in the nested loop. Used in DnD.
 707      *                      Additional attention is needed when using this feature as we short-circuit normal event
 708      *                      processing which could break Appkit.
 709      *                      (One known example is when the window is resized with the mouse)
 710      *
 711      *                      if false - all events come after exit form the nested loop
 712      */
 713     static native void doAWTRunLoop(long mediator, boolean processEvents);
 714     static native void stopAWTRunLoop(long mediator);
 715 
 716     private native boolean nativeSyncQueue(long timeout);
 717 
 718     @Override
 719     public Clipboard createPlatformClipboard() {
 720         return new CClipboard("System");
 721     }
 722 
 723     @Override
 724     public boolean isModalExclusionTypeSupported(Dialog.ModalExclusionType exclusionType) {
 725         return (exclusionType == null) ||
 726             (exclusionType == Dialog.ModalExclusionType.NO_EXCLUDE) ||
 727             (exclusionType == Dialog.ModalExclusionType.APPLICATION_EXCLUDE) ||
 728             (exclusionType == Dialog.ModalExclusionType.TOOLKIT_EXCLUDE);
 729     }
 730 
 731     @Override
 732     public boolean isModalityTypeSupported(Dialog.ModalityType modalityType) {
 733         //TODO: FileDialog blocks excluded windows...
 734         //TODO: Test: 2 file dialogs, separate AppContexts: a) Dialog 1 blocked, shouldn't be. Frame 4 blocked (shouldn't be).