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). |