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