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

Print this page




  46 
  47 class NamedCursor extends Cursor {
  48     NamedCursor(String name) {
  49         super(name);
  50     }
  51 }
  52 
  53 /**
  54  * Mac OS X Cocoa-based AWT Toolkit.
  55  */
  56 public final class LWCToolkit extends LWToolkit {
  57     // While it is possible to enumerate all mouse devices
  58     // and query them for the number of buttons, the code
  59     // that does it is rather complex. Instead, we opt for
  60     // the easy way and just support up to 5 mouse buttons,
  61     // like Windows.
  62     private static final int BUTTONS = 5;
  63 
  64     private static native void initIDs();
  65 
  66     static native void executeNextAppKitEvent();
  67 
  68     private static CInputMethodDescriptor sInputMethodDescriptor;
  69 
  70     static {
  71         System.err.flush();
  72         java.security.AccessController.doPrivileged(new java.security.PrivilegedAction<Object>() {
  73             public Object run() {
  74                 System.loadLibrary("awt");
  75                 System.loadLibrary("fontmanager");
  76                 return null;
  77             }
  78         });
  79         if (!GraphicsEnvironment.isHeadless()) {
  80             initIDs();
  81         }
  82     }
  83 
  84     public LWCToolkit() {
  85         SunToolkit.setDataTransfererClassName("sun.lwawt.macosx.CDataTransferer");
  86 
  87         areExtraMouseButtonsEnabled = Boolean.parseBoolean(System.getProperty("sun.awt.enableExtraMouseButtons", "true"));


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





 553 
 554         InvocationEvent invocationEvent = new CPeerEvent(event, mediator);












 555 
 556         if (component != null) {
 557             AppContext appContext = SunToolkit.targetToAppContext(component);
 558             SunToolkit.postEvent(appContext, invocationEvent);
 559 
 560             // 3746956 - flush events from PostEventQueue to prevent them from getting stuck and causing a deadlock
 561             SunToolkit.flushPendingEvents(appContext);
 562         } else {
 563             // This should be the equivalent to EventQueue.invokeAndWait
 564             ((LWCToolkit)Toolkit.getDefaultToolkit()).getSystemEventQueueForInvokeAndWait().postEvent(invocationEvent);
 565         }
 566 
 567         doAWTRunLoop(mediator, true, detectDeadlocks);
 568 
 569         Throwable eventException = invocationEvent.getException();
 570         if (eventException != null) {
 571             if (eventException instanceof UndeclaredThrowableException) {
 572                 eventException = ((UndeclaredThrowableException)eventException).getUndeclaredThrowable();
 573             }
 574             throw new InvocationTargetException(eventException);
 575         }
 576     }
 577 
 578     public static void invokeLater(Runnable event, Component component) throws InvocationTargetException {
 579         final InvocationEvent invocationEvent = new CPeerEvent(event, 0);

 580 
 581         if (component != null) {
 582             final AppContext appContext = SunToolkit.targetToAppContext(component);
 583             SunToolkit.postEvent(appContext, invocationEvent);
 584 
 585             // 3746956 - flush events from PostEventQueue to prevent them from getting stuck and causing a deadlock
 586             SunToolkit.flushPendingEvents(appContext);
 587         } else {
 588             // This should be the equivalent to EventQueue.invokeAndWait
 589             ((LWCToolkit)Toolkit.getDefaultToolkit()).getSystemEventQueueForInvokeAndWait().postEvent(invocationEvent);
 590         }
 591 
 592         final Throwable eventException = invocationEvent.getException();
 593         if (eventException == null) return;
 594 
 595         if (eventException instanceof UndeclaredThrowableException) {
 596             throw new InvocationTargetException(((UndeclaredThrowableException)eventException).getUndeclaredThrowable());
 597         }
 598         throw new InvocationTargetException(eventException);
 599     }


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








 739 
 740     private native boolean nativeSyncQueue(long timeout);
 741 
 742     @Override
 743     public Clipboard createPlatformClipboard() {
 744         return new CClipboard("System");
 745     }
 746 
 747     @Override
 748     public boolean isModalExclusionTypeSupported(Dialog.ModalExclusionType exclusionType) {
 749         return (exclusionType == null) ||
 750             (exclusionType == Dialog.ModalExclusionType.NO_EXCLUDE) ||
 751             (exclusionType == Dialog.ModalExclusionType.APPLICATION_EXCLUDE) ||
 752             (exclusionType == Dialog.ModalExclusionType.TOOLKIT_EXCLUDE);
 753     }
 754 
 755     @Override
 756     public boolean isModalityTypeSupported(Dialog.ModalityType modalityType) {
 757         //TODO: FileDialog blocks excluded windows...
 758         //TODO: Test: 2 file dialogs, separate AppContexts: a) Dialog 1 blocked, shouldn't be. Frame 4 blocked (shouldn't be).




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


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


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
























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


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

























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