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


 672         return InputEvent.CTRL_MASK | InputEvent.ALT_MASK;
 673     }
 674 
 675     /**
 676      * Tests whether specified key modifiers mask can be used to enter a printable
 677      * character.
 678      */
 679     @Override
 680     public boolean isPrintableCharacterModifiersMask(int mods) {
 681         return ((mods & (InputEvent.META_MASK | InputEvent.CTRL_MASK)) == 0);
 682     }
 683 
 684     /**
 685      * Returns whether popup is allowed to be shown above the task bar.
 686      */
 687     @Override
 688     public boolean canPopupOverlapTaskBar() {
 689         return false;
 690     }
 691 

























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