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