1 /* 2 * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.lwawt; 27 28 import java.awt.*; 29 import java.awt.event.*; 30 import java.awt.peer.*; 31 import java.util.List; 32 33 import javax.swing.*; 34 35 import sun.awt.*; 36 import sun.awt.AWTAccessor.ComponentAccessor; 37 import sun.java2d.*; 38 import sun.java2d.loops.Blit; 39 import sun.java2d.loops.CompositeType; 40 import sun.java2d.pipe.Region; 41 import sun.util.logging.PlatformLogger; 42 43 public class LWWindowPeer 44 extends LWContainerPeer<Window, JComponent> 45 implements FramePeer, DialogPeer, FullScreenCapable, DisplayChangedListener, PlatformEventNotifier 46 { 47 public enum PeerType { 48 SIMPLEWINDOW, 49 FRAME, 50 DIALOG, 51 EMBEDDED_FRAME, 52 VIEW_EMBEDDED_FRAME, 53 LW_FRAME 54 } 55 56 private static final PlatformLogger focusLog = PlatformLogger.getLogger("sun.lwawt.focus.LWWindowPeer"); 57 58 private final PlatformWindow platformWindow; 59 60 private static final int MINIMUM_WIDTH = 1; 61 private static final int MINIMUM_HEIGHT = 1; 62 63 private Insets insets = new Insets(0, 0, 0, 0); 64 65 private GraphicsDevice graphicsDevice; 66 private GraphicsConfiguration graphicsConfig; 67 68 private SurfaceData surfaceData; 69 private final Object surfaceDataLock = new Object(); 70 71 private volatile int windowState = Frame.NORMAL; 72 73 // check that the mouse is over the window 74 private volatile boolean isMouseOver = false; 75 76 // A peer where the last mouse event came to. Used by cursor manager to 77 // find the component under cursor 78 private static volatile LWComponentPeer<?, ?> lastCommonMouseEventPeer; 79 80 // A peer where the last mouse event came to. Used to generate 81 // MOUSE_ENTERED/EXITED notifications 82 private volatile LWComponentPeer<?, ?> lastMouseEventPeer; 83 84 // Peers where all dragged/released events should come to, 85 // depending on what mouse button is being dragged according to Cocoa 86 private static final LWComponentPeer<?, ?>[] mouseDownTarget = new LWComponentPeer<?, ?>[3]; 87 88 // A bitmask that indicates what mouse buttons produce MOUSE_CLICKED events 89 // on MOUSE_RELEASE. Click events are only generated if there were no drag 90 // events between MOUSE_PRESSED and MOUSE_RELEASED for particular button 91 private static int mouseClickButtons = 0; 92 93 private volatile boolean isOpaque = true; 94 95 private static final Font DEFAULT_FONT = new Font("Lucida Grande", Font.PLAIN, 13); 96 97 private static LWWindowPeer grabbingWindow; 98 99 private volatile boolean skipNextFocusChange; 100 101 private static final Color nonOpaqueBackground = new Color(0, 0, 0, 0); 102 103 private volatile boolean textured; 104 105 private final PeerType peerType; 106 107 private final SecurityWarningWindow warningWindow; 108 109 private volatile boolean targetFocusable; 110 111 /** 112 * Current modal blocker or null. 113 * 114 * Synchronization: peerTreeLock. 115 */ 116 private LWWindowPeer blocker; 117 118 public LWWindowPeer(Window target, PlatformComponent platformComponent, 119 PlatformWindow platformWindow, PeerType peerType) 120 { 121 super(target, platformComponent); 122 this.platformWindow = platformWindow; 123 this.peerType = peerType; 124 125 Window owner = target.getOwner(); 126 LWWindowPeer ownerPeer = owner == null ? null : 127 (LWWindowPeer) AWTAccessor.getComponentAccessor().getPeer(owner); 128 PlatformWindow ownerDelegate = (ownerPeer != null) ? ownerPeer.getPlatformWindow() : null; 129 130 // The delegate.initialize() needs a non-null GC on X11. 131 GraphicsConfiguration gc = getTarget().getGraphicsConfiguration(); 132 synchronized (getStateLock()) { 133 // graphicsConfig should be updated according to the real window 134 // bounds when the window is shown, see 4868278 135 this.graphicsConfig = gc; 136 } 137 138 if (!target.isFontSet()) { 139 target.setFont(DEFAULT_FONT); 140 } 141 142 if (!target.isBackgroundSet()) { 143 target.setBackground(SystemColor.window); 144 } else { 145 // first we check if user provided alpha for background. This is 146 // similar to what Apple's Java do. 147 // Since JDK7 we should rely on setOpacity() only. 148 // this.opacity = c.getAlpha(); 149 } 150 151 if (!target.isForegroundSet()) { 152 target.setForeground(SystemColor.windowText); 153 // we should not call setForeground because it will call a repaint 154 // which the peer may not be ready to do yet. 155 } 156 157 platformWindow.initialize(target, this, ownerDelegate); 158 159 // Init warning window(for applets) 160 SecurityWarningWindow warn = null; 161 if (target.getWarningString() != null) { 162 // accessSystemTray permission allows to display TrayIcon, TrayIcon tooltip 163 // and TrayIcon balloon windows without a warning window. 164 if (!AWTAccessor.getWindowAccessor().isTrayIconWindow(target)) { 165 LWToolkit toolkit = (LWToolkit)Toolkit.getDefaultToolkit(); 166 warn = toolkit.createSecurityWarning(target, this); 167 } 168 } 169 170 warningWindow = warn; 171 } 172 173 @Override 174 void initializeImpl() { 175 super.initializeImpl(); 176 177 178 if (getTarget() instanceof Frame) { 179 setTitle(((Frame) getTarget()).getTitle()); 180 setState(((Frame) getTarget()).getExtendedState()); 181 } else if (getTarget() instanceof Dialog) { 182 setTitle(((Dialog) getTarget()).getTitle()); 183 } 184 185 updateAlwaysOnTopState(); 186 updateMinimumSize(); 187 188 final Shape shape = getTarget().getShape(); 189 if (shape != null) { 190 applyShape(Region.getInstance(shape, null)); 191 } 192 193 final float opacity = getTarget().getOpacity(); 194 if (opacity < 1.0f) { 195 setOpacity(opacity); 196 } 197 198 setOpaque(getTarget().isOpaque()); 199 200 updateInsets(platformWindow.getInsets()); 201 if (getSurfaceData() == null) { 202 replaceSurfaceData(false); 203 } 204 activateDisplayListener(); 205 } 206 207 // Just a helper method 208 @Override 209 public PlatformWindow getPlatformWindow() { 210 return platformWindow; 211 } 212 213 @Override 214 protected LWWindowPeer getWindowPeerOrSelf() { 215 return this; 216 } 217 218 // ---- PEER METHODS ---- // 219 220 @Override 221 protected void disposeImpl() { 222 deactivateDisplayListener(); 223 SurfaceData oldData = getSurfaceData(); 224 synchronized (surfaceDataLock){ 225 surfaceData = null; 226 } 227 if (oldData != null) { 228 oldData.invalidate(); 229 } 230 if (isGrabbing()) { 231 ungrab(); 232 } 233 if (warningWindow != null) { 234 warningWindow.dispose(); 235 } 236 237 platformWindow.dispose(); 238 super.disposeImpl(); 239 } 240 241 @Override 242 protected void setVisibleImpl(final boolean visible) { 243 if (!visible && warningWindow != null) { 244 warningWindow.setVisible(false, false); 245 } 246 updateFocusableWindowState(); 247 super.setVisibleImpl(visible); 248 // TODO: update graphicsConfig, see 4868278 249 platformWindow.setVisible(visible); 250 if (isSimpleWindow()) { 251 KeyboardFocusManagerPeer kfmPeer = LWKeyboardFocusManagerPeer.getInstance(); 252 if (visible) { 253 if (!getTarget().isAutoRequestFocus()) { 254 return; 255 } else { 256 requestWindowFocus(CausedFocusEvent.Cause.ACTIVATION); 257 } 258 // Focus the owner in case this window is focused. 259 } else if (kfmPeer.getCurrentFocusedWindow() == getTarget()) { 260 // Transfer focus to the owner. 261 LWWindowPeer owner = getOwnerFrameDialog(LWWindowPeer.this); 262 if (owner != null) { 263 owner.requestWindowFocus(CausedFocusEvent.Cause.ACTIVATION); 264 } 265 } 266 } 267 } 268 269 @Override 270 public final GraphicsConfiguration getGraphicsConfiguration() { 271 synchronized (getStateLock()) { 272 return graphicsConfig; 273 } 274 } 275 276 @Override 277 public boolean updateGraphicsData(GraphicsConfiguration gc) { 278 setGraphicsConfig(gc); 279 return false; 280 } 281 282 protected final Graphics getOnscreenGraphics(Color fg, Color bg, Font f) { 283 if (getSurfaceData() == null) { 284 return null; 285 } 286 if (fg == null) { 287 fg = SystemColor.windowText; 288 } 289 if (bg == null) { 290 bg = SystemColor.window; 291 } 292 if (f == null) { 293 f = DEFAULT_FONT; 294 } 295 return platformWindow.transformGraphics(new SunGraphics2D(getSurfaceData(), fg, bg, f)); 296 } 297 298 @Override 299 public void setBounds(int x, int y, int w, int h, int op) { 300 301 if((op & NO_EMBEDDED_CHECK) == 0 && getPeerType() == PeerType.VIEW_EMBEDDED_FRAME) { 302 return; 303 } 304 305 if ((op & SET_CLIENT_SIZE) != 0) { 306 // SET_CLIENT_SIZE is only applicable to window peers, so handle it here 307 // instead of pulling 'insets' field up to LWComponentPeer 308 // no need to add insets since Window's notion of width and height includes insets. 309 op &= ~SET_CLIENT_SIZE; 310 op |= SET_SIZE; 311 } 312 313 // Don't post ComponentMoved/Resized and Paint events 314 // until we've got a notification from the delegate 315 Rectangle cb = constrainBounds(x, y, w, h); 316 317 Rectangle newBounds = new Rectangle(getBounds()); 318 if ((op & (SET_LOCATION | SET_BOUNDS)) != 0) { 319 newBounds.x = cb.x; 320 newBounds.y = cb.y; 321 } 322 if ((op & (SET_SIZE | SET_BOUNDS)) != 0) { 323 newBounds.width = cb.width; 324 newBounds.height = cb.height; 325 } 326 // Native system could constraint bounds, so the peer wold be updated in the callback 327 platformWindow.setBounds(newBounds.x, newBounds.y, newBounds.width, newBounds.height); 328 } 329 330 public Rectangle constrainBounds(Rectangle bounds) { 331 return constrainBounds(bounds.x, bounds.y, bounds.width, bounds.height); 332 } 333 334 public Rectangle constrainBounds(int x, int y, int w, int h) { 335 336 if (w < MINIMUM_WIDTH) { 337 w = MINIMUM_WIDTH; 338 } 339 340 if (h < MINIMUM_HEIGHT) { 341 h = MINIMUM_HEIGHT; 342 } 343 344 final int maxW = getLWGC().getMaxTextureWidth(); 345 final int maxH = getLWGC().getMaxTextureHeight(); 346 347 if (w > maxW) { 348 w = maxW; 349 } 350 if (h > maxH) { 351 h = maxH; 352 } 353 354 return new Rectangle(x, y, w, h); 355 } 356 357 @Override 358 public Point getLocationOnScreen() { 359 return platformWindow.getLocationOnScreen(); 360 } 361 362 /** 363 * Overridden from LWContainerPeer to return the correct insets. 364 * Insets are queried from the delegate and are kept up to date by 365 * requiering when needed (i.e. when the window geometry is changed). 366 */ 367 @Override 368 public Insets getInsets() { 369 synchronized (getStateLock()) { 370 return insets; 371 } 372 } 373 374 @Override 375 public FontMetrics getFontMetrics(Font f) { 376 // TODO: check for "use platform metrics" settings 377 return platformWindow.getFontMetrics(f); 378 } 379 380 @Override 381 public void toFront() { 382 platformWindow.toFront(); 383 } 384 385 @Override 386 public void toBack() { 387 platformWindow.toBack(); 388 } 389 390 @Override 391 public void setZOrder(ComponentPeer above) { 392 throw new RuntimeException("not implemented"); 393 } 394 395 @Override 396 public void updateAlwaysOnTopState() { 397 platformWindow.setAlwaysOnTop(getTarget().isAlwaysOnTop()); 398 } 399 400 @Override 401 public void updateFocusableWindowState() { 402 targetFocusable = getTarget().isFocusableWindow(); 403 platformWindow.updateFocusableWindowState(); 404 } 405 406 @Override 407 public void setModalBlocked(Dialog blocker, boolean blocked) { 408 synchronized (getPeerTreeLock()) { 409 ComponentPeer peer = AWTAccessor.getComponentAccessor().getPeer(blocker); 410 if (blocked && (peer instanceof LWWindowPeer)) { 411 this.blocker = (LWWindowPeer) peer; 412 } else { 413 this.blocker = null; 414 } 415 } 416 417 platformWindow.setModalBlocked(blocked); 418 } 419 420 @Override 421 public void updateMinimumSize() { 422 final Dimension min; 423 if (getTarget().isMinimumSizeSet()) { 424 min = getTarget().getMinimumSize(); 425 min.width = Math.max(min.width, MINIMUM_WIDTH); 426 min.height = Math.max(min.height, MINIMUM_HEIGHT); 427 } else { 428 min = new Dimension(MINIMUM_WIDTH, MINIMUM_HEIGHT); 429 } 430 431 final Dimension max; 432 if (getTarget().isMaximumSizeSet()) { 433 max = getTarget().getMaximumSize(); 434 max.width = Math.min(max.width, getLWGC().getMaxTextureWidth()); 435 max.height = Math.min(max.height, getLWGC().getMaxTextureHeight()); 436 } else { 437 max = new Dimension(getLWGC().getMaxTextureWidth(), 438 getLWGC().getMaxTextureHeight()); 439 } 440 441 platformWindow.setSizeConstraints(min.width, min.height, max.width, max.height); 442 } 443 444 @Override 445 public void updateIconImages() { 446 getPlatformWindow().updateIconImages(); 447 } 448 449 @Override 450 public void setBackground(final Color c) { 451 super.setBackground(c); 452 updateOpaque(); 453 } 454 455 @Override 456 public void setOpacity(float opacity) { 457 getPlatformWindow().setOpacity(opacity); 458 repaintPeer(); 459 } 460 461 @Override 462 public final void setOpaque(final boolean isOpaque) { 463 if (this.isOpaque != isOpaque) { 464 this.isOpaque = isOpaque; 465 updateOpaque(); 466 } 467 } 468 469 private void updateOpaque() { 470 getPlatformWindow().setOpaque(!isTranslucent()); 471 replaceSurfaceData(false); 472 repaintPeer(); 473 } 474 475 @Override 476 public void updateWindow() { 477 } 478 479 public final boolean isTextured() { 480 return textured; 481 } 482 483 public final void setTextured(final boolean isTextured) { 484 textured = isTextured; 485 } 486 487 @Override 488 public final boolean isTranslucent() { 489 synchronized (getStateLock()) { 490 /* 491 * Textured window is a special case of translucent window. 492 * The difference is only in nswindow background. So when we set 493 * texture property our peer became fully translucent. It doesn't 494 * fill background, create non opaque backbuffers and layer etc. 495 */ 496 return !isOpaque || isShaped() || isTextured(); 497 } 498 } 499 500 @Override 501 final void applyShapeImpl(final Region shape) { 502 super.applyShapeImpl(shape); 503 updateOpaque(); 504 } 505 506 @Override 507 public void repositionSecurityWarning() { 508 if (warningWindow != null) { 509 ComponentAccessor compAccessor = AWTAccessor.getComponentAccessor(); 510 Window target = getTarget(); 511 int x = compAccessor.getX(target); 512 int y = compAccessor.getY(target); 513 int width = compAccessor.getWidth(target); 514 int height = compAccessor.getHeight(target); 515 warningWindow.reposition(x, y, width, height); 516 } 517 } 518 519 // ---- FRAME PEER METHODS ---- // 520 521 @Override // FramePeer and DialogPeer 522 public void setTitle(String title) { 523 platformWindow.setTitle(title == null ? "" : title); 524 } 525 526 @Override 527 public void setMenuBar(MenuBar mb) { 528 platformWindow.setMenuBar(mb); 529 } 530 531 @Override // FramePeer and DialogPeer 532 public void setResizable(boolean resizable) { 533 platformWindow.setResizable(resizable); 534 } 535 536 @Override 537 public void setState(int state) { 538 platformWindow.setWindowState(state); 539 } 540 541 @Override 542 public int getState() { 543 return windowState; 544 } 545 546 public Rectangle getMaximizedBounds() { 547 Object target = getTarget(); 548 return (target instanceof Frame) 549 ? ((Frame) target).getMaximizedBounds() : null; 550 } 551 552 public Rectangle getDefaultMaximizedBounds() { 553 GraphicsConfiguration config = getGraphicsConfiguration(); 554 Insets insets = ((CGraphicsDevice) config.getDevice()).getScreenInsets(); 555 Rectangle toBounds = config.getBounds(); 556 return new Rectangle( 557 toBounds.x + insets.left, 558 toBounds.y + insets.top, 559 toBounds.width - insets.left - insets.right, 560 toBounds.height - insets.top - insets.bottom); 561 } 562 563 @Override 564 public void setMaximizedBounds(Rectangle bounds) { 565 566 bounds = (bounds == null) 567 ? getDefaultMaximizedBounds() 568 : constrainBounds(bounds); 569 platformWindow.setMaximizedBounds( 570 bounds.x, bounds.y, bounds.width, bounds.height); 571 } 572 573 private void updateMaximizedBounds() { 574 Rectangle maximizedBounds = getMaximizedBounds(); 575 if (maximizedBounds == null) { 576 setMaximizedBounds(getDefaultMaximizedBounds()); 577 } 578 } 579 580 @Override 581 public void setBoundsPrivate(int x, int y, int width, int height) { 582 setBounds(x, y, width, height, SET_BOUNDS | NO_EMBEDDED_CHECK); 583 } 584 585 @Override 586 public Rectangle getBoundsPrivate() { 587 throw new RuntimeException("not implemented"); 588 } 589 590 // ---- DIALOG PEER METHODS ---- // 591 592 @Override 593 public void blockWindows(List<Window> windows) { 594 //TODO: LWX will probably need some collectJavaToplevels to speed this up 595 for (Window w : windows) { 596 WindowPeer wp = AWTAccessor.getComponentAccessor().getPeer(w); 597 if (wp != null) { 598 wp.setModalBlocked((Dialog)getTarget(), true); 599 } 600 } 601 } 602 603 // ---- PEER NOTIFICATIONS ---- // 604 605 @Override 606 public void notifyIconify(boolean iconify) { 607 //The toplevel target is Frame and states are applicable to it. 608 //Otherwise, the target is Window and it don't have state property. 609 //Hopefully, no such events are posted in the queue so consider the 610 //target as Frame in all cases. 611 612 // REMIND: should we send it anyway if the state not changed since last 613 // time? 614 WindowEvent iconifyEvent = new WindowEvent(getTarget(), 615 iconify ? WindowEvent.WINDOW_ICONIFIED 616 : WindowEvent.WINDOW_DEICONIFIED); 617 postEvent(iconifyEvent); 618 619 int newWindowState = iconify ? Frame.ICONIFIED : Frame.NORMAL; 620 postWindowStateChangedEvent(newWindowState); 621 622 // REMIND: RepaintManager doesn't repaint iconified windows and 623 // hence ignores any repaint request during deiconification. 624 // So, we need to repaint window explicitly when it becomes normal. 625 if (!iconify) { 626 repaintPeer(); 627 } 628 } 629 630 @Override 631 public void notifyZoom(boolean isZoomed) { 632 int newWindowState = isZoomed ? Frame.MAXIMIZED_BOTH : Frame.NORMAL; 633 postWindowStateChangedEvent(newWindowState); 634 } 635 636 /** 637 * Called by the {@code PlatformWindow} when any part of the window should 638 * be repainted. 639 */ 640 @Override 641 public void notifyExpose(final Rectangle r) { 642 repaintPeer(r); 643 } 644 645 /** 646 * Called by the {@code PlatformWindow} when this window is moved/resized by 647 * user or window insets are changed. There's no notifyReshape() in 648 * LWComponentPeer as the only components which could be resized by user are 649 * top-level windows. 650 */ 651 @Override 652 public void notifyReshape(int x, int y, int w, int h) { 653 Rectangle oldBounds = getBounds(); 654 final boolean invalid = updateInsets(platformWindow.getInsets()); 655 final boolean moved = (x != oldBounds.x) || (y != oldBounds.y); 656 final boolean resized = (w != oldBounds.width) || (h != oldBounds.height); 657 658 // Check if anything changed 659 if (!moved && !resized && !invalid) { 660 return; 661 } 662 // First, update peer's bounds 663 setBounds(x, y, w, h, SET_BOUNDS, false, false); 664 665 // Second, update the graphics config and surface data 666 final boolean isNewDevice = updateGraphicsDevice(); 667 if (isNewDevice) { 668 updateMaximizedBounds(); 669 } 670 671 if (resized || isNewDevice) { 672 replaceSurfaceData(); 673 updateMinimumSize(); 674 } 675 676 // Third, COMPONENT_MOVED/COMPONENT_RESIZED/PAINT events 677 if (moved || invalid) { 678 handleMove(x, y, true); 679 } 680 if (resized || invalid || isNewDevice) { 681 handleResize(w, h, true); 682 repaintPeer(); 683 } 684 685 repositionSecurityWarning(); 686 } 687 688 private void clearBackground(final int w, final int h) { 689 final Graphics g = getOnscreenGraphics(getForeground(), getBackground(), 690 getFont()); 691 if (g != null) { 692 try { 693 if (g instanceof Graphics2D) { 694 ((Graphics2D) g).setComposite(AlphaComposite.Src); 695 } 696 if (isTranslucent()) { 697 g.setColor(nonOpaqueBackground); 698 g.fillRect(0, 0, w, h); 699 } 700 if (!isTextured()) { 701 if (g instanceof SunGraphics2D) { 702 ((SunGraphics2D) g).constrain(0, 0, w, h, getRegion()); 703 } 704 g.setColor(getBackground()); 705 g.fillRect(0, 0, w, h); 706 } 707 } finally { 708 g.dispose(); 709 } 710 } 711 } 712 713 @Override 714 public void notifyUpdateCursor() { 715 getLWToolkit().getCursorManager().updateCursorLater(this); 716 } 717 718 @Override 719 public void notifyActivation(boolean activation, LWWindowPeer opposite) { 720 Window oppositeWindow = (opposite == null)? null : opposite.getTarget(); 721 changeFocusedWindow(activation, oppositeWindow); 722 } 723 724 // MouseDown in non-client area 725 @Override 726 public void notifyNCMouseDown() { 727 // Ungrab except for a click on a Dialog with the grabbing owner 728 if (grabbingWindow != null && 729 !grabbingWindow.isOneOfOwnersOf(this)) 730 { 731 grabbingWindow.ungrab(); 732 } 733 } 734 735 // ---- EVENTS ---- // 736 737 /* 738 * Called by the delegate to dispatch the event to Java. Event 739 * coordinates are relative to non-client window are, i.e. the top-left 740 * point of the client area is (insets.top, insets.left). 741 */ 742 @Override 743 public void notifyMouseEvent(int id, long when, int button, 744 int x, int y, int screenX, int screenY, 745 int modifiers, int clickCount, boolean popupTrigger, 746 byte[] bdata) 747 { 748 // TODO: fill "bdata" member of AWTEvent 749 Rectangle r = getBounds(); 750 // findPeerAt() expects parent coordinates 751 LWComponentPeer<?, ?> targetPeer = findPeerAt(r.x + x, r.y + y); 752 753 if (id == MouseEvent.MOUSE_EXITED) { 754 isMouseOver = false; 755 if (lastMouseEventPeer != null) { 756 if (lastMouseEventPeer.isEnabled()) { 757 Point lp = lastMouseEventPeer.windowToLocal(x, y, 758 this); 759 Component target = lastMouseEventPeer.getTarget(); 760 postMouseExitedEvent(target, when, modifiers, lp, 761 screenX, screenY, clickCount, popupTrigger, button); 762 } 763 764 // Sometimes we may get MOUSE_EXITED after lastCommonMouseEventPeer is switched 765 // to a peer from another window. So we must first check if this peer is 766 // the same as lastWindowPeer 767 if (lastCommonMouseEventPeer != null && lastCommonMouseEventPeer.getWindowPeerOrSelf() == this) { 768 lastCommonMouseEventPeer = null; 769 } 770 lastMouseEventPeer = null; 771 } 772 } else if(id == MouseEvent.MOUSE_ENTERED) { 773 isMouseOver = true; 774 if (targetPeer != null) { 775 if (targetPeer.isEnabled()) { 776 Point lp = targetPeer.windowToLocal(x, y, this); 777 Component target = targetPeer.getTarget(); 778 postMouseEnteredEvent(target, when, modifiers, lp, 779 screenX, screenY, clickCount, popupTrigger, button); 780 } 781 lastCommonMouseEventPeer = targetPeer; 782 lastMouseEventPeer = targetPeer; 783 } 784 } else { 785 PlatformWindow topmostPlatforWindow = 786 platformWindow.getTopmostPlatformWindowUnderMouse(); 787 788 LWWindowPeer topmostWindowPeer = 789 topmostPlatforWindow != null ? topmostPlatforWindow.getPeer() : null; 790 791 // topmostWindowPeer == null condition is added for the backward 792 // compatibility with applets. It can be removed when the 793 // getTopmostPlatformWindowUnderMouse() method will be properly 794 // implemented in CPlatformEmbeddedFrame class 795 if (topmostWindowPeer == this || topmostWindowPeer == null) { 796 generateMouseEnterExitEventsForComponents(when, button, x, y, 797 screenX, screenY, modifiers, clickCount, popupTrigger, 798 targetPeer); 799 } else { 800 LWComponentPeer<?, ?> topmostTargetPeer = 801 topmostWindowPeer != null ? topmostWindowPeer.findPeerAt(r.x + x, r.y + y) : null; 802 topmostWindowPeer.generateMouseEnterExitEventsForComponents(when, button, x, y, 803 screenX, screenY, modifiers, clickCount, popupTrigger, 804 topmostTargetPeer); 805 } 806 807 // TODO: fill "bdata" member of AWTEvent 808 809 int eventButtonMask = (button > 0)? MouseEvent.getMaskForButton(button) : 0; 810 int otherButtonsPressed = modifiers & ~eventButtonMask; 811 812 // For pressed/dragged/released events OS X treats other 813 // mouse buttons as if they were BUTTON2, so we do the same 814 int targetIdx = (button > 3) ? MouseEvent.BUTTON2 - 1 : button - 1; 815 816 // MOUSE_ENTERED/EXITED are generated for the components strictly under 817 // mouse even when dragging. That's why we first update lastMouseEventPeer 818 // based on initial targetPeer value and only then recalculate targetPeer 819 // for MOUSE_DRAGGED/RELEASED events 820 if (id == MouseEvent.MOUSE_PRESSED) { 821 822 // Ungrab only if this window is not an owned window of the grabbing one. 823 if (!isGrabbing() && grabbingWindow != null && 824 !grabbingWindow.isOneOfOwnersOf(this)) 825 { 826 grabbingWindow.ungrab(); 827 } 828 if (otherButtonsPressed == 0) { 829 mouseClickButtons = eventButtonMask; 830 } else { 831 mouseClickButtons |= eventButtonMask; 832 } 833 834 // The window should be focused on mouse click. If it gets activated by the native platform, 835 // this request will be no op. It will take effect when: 836 // 1. A simple not focused window is clicked. 837 // 2. An active but not focused owner frame/dialog is clicked. 838 // The mouse event then will trigger a focus request "in window" to the component, so the window 839 // should gain focus before. 840 requestWindowFocus(CausedFocusEvent.Cause.MOUSE_EVENT); 841 842 mouseDownTarget[targetIdx] = targetPeer; 843 } else if (id == MouseEvent.MOUSE_DRAGGED) { 844 // Cocoa dragged event has the information about which mouse 845 // button is being dragged. Use it to determine the peer that 846 // should receive the dragged event. 847 targetPeer = mouseDownTarget[targetIdx]; 848 mouseClickButtons &= ~modifiers; 849 } else if (id == MouseEvent.MOUSE_RELEASED) { 850 // TODO: currently, mouse released event goes to the same component 851 // that received corresponding mouse pressed event. For most cases, 852 // it's OK, however, we need to make sure that our behavior is consistent 853 // with 1.6 for cases where component in question have been 854 // hidden/removed in between of mouse pressed/released events. 855 targetPeer = mouseDownTarget[targetIdx]; 856 857 if ((modifiers & eventButtonMask) == 0) { 858 mouseDownTarget[targetIdx] = null; 859 } 860 861 // mouseClickButtons is updated below, after MOUSE_CLICK is sent 862 } 863 864 if (targetPeer == null) { 865 //TODO This can happen if this window is invisible. this is correct behavior in this case? 866 targetPeer = this; 867 } 868 869 870 Point lp = targetPeer.windowToLocal(x, y, this); 871 if (targetPeer.isEnabled()) { 872 MouseEvent event = new MouseEvent(targetPeer.getTarget(), id, 873 when, modifiers, lp.x, lp.y, 874 screenX, screenY, clickCount, 875 popupTrigger, button); 876 postEvent(event); 877 } 878 879 if (id == MouseEvent.MOUSE_RELEASED) { 880 if ((mouseClickButtons & eventButtonMask) != 0 881 && targetPeer.isEnabled()) { 882 postEvent(new MouseEvent(targetPeer.getTarget(), 883 MouseEvent.MOUSE_CLICKED, 884 when, modifiers, 885 lp.x, lp.y, screenX, screenY, 886 clickCount, popupTrigger, button)); 887 } 888 mouseClickButtons &= ~eventButtonMask; 889 } 890 } 891 notifyUpdateCursor(); 892 } 893 894 private void generateMouseEnterExitEventsForComponents(long when, 895 int button, int x, int y, int screenX, int screenY, 896 int modifiers, int clickCount, boolean popupTrigger, 897 final LWComponentPeer<?, ?> targetPeer) { 898 899 if (!isMouseOver || targetPeer == lastMouseEventPeer) { 900 return; 901 } 902 903 // Generate Mouse Exit for components 904 if (lastMouseEventPeer != null && lastMouseEventPeer.isEnabled()) { 905 Point oldp = lastMouseEventPeer.windowToLocal(x, y, this); 906 Component target = lastMouseEventPeer.getTarget(); 907 postMouseExitedEvent(target, when, modifiers, oldp, screenX, screenY, 908 clickCount, popupTrigger, button); 909 } 910 lastCommonMouseEventPeer = targetPeer; 911 lastMouseEventPeer = targetPeer; 912 913 // Generate Mouse Enter for components 914 if (targetPeer != null && targetPeer.isEnabled()) { 915 Point newp = targetPeer.windowToLocal(x, y, this); 916 Component target = targetPeer.getTarget(); 917 postMouseEnteredEvent(target, when, modifiers, newp, screenX, screenY, clickCount, popupTrigger, button); 918 } 919 } 920 921 private void postMouseEnteredEvent(Component target, long when, int modifiers, 922 Point loc, int xAbs, int yAbs, 923 int clickCount, boolean popupTrigger, int button) { 924 925 updateSecurityWarningVisibility(); 926 927 postEvent(new MouseEvent(target, 928 MouseEvent.MOUSE_ENTERED, 929 when, modifiers, 930 loc.x, loc.y, xAbs, yAbs, 931 clickCount, popupTrigger, button)); 932 } 933 934 private void postMouseExitedEvent(Component target, long when, int modifiers, 935 Point loc, int xAbs, int yAbs, 936 int clickCount, boolean popupTrigger, int button) { 937 938 updateSecurityWarningVisibility(); 939 940 postEvent(new MouseEvent(target, 941 MouseEvent.MOUSE_EXITED, 942 when, modifiers, 943 loc.x, loc.y, xAbs, yAbs, 944 clickCount, popupTrigger, button)); 945 } 946 947 @Override 948 public void notifyMouseWheelEvent(long when, int x, int y, int modifiers, 949 int scrollType, int scrollAmount, 950 int wheelRotation, double preciseWheelRotation, 951 byte[] bdata) 952 { 953 // TODO: could we just use the last mouse event target here? 954 Rectangle r = getBounds(); 955 // findPeerAt() expects parent coordinates 956 final LWComponentPeer<?, ?> targetPeer = findPeerAt(r.x + x, r.y + y); 957 if (targetPeer == null || !targetPeer.isEnabled()) { 958 return; 959 } 960 961 Point lp = targetPeer.windowToLocal(x, y, this); 962 // TODO: fill "bdata" member of AWTEvent 963 // TODO: screenX/screenY 964 postEvent(new MouseWheelEvent(targetPeer.getTarget(), 965 MouseEvent.MOUSE_WHEEL, 966 when, modifiers, 967 lp.x, lp.y, 968 0, 0, /* screenX, Y */ 969 0 /* clickCount */, false /* popupTrigger */, 970 scrollType, scrollAmount, 971 wheelRotation, preciseWheelRotation)); 972 } 973 974 /* 975 * Called by the delegate when a key is pressed. 976 */ 977 @Override 978 public void notifyKeyEvent(int id, long when, int modifiers, 979 int keyCode, char keyChar, int keyLocation) 980 { 981 LWKeyboardFocusManagerPeer kfmPeer = LWKeyboardFocusManagerPeer.getInstance(); 982 Component focusOwner = kfmPeer.getCurrentFocusOwner(); 983 984 if (focusOwner == null) { 985 focusOwner = kfmPeer.getCurrentFocusedWindow(); 986 if (focusOwner == null) { 987 focusOwner = this.getTarget(); 988 } 989 } 990 991 KeyEvent keyEvent = new KeyEvent(focusOwner, id, when, modifiers, 992 keyCode, keyChar, keyLocation); 993 AWTAccessor.getKeyEventAccessor().setExtendedKeyCode(keyEvent, 994 (keyChar == KeyEvent.CHAR_UNDEFINED) ? keyCode 995 : ExtendedKeyCodes.getExtendedKeyCodeForChar(keyChar)); 996 postEvent(keyEvent); 997 } 998 999 // ---- UTILITY METHODS ---- // 1000 1001 private void activateDisplayListener() { 1002 final GraphicsEnvironment ge = 1003 GraphicsEnvironment.getLocalGraphicsEnvironment(); 1004 ((SunGraphicsEnvironment) ge).addDisplayChangedListener(this); 1005 } 1006 1007 private void deactivateDisplayListener() { 1008 final GraphicsEnvironment ge = 1009 GraphicsEnvironment.getLocalGraphicsEnvironment(); 1010 ((SunGraphicsEnvironment) ge).removeDisplayChangedListener(this); 1011 } 1012 1013 private void postWindowStateChangedEvent(int newWindowState) { 1014 if (getTarget() instanceof Frame) { 1015 AWTAccessor.getFrameAccessor().setExtendedState( 1016 (Frame)getTarget(), newWindowState); 1017 } 1018 1019 WindowEvent stateChangedEvent = new WindowEvent(getTarget(), 1020 WindowEvent.WINDOW_STATE_CHANGED, 1021 windowState, newWindowState); 1022 postEvent(stateChangedEvent); 1023 windowState = newWindowState; 1024 1025 updateSecurityWarningVisibility(); 1026 } 1027 1028 private static int getGraphicsConfigScreen(GraphicsConfiguration gc) { 1029 // TODO: this method can be implemented in a more 1030 // efficient way by forwarding to the delegate 1031 GraphicsDevice gd = gc.getDevice(); 1032 GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); 1033 GraphicsDevice[] gds = ge.getScreenDevices(); 1034 for (int i = 0; i < gds.length; i++) { 1035 if (gds[i] == gd) { 1036 return i; 1037 } 1038 } 1039 // Should never happen if gc is a screen device config 1040 return 0; 1041 } 1042 1043 /* 1044 * This method is called when window's graphics config is changed from 1045 * the app code (e.g. when the window is made non-opaque) or when 1046 * the window is moved to another screen by user. 1047 * 1048 * Returns true if the graphics config has been changed, false otherwise. 1049 */ 1050 private boolean setGraphicsConfig(GraphicsConfiguration gc) { 1051 synchronized (getStateLock()) { 1052 if (graphicsConfig == gc) { 1053 return false; 1054 } 1055 // If window's graphics config is changed from the app code, the 1056 // config correspond to the same device as before; when the window 1057 // is moved by user, graphicsDevice is updated in notifyReshape(). 1058 // In either case, there's nothing to do with screenOn here 1059 graphicsConfig = gc; 1060 } 1061 // SurfaceData is replaced later in updateGraphicsData() 1062 return true; 1063 } 1064 1065 /** 1066 * Returns true if the GraphicsDevice has been changed, false otherwise. 1067 */ 1068 public boolean updateGraphicsDevice() { 1069 GraphicsDevice newGraphicsDevice = platformWindow.getGraphicsDevice(); 1070 synchronized (getStateLock()) { 1071 if (graphicsDevice == newGraphicsDevice) { 1072 return false; 1073 } 1074 graphicsDevice = newGraphicsDevice; 1075 } 1076 1077 final GraphicsConfiguration newGC = newGraphicsDevice.getDefaultConfiguration(); 1078 1079 if (!setGraphicsConfig(newGC)) return false; 1080 1081 SunToolkit.executeOnEventHandlerThread(getTarget(), new Runnable() { 1082 public void run() { 1083 AWTAccessor.getComponentAccessor().setGraphicsConfiguration(getTarget(), newGC); 1084 } 1085 }); 1086 return true; 1087 } 1088 1089 @Override 1090 public final void displayChanged() { 1091 if (updateGraphicsDevice()) { 1092 updateMinimumSize(); 1093 } 1094 1095 updateMaximizedBounds(); 1096 1097 // Replace surface unconditionally, because internal state of the 1098 // GraphicsDevice could be changed. 1099 replaceSurfaceData(); 1100 repaintPeer(); 1101 } 1102 1103 @Override 1104 public final void paletteChanged() { 1105 // components do not need to react to this event. 1106 } 1107 1108 /* 1109 * May be called by delegate to provide SD to Java2D code. 1110 */ 1111 public SurfaceData getSurfaceData() { 1112 synchronized (surfaceDataLock) { 1113 return surfaceData; 1114 } 1115 } 1116 1117 private void replaceSurfaceData() { 1118 replaceSurfaceData(true); 1119 } 1120 1121 private void replaceSurfaceData(final boolean blit) { 1122 synchronized (surfaceDataLock) { 1123 final SurfaceData oldData = getSurfaceData(); 1124 surfaceData = platformWindow.replaceSurfaceData(); 1125 final Rectangle size = getSize(); 1126 if (getSurfaceData() != null && oldData != getSurfaceData()) { 1127 clearBackground(size.width, size.height); 1128 } 1129 1130 if (blit) { 1131 blitSurfaceData(oldData, getSurfaceData()); 1132 } 1133 1134 if (oldData != null && oldData != getSurfaceData()) { 1135 // TODO: drop oldData for D3D/WGL pipelines 1136 // This can only happen when this peer is being created 1137 oldData.flush(); 1138 } 1139 } 1140 flushOnscreenGraphics(); 1141 } 1142 1143 private void blitSurfaceData(final SurfaceData src, final SurfaceData dst) { 1144 //TODO blit. proof-of-concept 1145 if (src != dst && src != null && dst != null 1146 && !(dst instanceof NullSurfaceData) 1147 && !(src instanceof NullSurfaceData) 1148 && src.getSurfaceType().equals(dst.getSurfaceType()) 1149 && src.getDefaultScale() == dst.getDefaultScale()) { 1150 final Rectangle size = src.getBounds(); 1151 final Blit blit = Blit.locate(src.getSurfaceType(), 1152 CompositeType.Src, 1153 dst.getSurfaceType()); 1154 if (blit != null) { 1155 blit.Blit(src, dst, AlphaComposite.Src, null, 0, 0, 0, 0, 1156 size.width, size.height); 1157 } 1158 } 1159 } 1160 1161 /** 1162 * Request the window insets from the delegate and compares it with the 1163 * current one. This method is mostly called by the delegate, e.g. when the 1164 * window state is changed and insets should be recalculated. 1165 * <p/> 1166 * This method may be called on the toolkit thread. 1167 */ 1168 public final boolean updateInsets(final Insets newInsets) { 1169 synchronized (getStateLock()) { 1170 if (insets.equals(newInsets)) { 1171 return false; 1172 } 1173 insets = newInsets; 1174 } 1175 return true; 1176 } 1177 1178 public static LWWindowPeer getWindowUnderCursor() { 1179 return lastCommonMouseEventPeer != null ? lastCommonMouseEventPeer.getWindowPeerOrSelf() : null; 1180 } 1181 1182 public static LWComponentPeer<?, ?> getPeerUnderCursor() { 1183 return lastCommonMouseEventPeer; 1184 } 1185 1186 /* 1187 * Requests platform to set native focus on a frame/dialog. 1188 * In case of a simple window, triggers appropriate java focus change. 1189 */ 1190 public boolean requestWindowFocus(CausedFocusEvent.Cause cause) { 1191 if (focusLog.isLoggable(PlatformLogger.Level.FINE)) { 1192 focusLog.fine("requesting native focus to " + this); 1193 } 1194 1195 if (!focusAllowedFor()) { 1196 focusLog.fine("focus is not allowed"); 1197 return false; 1198 } 1199 1200 if (platformWindow.rejectFocusRequest(cause)) { 1201 return false; 1202 } 1203 1204 AppContext targetAppContext = AWTAccessor.getComponentAccessor().getAppContext(getTarget()); 1205 KeyboardFocusManager kfm = AWTAccessor.getKeyboardFocusManagerAccessor() 1206 .getCurrentKeyboardFocusManager(targetAppContext); 1207 Window currentActive = kfm.getActiveWindow(); 1208 1209 1210 Window opposite = LWKeyboardFocusManagerPeer.getInstance(). 1211 getCurrentFocusedWindow(); 1212 1213 // Make the owner active window. 1214 if (isSimpleWindow()) { 1215 LWWindowPeer owner = getOwnerFrameDialog(this); 1216 1217 // If owner is not natively active, request native 1218 // activation on it w/o sending events up to java. 1219 if (owner != null && !owner.platformWindow.isActive()) { 1220 if (focusLog.isLoggable(PlatformLogger.Level.FINE)) { 1221 focusLog.fine("requesting native focus to the owner " + owner); 1222 } 1223 LWWindowPeer currentActivePeer = currentActive == null ? null : 1224 (LWWindowPeer) AWTAccessor.getComponentAccessor().getPeer( 1225 currentActive); 1226 1227 // Ensure the opposite is natively active and suppress sending events. 1228 if (currentActivePeer != null && currentActivePeer.platformWindow.isActive()) { 1229 if (focusLog.isLoggable(PlatformLogger.Level.FINE)) { 1230 focusLog.fine("the opposite is " + currentActivePeer); 1231 } 1232 currentActivePeer.skipNextFocusChange = true; 1233 } 1234 owner.skipNextFocusChange = true; 1235 1236 owner.platformWindow.requestWindowFocus(); 1237 } 1238 1239 // DKFM will synthesize all the focus/activation events correctly. 1240 changeFocusedWindow(true, opposite); 1241 return true; 1242 1243 // In case the toplevel is active but not focused, change focus directly, 1244 // as requesting native focus on it will not have effect. 1245 } else if (getTarget() == currentActive && !getTarget().hasFocus()) { 1246 1247 changeFocusedWindow(true, opposite); 1248 return true; 1249 } 1250 1251 return platformWindow.requestWindowFocus(); 1252 } 1253 1254 protected boolean focusAllowedFor() { 1255 Window window = getTarget(); 1256 // TODO: check if modal blocked 1257 return window.isVisible() && window.isEnabled() && isFocusableWindow(); 1258 } 1259 1260 private boolean isFocusableWindow() { 1261 boolean focusable = targetFocusable; 1262 if (isSimpleWindow()) { 1263 LWWindowPeer ownerPeer = getOwnerFrameDialog(this); 1264 if (ownerPeer == null) { 1265 return false; 1266 } 1267 return focusable && ownerPeer.targetFocusable; 1268 } 1269 return focusable; 1270 } 1271 1272 public boolean isSimpleWindow() { 1273 Window window = getTarget(); 1274 return !(window instanceof Dialog || window instanceof Frame); 1275 } 1276 1277 @Override 1278 public void emulateActivation(boolean activate) { 1279 changeFocusedWindow(activate, null); 1280 } 1281 1282 @SuppressWarnings("deprecation") 1283 private boolean isOneOfOwnersOf(LWWindowPeer peer) { 1284 Window owner = (peer != null ? peer.getTarget().getOwner() : null); 1285 while (owner != null) { 1286 final ComponentAccessor acc = AWTAccessor.getComponentAccessor(); 1287 if (acc.getPeer(owner) == this) { 1288 return true; 1289 } 1290 owner = owner.getOwner(); 1291 } 1292 return false; 1293 } 1294 1295 /* 1296 * Changes focused window on java level. 1297 */ 1298 protected void changeFocusedWindow(boolean becomesFocused, Window opposite) { 1299 if (focusLog.isLoggable(PlatformLogger.Level.FINE)) { 1300 focusLog.fine((becomesFocused?"gaining":"loosing") + " focus window: " + this); 1301 } 1302 if (skipNextFocusChange) { 1303 focusLog.fine("skipping focus change"); 1304 skipNextFocusChange = false; 1305 return; 1306 } 1307 if (!isFocusableWindow() && becomesFocused) { 1308 focusLog.fine("the window is not focusable"); 1309 return; 1310 } 1311 if (becomesFocused) { 1312 synchronized (getPeerTreeLock()) { 1313 if (blocker != null) { 1314 if (focusLog.isLoggable(PlatformLogger.Level.FINEST)) { 1315 focusLog.finest("the window is blocked by " + blocker); 1316 } 1317 return; 1318 } 1319 } 1320 } 1321 1322 // Note, the method is not called: 1323 // - when the opposite (gaining focus) window is an owned/owner window. 1324 // - for a simple window in any case. 1325 if (!becomesFocused && 1326 (isGrabbing() || this.isOneOfOwnersOf(grabbingWindow))) 1327 { 1328 if (focusLog.isLoggable(PlatformLogger.Level.FINE)) { 1329 focusLog.fine("ungrabbing on " + grabbingWindow); 1330 } 1331 // ungrab a simple window if its owner looses activation. 1332 grabbingWindow.ungrab(); 1333 } 1334 1335 KeyboardFocusManagerPeer kfmPeer = LWKeyboardFocusManagerPeer.getInstance(); 1336 1337 if (!becomesFocused && kfmPeer.getCurrentFocusedWindow() != getTarget()) { 1338 // late window focus lost event - ingoring 1339 return; 1340 } 1341 1342 kfmPeer.setCurrentFocusedWindow(becomesFocused ? getTarget() : null); 1343 1344 int eventID = becomesFocused ? WindowEvent.WINDOW_GAINED_FOCUS : WindowEvent.WINDOW_LOST_FOCUS; 1345 WindowEvent windowEvent = new TimedWindowEvent(getTarget(), eventID, opposite, System.currentTimeMillis()); 1346 1347 // TODO: wrap in SequencedEvent 1348 postEvent(windowEvent); 1349 } 1350 1351 /* 1352 * Retrieves the owner of the peer. 1353 * Note: this method returns the owner which can be activated, (i.e. the instance 1354 * of Frame or Dialog may be returned). 1355 */ 1356 static LWWindowPeer getOwnerFrameDialog(LWWindowPeer peer) { 1357 Window owner = (peer != null ? peer.getTarget().getOwner() : null); 1358 while (owner != null && !(owner instanceof Frame || owner instanceof Dialog)) { 1359 owner = owner.getOwner(); 1360 } 1361 return owner == null ? null : AWTAccessor.getComponentAccessor() 1362 .getPeer(owner); 1363 } 1364 1365 /** 1366 * Returns the foremost modal blocker of this window, or null. 1367 */ 1368 public LWWindowPeer getBlocker() { 1369 synchronized (getPeerTreeLock()) { 1370 LWWindowPeer blocker = this.blocker; 1371 if (blocker == null) { 1372 return null; 1373 } 1374 while (blocker.blocker != null) { 1375 blocker = blocker.blocker; 1376 } 1377 return blocker; 1378 } 1379 } 1380 1381 @Override 1382 public void enterFullScreenMode() { 1383 platformWindow.enterFullScreenMode(); 1384 updateSecurityWarningVisibility(); 1385 } 1386 1387 @Override 1388 public void exitFullScreenMode() { 1389 platformWindow.exitFullScreenMode(); 1390 updateSecurityWarningVisibility(); 1391 } 1392 1393 public long getLayerPtr() { 1394 return getPlatformWindow().getLayerPtr(); 1395 } 1396 1397 void grab() { 1398 if (grabbingWindow != null && !isGrabbing()) { 1399 grabbingWindow.ungrab(); 1400 } 1401 grabbingWindow = this; 1402 } 1403 1404 final void ungrab(boolean doPost) { 1405 if (isGrabbing()) { 1406 grabbingWindow = null; 1407 if (doPost) { 1408 postEvent(new UngrabEvent(getTarget())); 1409 } 1410 } 1411 } 1412 1413 void ungrab() { 1414 ungrab(true); 1415 } 1416 1417 private boolean isGrabbing() { 1418 return this == grabbingWindow; 1419 } 1420 1421 public PeerType getPeerType() { 1422 return peerType; 1423 } 1424 1425 public void updateSecurityWarningVisibility() { 1426 if (warningWindow == null) { 1427 return; 1428 } 1429 1430 if (!isVisible()) { 1431 return; // The warning window should already be hidden. 1432 } 1433 1434 boolean show = false; 1435 1436 if (!platformWindow.isFullScreenMode()) { 1437 if (isVisible()) { 1438 if (LWKeyboardFocusManagerPeer.getInstance().getCurrentFocusedWindow() == 1439 getTarget()) { 1440 show = true; 1441 } 1442 1443 if (platformWindow.isUnderMouse() || warningWindow.isUnderMouse()) { 1444 show = true; 1445 } 1446 } 1447 } 1448 1449 warningWindow.setVisible(show, true); 1450 } 1451 1452 @Override 1453 public String toString() { 1454 return super.toString() + " [target is " + getTarget() + "]"; 1455 } 1456 }