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