71 72 private GraphicsDevice graphicsDevice; 73 private GraphicsConfiguration graphicsConfig; 74 75 private SurfaceData surfaceData; 76 private final Object surfaceDataLock = new Object(); 77 78 private int backBufferCount; 79 private BufferCapabilities backBufferCaps; 80 81 // The back buffer is used for two purposes: 82 // 1. To render all the lightweight peers 83 // 2. To provide user with a BufferStrategy 84 // Need to check if a single back buffer can be used for both 85 // TODO: VolatileImage 86 // private VolatileImage backBuffer; 87 private volatile BufferedImage backBuffer; 88 89 private volatile int windowState = Frame.NORMAL; 90 91 // A peer where the last mouse event came to. Used to generate 92 // MOUSE_ENTERED/EXITED notifications and by cursor manager to 93 // find the component under cursor 94 private static volatile LWComponentPeer lastMouseEventPeer = null; 95 96 // Peers where all dragged/released events should come to, 97 // depending on what mouse button is being dragged according to Cocoa 98 private static LWComponentPeer mouseDownTarget[] = new LWComponentPeer[3]; 99 100 // A bitmask that indicates what mouse buttons produce MOUSE_CLICKED events 101 // on MOUSE_RELEASE. Click events are only generated if there were no drag 102 // events between MOUSE_PRESSED and MOUSE_RELEASED for particular button 103 private static int mouseClickButtons = 0; 104 105 private volatile boolean isOpaque = true; 106 107 private static final Font DEFAULT_FONT = new Font("Lucida Grande", Font.PLAIN, 13); 108 109 private static LWWindowPeer grabbingWindow; 110 111 private volatile boolean skipNextFocusChange; 112 113 private static final Color nonOpaqueBackground = new Color(0, 0, 0, 0); 114 659 grabbingWindow.ungrab(); 660 } 661 } 662 663 // ---- EVENTS ---- // 664 665 /* 666 * Called by the delegate to dispatch the event to Java. Event 667 * coordinates are relative to non-client window are, i.e. the top-left 668 * point of the client area is (insets.top, insets.left). 669 */ 670 public void dispatchMouseEvent(int id, long when, int button, 671 int x, int y, int screenX, int screenY, 672 int modifiers, int clickCount, boolean popupTrigger, 673 byte[] bdata) 674 { 675 // TODO: fill "bdata" member of AWTEvent 676 Rectangle r = getBounds(); 677 // findPeerAt() expects parent coordinates 678 LWComponentPeer targetPeer = findPeerAt(r.x + x, r.y + y); 679 LWWindowPeer lastWindowPeer = 680 (lastMouseEventPeer != null) ? lastMouseEventPeer.getWindowPeerOrSelf() : null; 681 LWWindowPeer curWindowPeer = 682 (targetPeer != null) ? targetPeer.getWindowPeerOrSelf() : null; 683 684 if (id == MouseEvent.MOUSE_EXITED) { 685 // Sometimes we may get MOUSE_EXITED after lastMouseEventPeer is switched 686 // to a peer from another window. So we must first check if this peer is 687 // the same as lastWindowPeer 688 if (lastWindowPeer == this) { 689 if (isEnabled()) { 690 Point lp = lastMouseEventPeer.windowToLocal(x, y, 691 lastWindowPeer); 692 postEvent(new MouseEvent(lastMouseEventPeer.getTarget(), 693 MouseEvent.MOUSE_EXITED, when, 694 modifiers, lp.x, lp.y, screenX, 695 screenY, clickCount, popupTrigger, 696 button)); 697 } 698 lastMouseEventPeer = null; 699 } 700 } else { 701 if (targetPeer != lastMouseEventPeer) { 702 703 if (id != MouseEvent.MOUSE_DRAGGED || lastMouseEventPeer == null) { 704 // lastMouseEventPeer may be null if mouse was out of Java windows 705 if (lastMouseEventPeer != null && lastMouseEventPeer.isEnabled()) { 706 // Sometimes, MOUSE_EXITED is not sent by delegate (or is sent a bit 707 // later), in which case lastWindowPeer is another window 708 if (lastWindowPeer != this) { 709 Point oldp = lastMouseEventPeer.windowToLocal(x, y, lastWindowPeer); 710 // Additionally translate from this to lastWindowPeer coordinates 711 Rectangle lr = lastWindowPeer.getBounds(); 712 oldp.x += r.x - lr.x; 713 oldp.y += r.y - lr.y; 714 postEvent(new MouseEvent(lastMouseEventPeer.getTarget(), 715 MouseEvent.MOUSE_EXITED, 716 when, modifiers, 717 oldp.x, oldp.y, screenX, screenY, 718 clickCount, popupTrigger, button)); 719 } else { 720 Point oldp = lastMouseEventPeer.windowToLocal(x, y, this); 721 postEvent(new MouseEvent(lastMouseEventPeer.getTarget(), 722 MouseEvent.MOUSE_EXITED, 723 when, modifiers, 724 oldp.x, oldp.y, screenX, screenY, 725 clickCount, popupTrigger, button)); 726 } 727 } 728 if (targetPeer != null && targetPeer.isEnabled() && id != MouseEvent.MOUSE_ENTERED) { 729 Point newp = targetPeer.windowToLocal(x, y, curWindowPeer); 730 postEvent(new MouseEvent(targetPeer.getTarget(), 731 MouseEvent.MOUSE_ENTERED, 732 when, modifiers, 733 newp.x, newp.y, screenX, screenY, 734 clickCount, popupTrigger, button)); 735 } 736 } 737 lastMouseEventPeer = targetPeer; 738 } 739 // TODO: fill "bdata" member of AWTEvent 740 741 int eventButtonMask = (button > 0)? MouseEvent.getMaskForButton(button) : 0; 742 int otherButtonsPressed = modifiers & ~eventButtonMask; 743 744 // For pressed/dragged/released events OS X treats other 745 // mouse buttons as if they were BUTTON2, so we do the same 746 int targetIdx = (button > 3) ? MouseEvent.BUTTON2 - 1 : button - 1; 747 748 // MOUSE_ENTERED/EXITED are generated for the components strictly under 749 // mouse even when dragging. That's why we first update lastMouseEventPeer 750 // based on initial targetPeer value and only then recalculate targetPeer 751 // for MOUSE_DRAGGED/RELEASED events 752 if (id == MouseEvent.MOUSE_PRESSED) { 753 754 // Ungrab only if this window is not an owned window of the grabbing one. 755 if (!isGrabbing() && grabbingWindow != null && 756 grabbingWindow != getOwnerFrameDialog(this)) 757 { 758 grabbingWindow.ungrab(); 768 // Cocoa dragged event has the information about which mouse 769 // button is being dragged. Use it to determine the peer that 770 // should receive the dragged event. 771 targetPeer = mouseDownTarget[targetIdx]; 772 mouseClickButtons &= ~modifiers; 773 } else if (id == MouseEvent.MOUSE_RELEASED) { 774 // TODO: currently, mouse released event goes to the same component 775 // that received corresponding mouse pressed event. For most cases, 776 // it's OK, however, we need to make sure that our behavior is consistent 777 // with 1.6 for cases where component in question have been 778 // hidden/removed in between of mouse pressed/released events. 779 targetPeer = mouseDownTarget[targetIdx]; 780 781 if ((modifiers & eventButtonMask) == 0) { 782 mouseDownTarget[targetIdx] = null; 783 } 784 785 // mouseClickButtons is updated below, after MOUSE_CLICK is sent 786 } 787 788 // check if we receive mouseEvent from outside the window's bounds 789 // it can be either mouseDragged or mouseReleased 790 if (curWindowPeer == null) { 791 //TODO This can happen if this window is invisible. this is correct behavior in this case? 792 curWindowPeer = this; 793 } 794 if (targetPeer == null) { 795 //TODO This can happen if this window is invisible. this is correct behavior in this case? 796 targetPeer = this; 797 } 798 799 800 Point lp = targetPeer.windowToLocal(x, y, curWindowPeer); 801 if (targetPeer.isEnabled()) { 802 MouseEvent event = new MouseEvent(targetPeer.getTarget(), id, 803 when, modifiers, lp.x, lp.y, 804 screenX, screenY, clickCount, 805 popupTrigger, button); 806 postEvent(event); 807 } 808 809 if (id == MouseEvent.MOUSE_RELEASED) { 810 if ((mouseClickButtons & eventButtonMask) != 0 811 && targetPeer.isEnabled()) { 812 postEvent(new MouseEvent(targetPeer.getTarget(), 813 MouseEvent.MOUSE_CLICKED, 814 when, modifiers, 815 lp.x, lp.y, screenX, screenY, 816 clickCount, popupTrigger, button)); 817 } 818 mouseClickButtons &= ~eventButtonMask; 819 } 820 } 821 notifyUpdateCursor(); 822 } 823 824 public void dispatchMouseWheelEvent(long when, int x, int y, int modifiers, 825 int scrollType, int scrollAmount, 826 int wheelRotation, double preciseWheelRotation, 827 byte[] bdata) 828 { 829 // TODO: could we just use the last mouse event target here? 830 Rectangle r = getBounds(); 831 // findPeerAt() expects parent coordinates 832 final LWComponentPeer targetPeer = findPeerAt(r.x + x, r.y + y); 833 if (targetPeer == null || !targetPeer.isEnabled()) { 834 return; 835 } 836 837 Point lp = targetPeer.windowToLocal(x, y, this); 838 // TODO: fill "bdata" member of AWTEvent 839 // TODO: screenX/screenY 840 postEvent(new MouseWheelEvent(targetPeer.getTarget(), 841 MouseEvent.MOUSE_WHEEL, 842 when, modifiers, 843 lp.x, lp.y, 1048 * should be recalculated. 1049 * 1050 * This method may be called on the toolkit thread. 1051 */ 1052 public boolean updateInsets(Insets newInsets) { 1053 boolean changed = false; 1054 synchronized (getStateLock()) { 1055 changed = (insets.equals(newInsets)); 1056 insets = newInsets; 1057 } 1058 1059 if (changed) { 1060 replaceSurfaceData(); 1061 repaintPeer(); 1062 } 1063 1064 return changed; 1065 } 1066 1067 public static LWWindowPeer getWindowUnderCursor() { 1068 return lastMouseEventPeer != null ? lastMouseEventPeer.getWindowPeerOrSelf() : null; 1069 } 1070 1071 public static LWComponentPeer<?, ?> getPeerUnderCursor() { 1072 return lastMouseEventPeer; 1073 } 1074 1075 /* 1076 * Requests platform to set native focus on a frame/dialog. 1077 * In case of a simple window, triggers appropriate java focus change. 1078 */ 1079 public boolean requestWindowFocus(CausedFocusEvent.Cause cause) { 1080 if (focusLog.isLoggable(PlatformLogger.FINE)) { 1081 focusLog.fine("requesting native focus to " + this); 1082 } 1083 1084 if (!focusAllowedFor()) { 1085 focusLog.fine("focus is not allowed"); 1086 return false; 1087 } 1088 1089 if (platformWindow.rejectFocusRequest(cause)) { 1090 return false; 1091 } 1092 | 71 72 private GraphicsDevice graphicsDevice; 73 private GraphicsConfiguration graphicsConfig; 74 75 private SurfaceData surfaceData; 76 private final Object surfaceDataLock = new Object(); 77 78 private int backBufferCount; 79 private BufferCapabilities backBufferCaps; 80 81 // The back buffer is used for two purposes: 82 // 1. To render all the lightweight peers 83 // 2. To provide user with a BufferStrategy 84 // Need to check if a single back buffer can be used for both 85 // TODO: VolatileImage 86 // private VolatileImage backBuffer; 87 private volatile BufferedImage backBuffer; 88 89 private volatile int windowState = Frame.NORMAL; 90 91 // check that the mouse is over the window 92 private volatile boolean isMouseOver = false; 93 94 // A peer where the last mouse event came to. Used by cursor manager to 95 // find the component under cursor 96 private static volatile LWComponentPeer lastCommonMouseEventPeer = null; 97 98 // A peer where the last mouse event came to. Used to generate 99 // MOUSE_ENTERED/EXITED notifications 100 private volatile LWComponentPeer lastMouseEventPeer; 101 102 // Peers where all dragged/released events should come to, 103 // depending on what mouse button is being dragged according to Cocoa 104 private static LWComponentPeer mouseDownTarget[] = new LWComponentPeer[3]; 105 106 // A bitmask that indicates what mouse buttons produce MOUSE_CLICKED events 107 // on MOUSE_RELEASE. Click events are only generated if there were no drag 108 // events between MOUSE_PRESSED and MOUSE_RELEASED for particular button 109 private static int mouseClickButtons = 0; 110 111 private volatile boolean isOpaque = true; 112 113 private static final Font DEFAULT_FONT = new Font("Lucida Grande", Font.PLAIN, 13); 114 115 private static LWWindowPeer grabbingWindow; 116 117 private volatile boolean skipNextFocusChange; 118 119 private static final Color nonOpaqueBackground = new Color(0, 0, 0, 0); 120 665 grabbingWindow.ungrab(); 666 } 667 } 668 669 // ---- EVENTS ---- // 670 671 /* 672 * Called by the delegate to dispatch the event to Java. Event 673 * coordinates are relative to non-client window are, i.e. the top-left 674 * point of the client area is (insets.top, insets.left). 675 */ 676 public void dispatchMouseEvent(int id, long when, int button, 677 int x, int y, int screenX, int screenY, 678 int modifiers, int clickCount, boolean popupTrigger, 679 byte[] bdata) 680 { 681 // TODO: fill "bdata" member of AWTEvent 682 Rectangle r = getBounds(); 683 // findPeerAt() expects parent coordinates 684 LWComponentPeer targetPeer = findPeerAt(r.x + x, r.y + y); 685 686 if (id == MouseEvent.MOUSE_EXITED) { 687 isMouseOver = false; 688 if (lastMouseEventPeer != null) { 689 if (lastMouseEventPeer.isEnabled()) { 690 Point lp = lastMouseEventPeer.windowToLocal(x, y, 691 this); 692 postEvent(new MouseEvent(lastMouseEventPeer.getTarget(), 693 MouseEvent.MOUSE_EXITED, when, 694 modifiers, lp.x, lp.y, screenX, 695 screenY, clickCount, popupTrigger, 696 button)); 697 } 698 699 // Sometimes we may get MOUSE_EXITED after lastCommonMouseEventPeer is switched 700 // to a peer from another window. So we must first check if this peer is 701 // the same as lastWindowPeer 702 if (lastCommonMouseEventPeer != null && lastCommonMouseEventPeer.getWindowPeerOrSelf() == this) { 703 lastCommonMouseEventPeer = null; 704 } 705 lastMouseEventPeer = null; 706 } 707 } else if(id == MouseEvent.MOUSE_ENTERED) { 708 isMouseOver = true; 709 if (targetPeer != null) { 710 if (targetPeer.isEnabled()) { 711 Point lp = targetPeer.windowToLocal(x, y, this); 712 postEvent(new MouseEvent(targetPeer.getTarget(), 713 MouseEvent.MOUSE_ENTERED, when, 714 modifiers, lp.x, lp.y, screenX, 715 screenY, clickCount, popupTrigger, 716 button)); 717 } 718 lastCommonMouseEventPeer = targetPeer; 719 lastMouseEventPeer = targetPeer; 720 } 721 } else { 722 PlatformWindow topmostPlatforWindow = 723 platformWindow.getTopmostPlatformWindowUnderMouse(); 724 725 LWWindowPeer topmostWindowPeer = 726 topmostPlatforWindow != null ? topmostPlatforWindow.getPeer() : null; 727 728 // topmostWindowPeer == null condition is added for the backward 729 // compatibility with applets. It can be removed when the 730 // getTopmostPlatformWindowUnderMouse() method will be properly 731 // implemented in CPlatformEmbeddedFrame class 732 if (topmostWindowPeer == this || topmostWindowPeer == null) { 733 generateMouseEnterExitEventsForComponents(when, button, x, y, 734 screenX, screenY, modifiers, clickCount, popupTrigger, 735 targetPeer); 736 } else { 737 LWComponentPeer topmostTargetPeer = 738 topmostWindowPeer != null ? topmostWindowPeer.findPeerAt(r.x + x, r.y + y) : null; 739 topmostWindowPeer.generateMouseEnterExitEventsForComponents(when, button, x, y, 740 screenX, screenY, modifiers, clickCount, popupTrigger, 741 topmostTargetPeer); 742 } 743 744 // TODO: fill "bdata" member of AWTEvent 745 746 int eventButtonMask = (button > 0)? MouseEvent.getMaskForButton(button) : 0; 747 int otherButtonsPressed = modifiers & ~eventButtonMask; 748 749 // For pressed/dragged/released events OS X treats other 750 // mouse buttons as if they were BUTTON2, so we do the same 751 int targetIdx = (button > 3) ? MouseEvent.BUTTON2 - 1 : button - 1; 752 753 // MOUSE_ENTERED/EXITED are generated for the components strictly under 754 // mouse even when dragging. That's why we first update lastMouseEventPeer 755 // based on initial targetPeer value and only then recalculate targetPeer 756 // for MOUSE_DRAGGED/RELEASED events 757 if (id == MouseEvent.MOUSE_PRESSED) { 758 759 // Ungrab only if this window is not an owned window of the grabbing one. 760 if (!isGrabbing() && grabbingWindow != null && 761 grabbingWindow != getOwnerFrameDialog(this)) 762 { 763 grabbingWindow.ungrab(); 773 // Cocoa dragged event has the information about which mouse 774 // button is being dragged. Use it to determine the peer that 775 // should receive the dragged event. 776 targetPeer = mouseDownTarget[targetIdx]; 777 mouseClickButtons &= ~modifiers; 778 } else if (id == MouseEvent.MOUSE_RELEASED) { 779 // TODO: currently, mouse released event goes to the same component 780 // that received corresponding mouse pressed event. For most cases, 781 // it's OK, however, we need to make sure that our behavior is consistent 782 // with 1.6 for cases where component in question have been 783 // hidden/removed in between of mouse pressed/released events. 784 targetPeer = mouseDownTarget[targetIdx]; 785 786 if ((modifiers & eventButtonMask) == 0) { 787 mouseDownTarget[targetIdx] = null; 788 } 789 790 // mouseClickButtons is updated below, after MOUSE_CLICK is sent 791 } 792 793 if (targetPeer == null) { 794 //TODO This can happen if this window is invisible. this is correct behavior in this case? 795 targetPeer = this; 796 } 797 798 799 Point lp = targetPeer.windowToLocal(x, y, this); 800 if (targetPeer.isEnabled()) { 801 MouseEvent event = new MouseEvent(targetPeer.getTarget(), id, 802 when, modifiers, lp.x, lp.y, 803 screenX, screenY, clickCount, 804 popupTrigger, button); 805 postEvent(event); 806 } 807 808 if (id == MouseEvent.MOUSE_RELEASED) { 809 if ((mouseClickButtons & eventButtonMask) != 0 810 && targetPeer.isEnabled()) { 811 postEvent(new MouseEvent(targetPeer.getTarget(), 812 MouseEvent.MOUSE_CLICKED, 813 when, modifiers, 814 lp.x, lp.y, screenX, screenY, 815 clickCount, popupTrigger, button)); 816 } 817 mouseClickButtons &= ~eventButtonMask; 818 } 819 } 820 notifyUpdateCursor(); 821 } 822 823 private void generateMouseEnterExitEventsForComponents(long when, 824 int button, int x, int y, int screenX, int screenY, 825 int modifiers, int clickCount, boolean popupTrigger, 826 LWComponentPeer targetPeer) { 827 828 if (!isMouseOver || targetPeer == lastMouseEventPeer) { 829 return; 830 } 831 832 // Generate Mouse Exit for components 833 if (lastMouseEventPeer != null && lastMouseEventPeer.isEnabled()) { 834 Point oldp = lastMouseEventPeer.windowToLocal(x, y, this); 835 postEvent(new MouseEvent(lastMouseEventPeer.getTarget(), 836 MouseEvent.MOUSE_EXITED, 837 when, modifiers, 838 oldp.x, oldp.y, screenX, screenY, 839 clickCount, popupTrigger, button)); 840 } 841 lastCommonMouseEventPeer = targetPeer; 842 lastMouseEventPeer = targetPeer; 843 844 // Generate Mouse Enter for components 845 if (targetPeer != null && targetPeer.isEnabled()) { 846 Point newp = targetPeer.windowToLocal(x, y, this); 847 postEvent(new MouseEvent(targetPeer.getTarget(), 848 MouseEvent.MOUSE_ENTERED, 849 when, modifiers, 850 newp.x, newp.y, screenX, screenY, 851 clickCount, popupTrigger, button)); 852 } 853 } 854 855 public void dispatchMouseWheelEvent(long when, int x, int y, int modifiers, 856 int scrollType, int scrollAmount, 857 int wheelRotation, double preciseWheelRotation, 858 byte[] bdata) 859 { 860 // TODO: could we just use the last mouse event target here? 861 Rectangle r = getBounds(); 862 // findPeerAt() expects parent coordinates 863 final LWComponentPeer targetPeer = findPeerAt(r.x + x, r.y + y); 864 if (targetPeer == null || !targetPeer.isEnabled()) { 865 return; 866 } 867 868 Point lp = targetPeer.windowToLocal(x, y, this); 869 // TODO: fill "bdata" member of AWTEvent 870 // TODO: screenX/screenY 871 postEvent(new MouseWheelEvent(targetPeer.getTarget(), 872 MouseEvent.MOUSE_WHEEL, 873 when, modifiers, 874 lp.x, lp.y, 1079 * should be recalculated. 1080 * 1081 * This method may be called on the toolkit thread. 1082 */ 1083 public boolean updateInsets(Insets newInsets) { 1084 boolean changed = false; 1085 synchronized (getStateLock()) { 1086 changed = (insets.equals(newInsets)); 1087 insets = newInsets; 1088 } 1089 1090 if (changed) { 1091 replaceSurfaceData(); 1092 repaintPeer(); 1093 } 1094 1095 return changed; 1096 } 1097 1098 public static LWWindowPeer getWindowUnderCursor() { 1099 return lastCommonMouseEventPeer != null ? lastCommonMouseEventPeer.getWindowPeerOrSelf() : null; 1100 } 1101 1102 public static LWComponentPeer<?, ?> getPeerUnderCursor() { 1103 return lastCommonMouseEventPeer; 1104 } 1105 1106 /* 1107 * Requests platform to set native focus on a frame/dialog. 1108 * In case of a simple window, triggers appropriate java focus change. 1109 */ 1110 public boolean requestWindowFocus(CausedFocusEvent.Cause cause) { 1111 if (focusLog.isLoggable(PlatformLogger.FINE)) { 1112 focusLog.fine("requesting native focus to " + this); 1113 } 1114 1115 if (!focusAllowedFor()) { 1116 focusLog.fine("focus is not allowed"); 1117 return false; 1118 } 1119 1120 if (platformWindow.rejectFocusRequest(cause)) { 1121 return false; 1122 } 1123 |