1 /* 2 * Copyright (c) 2002, 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 package sun.awt.X11; 26 27 import java.awt.*; 28 29 import java.awt.event.ComponentEvent; 30 import java.awt.event.InvocationEvent; 31 import java.awt.event.WindowEvent; 32 33 import sun.awt.IconInfo; 34 import sun.util.logging.PlatformLogger; 35 36 import sun.awt.AWTAccessor; 37 import sun.awt.SunToolkit; 38 39 abstract class XDecoratedPeer extends XWindowPeer { 40 private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.X11.XDecoratedPeer"); 41 private static final PlatformLogger insLog = PlatformLogger.getLogger("sun.awt.X11.insets.XDecoratedPeer"); 42 private static final PlatformLogger focusLog = PlatformLogger.getLogger("sun.awt.X11.focus.XDecoratedPeer"); 43 private static final PlatformLogger iconLog = PlatformLogger.getLogger("sun.awt.X11.icon.XDecoratedPeer"); 44 45 // Set to true when we get the first ConfigureNotify after being 46 // reparented - indicates that WM has adopted the top-level. 47 boolean configure_seen; 48 boolean insets_corrected; 49 50 XIconWindow iconWindow; 51 WindowDimensions dimensions; 52 XContentWindow content; 53 Insets currentInsets; 54 XFocusProxyWindow focusProxy; 55 56 XDecoratedPeer(Window target) { 57 super(target); 58 } 59 60 XDecoratedPeer(XCreateWindowParams params) { 61 super(params); 62 } 63 64 public long getShell() { 65 return window; 66 } 67 68 public long getContentWindow() { 69 return (content == null) ? window : content.getWindow(); 70 } 71 72 void preInit(XCreateWindowParams params) { 73 super.preInit(params); 74 winAttr.initialFocus = true; 75 76 currentInsets = new Insets(0,0,0,0); 77 applyGuessedInsets(); 78 79 Rectangle bounds = (Rectangle)params.get(BOUNDS); 80 dimensions = new WindowDimensions(bounds, getRealInsets(), false); 81 params.put(BOUNDS, dimensions.getClientRect()); 82 if (insLog.isLoggable(PlatformLogger.Level.FINE)) { 83 insLog.fine("Initial dimensions {0}", dimensions); 84 } 85 86 // Deny default processing of these events on the shell - proxy will take care of 87 // them instead 88 Long eventMask = (Long)params.get(EVENT_MASK); 89 params.add(EVENT_MASK, Long.valueOf(eventMask.longValue() & ~(XConstants.FocusChangeMask | XConstants.KeyPressMask | XConstants.KeyReleaseMask))); 90 } 91 92 void postInit(XCreateWindowParams params) { 93 // The size hints must be set BEFORE mapping the window (see 6895647) 94 updateSizeHints(dimensions); 95 96 // The super method maps the window if it's visible on the shared level 97 super.postInit(params); 98 99 // The lines that follow need to be in a postInit, so they 100 // happen after the X window is created. 101 initResizability(); 102 XWM.requestWMExtents(getWindow()); 103 104 content = XContentWindow.createContent(this); 105 106 if (warningWindow != null) { 107 warningWindow.toFront(); 108 } 109 focusProxy = createFocusProxy(); 110 } 111 112 void setIconHints(java.util.List<IconInfo> icons) { 113 if (!XWM.getWM().setNetWMIcon(this, icons)) { 114 if (icons.size() > 0) { 115 if (iconWindow == null) { 116 iconWindow = new XIconWindow(this); 117 } 118 iconWindow.setIconImages(icons); 119 } 120 } 121 } 122 123 public void updateMinimumSize() { 124 super.updateMinimumSize(); 125 updateMinSizeHints(); 126 } 127 128 private void updateMinSizeHints() { 129 if (isResizable()) { 130 Dimension minimumSize = getTargetMinimumSize(); 131 if (minimumSize != null) { 132 Insets insets = getRealInsets(); 133 int minWidth = minimumSize.width - insets.left - insets.right; 134 int minHeight = minimumSize.height - insets.top - insets.bottom; 135 if (minWidth < 0) minWidth = 0; 136 if (minHeight < 0) minHeight = 0; 137 setSizeHints(XUtilConstants.PMinSize | (isLocationByPlatform()?0:(XUtilConstants.PPosition | XUtilConstants.USPosition)), 138 getX(), getY(), minWidth, minHeight); 139 if (isVisible()) { 140 Rectangle bounds = getShellBounds(); 141 int nw = (bounds.width < minWidth) ? minWidth : bounds.width; 142 int nh = (bounds.height < minHeight) ? minHeight : bounds.height; 143 if (nw != bounds.width || nh != bounds.height) { 144 setShellSize(new Rectangle(0, 0, nw, nh)); 145 } 146 } 147 } else { 148 boolean isMinSizeSet = isMinSizeSet(); 149 XWM.removeSizeHints(this, XUtilConstants.PMinSize); 150 /* Some WMs need remap to redecorate the window */ 151 if (isMinSizeSet && isShowing() && XWM.needRemap(this)) { 152 /* 153 * Do the re/mapping at the Xlib level. Since we essentially 154 * work around a WM bug we don't want this hack to be exposed 155 * to Intrinsics (i.e. don't mess with grabs, callbacks etc). 156 */ 157 xSetVisible(false); 158 XToolkit.XSync(); 159 xSetVisible(true); 160 } 161 } 162 } 163 } 164 165 XFocusProxyWindow createFocusProxy() { 166 return new XFocusProxyWindow(this); 167 } 168 169 protected XAtomList getWMProtocols() { 170 XAtomList protocols = super.getWMProtocols(); 171 protocols.add(wm_delete_window); 172 protocols.add(wm_take_focus); 173 return protocols; 174 } 175 176 public Graphics getGraphics() { 177 AWTAccessor.ComponentAccessor compAccessor = AWTAccessor.getComponentAccessor(); 178 return getGraphics(content.surfaceData, 179 compAccessor.getForeground(target), 180 compAccessor.getBackground(target), 181 compAccessor.getFont(target)); 182 } 183 184 public void setTitle(String title) { 185 if (log.isLoggable(PlatformLogger.Level.FINE)) { 186 log.fine("Title is " + title); 187 } 188 winAttr.title = title; 189 updateWMName(); 190 } 191 192 protected String getWMName() { 193 if (winAttr.title == null || winAttr.title.trim().equals("")) { 194 return " "; 195 } else { 196 return winAttr.title; 197 } 198 } 199 200 void updateWMName() { 201 super.updateWMName(); 202 String name = getWMName(); 203 XToolkit.awtLock(); 204 try { 205 if (name == null || name.trim().equals("")) { 206 name = "Java"; 207 } 208 XAtom iconNameAtom = XAtom.get(XAtom.XA_WM_ICON_NAME); 209 iconNameAtom.setProperty(getWindow(), name); 210 XAtom netIconNameAtom = XAtom.get("_NET_WM_ICON_NAME"); 211 netIconNameAtom.setPropertyUTF8(getWindow(), name); 212 } finally { 213 XToolkit.awtUnlock(); 214 } 215 } 216 217 // NOTE: This method may be called by privileged threads. 218 // DO NOT INVOKE CLIENT CODE ON THIS THREAD! 219 public void handleIconify() { 220 postEvent(new WindowEvent((Window)target, WindowEvent.WINDOW_ICONIFIED)); 221 } 222 223 // NOTE: This method may be called by privileged threads. 224 // DO NOT INVOKE CLIENT CODE ON THIS THREAD! 225 public void handleDeiconify() { 226 postEvent(new WindowEvent((Window)target, WindowEvent.WINDOW_DEICONIFIED)); 227 } 228 229 public void handleFocusEvent(XEvent xev) { 230 super.handleFocusEvent(xev); 231 XFocusChangeEvent xfe = xev.get_xfocus(); 232 233 // If we somehow received focus events forward it instead to proxy 234 // FIXME: Shouldn't we instead check for inferrior? 235 if (focusLog.isLoggable(PlatformLogger.Level.FINER)) { 236 focusLog.finer("Received focus event on shell: " + xfe); 237 } 238 // focusProxy.xRequestFocus(); 239 } 240 241 /*************************************************************************************** 242 * I N S E T S C O D E 243 **************************************************************************************/ 244 245 protected boolean isInitialReshape() { 246 return false; 247 } 248 249 private static Insets difference(Insets i1, Insets i2) { 250 return new Insets(i1.top-i2.top, i1.left - i2.left, i1.bottom-i2.bottom, i1.right-i2.right); 251 } 252 253 private static boolean isNull(Insets i) { 254 return (i == null) || ((i.left | i.top | i.right | i.bottom) == 0); 255 } 256 257 private static Insets copy(Insets i) { 258 return new Insets(i.top, i.left, i.bottom, i.right); 259 } 260 261 // insets which we get from WM (e.g from _NET_FRAME_EXTENTS) 262 private Insets wm_set_insets; 263 264 private Insets getWMSetInsets(XAtom changedAtom) { 265 if (isEmbedded()) { 266 return null; 267 } 268 269 if (wm_set_insets != null) { 270 return wm_set_insets; 271 } 272 273 if (changedAtom == null) { 274 wm_set_insets = XWM.getInsetsFromExtents(getWindow()); 275 } else { 276 wm_set_insets = XWM.getInsetsFromProp(getWindow(), changedAtom); 277 } 278 279 if (insLog.isLoggable(PlatformLogger.Level.FINER)) { 280 insLog.finer("FRAME_EXTENTS: {0}", wm_set_insets); 281 } 282 283 if (wm_set_insets != null) { 284 wm_set_insets = copy(wm_set_insets); 285 } 286 return wm_set_insets; 287 } 288 289 private void resetWMSetInsets() { 290 wm_set_insets = null; 291 } 292 293 public void handlePropertyNotify(XEvent xev) { 294 super.handlePropertyNotify(xev); 295 296 XPropertyEvent ev = xev.get_xproperty(); 297 if (ev.get_atom() == XWM.XA_KDE_NET_WM_FRAME_STRUT.getAtom() 298 || ev.get_atom() == XWM.XA_NET_FRAME_EXTENTS.getAtom()) 299 { 300 getWMSetInsets(XAtom.get(ev.get_atom())); 301 } 302 } 303 304 long reparent_serial = 0; 305 306 public void handleReparentNotifyEvent(XEvent xev) { 307 XReparentEvent xe = xev.get_xreparent(); 308 if (insLog.isLoggable(PlatformLogger.Level.FINE)) { 309 insLog.fine(xe.toString()); 310 } 311 reparent_serial = xe.get_serial(); 312 XToolkit.awtLock(); 313 try { 314 long root = XlibWrapper.RootWindow(XToolkit.getDisplay(), getScreenNumber()); 315 316 if (isEmbedded()) { 317 setReparented(true); 318 insets_corrected = true; 319 return; 320 } 321 Component t = target; 322 if (getDecorations() == XWindowAttributesData.AWT_DECOR_NONE) { 323 setReparented(true); 324 insets_corrected = true; 325 reshape(dimensions, SET_SIZE, false); 326 } else if (xe.get_parent() == root) { 327 configure_seen = false; 328 insets_corrected = false; 329 330 /* 331 * We can be repareted to root for two reasons: 332 * . setVisible(false) 333 * . WM exited 334 */ 335 if (isVisible()) { /* WM exited */ 336 /* Work around 4775545 */ 337 XWM.getWM().unshadeKludge(this); 338 insLog.fine("- WM exited"); 339 } else { 340 insLog.fine(" - reparent due to hide"); 341 } 342 } else { /* reparented to WM frame, figure out our insets */ 343 setReparented(true); 344 insets_corrected = false; 345 346 // Check if we have insets provided by the WM 347 Insets correctWM = getWMSetInsets(null); 348 if (correctWM != null) { 349 if (insLog.isLoggable(PlatformLogger.Level.FINER)) { 350 insLog.finer("wm-provided insets {0}", correctWM); 351 } 352 // If these insets are equal to our current insets - no actions are necessary 353 Insets dimInsets = dimensions.getInsets(); 354 if (correctWM.equals(dimInsets)) { 355 insLog.finer("Insets are the same as estimated - no additional reshapes necessary"); 356 no_reparent_artifacts = true; 357 insets_corrected = true; 358 applyGuessedInsets(); 359 return; 360 } 361 } else { 362 correctWM = XWM.getWM().getInsets(this, xe.get_window(), xe.get_parent()); 363 364 if (insLog.isLoggable(PlatformLogger.Level.FINER)) { 365 if (correctWM != null) { 366 insLog.finer("correctWM {0}", correctWM); 367 } else { 368 insLog.finer("correctWM insets are not available, waiting for configureNotify"); 369 } 370 } 371 } 372 373 if (correctWM != null) { 374 handleCorrectInsets(correctWM); 375 } 376 } 377 } finally { 378 XToolkit.awtUnlock(); 379 } 380 } 381 382 protected void handleCorrectInsets(Insets correctWM) { 383 XToolkit.awtLock(); 384 try { 385 /* 386 * Ok, now see if we need adjust window size because 387 * initial insets were wrong (most likely they were). 388 */ 389 Insets correction = difference(correctWM, currentInsets); 390 if (insLog.isLoggable(PlatformLogger.Level.FINEST)) { 391 insLog.finest("Corrention {0}", correction); 392 } 393 if (!isNull(correction)) { 394 currentInsets = copy(correctWM); 395 applyGuessedInsets(); 396 397 //Fix for 6318109: PIT: Min Size is not honored properly when a 398 //smaller size is specified in setSize(), XToolkit 399 //update minimum size hints 400 updateMinSizeHints(); 401 } 402 if (insLog.isLoggable(PlatformLogger.Level.FINER)) { 403 insLog.finer("Dimensions before reparent: " + dimensions); 404 } 405 406 dimensions.setInsets(getRealInsets()); 407 insets_corrected = true; 408 409 if (isMaximized()) { 410 return; 411 } 412 413 /* 414 * If this window has been sized by a pack() we need 415 * to keep the interior geometry intact. Since pack() 416 * computed width and height with wrong insets, we 417 * must adjust the target dimensions appropriately. 418 */ 419 if ((getHints().get_flags() & (XUtilConstants.USPosition | XUtilConstants.PPosition)) != 0) { 420 reshape(dimensions, SET_BOUNDS, false); 421 } else { 422 reshape(dimensions, SET_SIZE, false); 423 } 424 } finally { 425 XToolkit.awtUnlock(); 426 } 427 } 428 429 public void handleMoved(WindowDimensions dims) { 430 Point loc = dims.getLocation(); 431 AWTAccessor.getComponentAccessor().setLocation(target, loc.x, loc.y); 432 postEvent(new ComponentEvent(target, ComponentEvent.COMPONENT_MOVED)); 433 } 434 435 436 protected Insets guessInsets() { 437 if (isEmbedded() || isTargetUndecorated()) { 438 return new Insets(0, 0, 0, 0); 439 } else { 440 if (!isNull(currentInsets)) { 441 /* insets were set on wdata by System Properties */ 442 return copy(currentInsets); 443 } else { 444 Insets res = getWMSetInsets(null); 445 if (res == null) { 446 res = XWM.getWM().guessInsets(this); 447 } 448 return res; 449 } 450 } 451 } 452 453 private void applyGuessedInsets() { 454 Insets guessed = guessInsets(); 455 currentInsets = copy(guessed); 456 } 457 458 public void revalidate() { 459 XToolkit.executeOnEventHandlerThread(target, new Runnable() { 460 public void run() { 461 target.invalidate(); 462 target.validate(); 463 } 464 }); 465 } 466 467 Insets getRealInsets() { 468 if (isNull(currentInsets)) { 469 applyGuessedInsets(); 470 } 471 return currentInsets; 472 } 473 474 public Insets getInsets() { 475 Insets in = copy(getRealInsets()); 476 in.top += getMenuBarHeight(); 477 if (insLog.isLoggable(PlatformLogger.Level.FINEST)) { 478 insLog.finest("Get insets returns {0}", in); 479 } 480 return in; 481 } 482 483 boolean gravityBug() { 484 return XWM.configureGravityBuggy(); 485 } 486 487 // The height of area used to display current active input method 488 int getInputMethodHeight() { 489 return 0; 490 } 491 492 void updateSizeHints(WindowDimensions dims) { 493 Rectangle rec = dims.getClientRect(); 494 checkShellRect(rec); 495 updateSizeHints(rec.x, rec.y, rec.width, rec.height); 496 } 497 498 void updateSizeHints() { 499 updateSizeHints(dimensions); 500 } 501 502 // Coordinates are that of the target 503 // Called only on Toolkit thread 504 public void reshape(WindowDimensions newDimensions, int op, 505 boolean userReshape) 506 { 507 if (insLog.isLoggable(PlatformLogger.Level.FINE)) { 508 insLog.fine("Reshaping " + this + " to " + newDimensions + " op " + op + " user reshape " + userReshape); 509 } 510 if (userReshape) { 511 // We handle only userReshape == true cases. It means that 512 // if the window manager or any other part of the windowing 513 // system sets inappropriate size for this window, we can 514 // do nothing but accept it. 515 Rectangle newBounds = newDimensions.getBounds(); 516 Insets insets = newDimensions.getInsets(); 517 // Inherit isClientSizeSet from newDimensions 518 if (newDimensions.isClientSizeSet()) { 519 newBounds = new Rectangle(newBounds.x, newBounds.y, 520 newBounds.width - insets.left - insets.right, 521 newBounds.height - insets.top - insets.bottom); 522 } 523 newDimensions = new WindowDimensions(newBounds, insets, newDimensions.isClientSizeSet()); 524 } 525 XToolkit.awtLock(); 526 try { 527 if (!isReparented() || !isVisible()) { 528 if (insLog.isLoggable(PlatformLogger.Level.FINE)) { 529 insLog.fine("- not reparented({0}) or not visible({1}), default reshape", 530 Boolean.valueOf(isReparented()), Boolean.valueOf(visible)); 531 } 532 533 // Fix for 6323293. 534 // This actually is needed to preserve compatibility with previous releases - 535 // some of licensees are expecting componentMoved event on invisible one while 536 // its location changes. 537 Point oldLocation = getLocation(); 538 539 Point newLocation = new Point(AWTAccessor.getComponentAccessor().getX(target), 540 AWTAccessor.getComponentAccessor().getY(target)); 541 542 if (!newLocation.equals(oldLocation)) { 543 handleMoved(newDimensions); 544 } 545 546 dimensions = new WindowDimensions(newDimensions); 547 updateSizeHints(dimensions); 548 Rectangle client = dimensions.getClientRect(); 549 checkShellRect(client); 550 setShellBounds(client); 551 if (content != null && 552 !content.getSize().equals(newDimensions.getSize())) 553 { 554 reconfigureContentWindow(newDimensions); 555 } 556 return; 557 } 558 559 int wm = XWM.getWMID(); 560 updateChildrenSizes(); 561 applyGuessedInsets(); 562 563 Rectangle shellRect = newDimensions.getClientRect(); 564 565 if (gravityBug()) { 566 Insets in = newDimensions.getInsets(); 567 shellRect.translate(in.left, in.top); 568 } 569 570 if ((op & NO_EMBEDDED_CHECK) == 0 && isEmbedded()) { 571 shellRect.setLocation(0, 0); 572 } 573 574 checkShellRectSize(shellRect); 575 if (!isEmbedded()) { 576 checkShellRectPos(shellRect); 577 } 578 579 op = op & ~NO_EMBEDDED_CHECK; 580 581 if (op == SET_LOCATION) { 582 setShellPosition(shellRect); 583 } else if (isResizable()) { 584 if (op == SET_BOUNDS) { 585 setShellBounds(shellRect); 586 } else { 587 setShellSize(shellRect); 588 } 589 } else { 590 XWM.setShellNotResizable(this, newDimensions, shellRect, true); 591 if (op == SET_BOUNDS) { 592 setShellPosition(shellRect); 593 } 594 } 595 596 reconfigureContentWindow(newDimensions); 597 } finally { 598 XToolkit.awtUnlock(); 599 } 600 } 601 602 /** 603 * @param x, y, width, heith - dimensions of the window with insets 604 */ 605 private void reshape(int x, int y, int width, int height, int operation, 606 boolean userReshape) 607 { 608 Rectangle newRec; 609 boolean setClient = false; 610 WindowDimensions dims = new WindowDimensions(dimensions); 611 switch (operation & (~NO_EMBEDDED_CHECK)) { 612 case SET_LOCATION: 613 // Set location always sets bounds location. However, until the window is mapped we 614 // should use client coordinates 615 dims.setLocation(x, y); 616 break; 617 case SET_SIZE: 618 // Set size sets bounds size. However, until the window is mapped we 619 // should use client coordinates 620 dims.setSize(width, height); 621 break; 622 case SET_CLIENT_SIZE: { 623 // Sets client rect size. Width and height contain insets. 624 Insets in = currentInsets; 625 width -= in.left+in.right; 626 height -= in.top+in.bottom; 627 dims.setClientSize(width, height); 628 break; 629 } 630 case SET_BOUNDS: 631 default: 632 dims.setLocation(x, y); 633 dims.setSize(width, height); 634 break; 635 } 636 if (insLog.isLoggable(PlatformLogger.Level.FINE)) { 637 insLog.fine("For the operation {0} new dimensions are {1}", 638 operationToString(operation), dims); 639 } 640 641 reshape(dims, operation, userReshape); 642 } 643 644 // This method gets overriden in XFramePeer & XDialogPeer. 645 abstract boolean isTargetUndecorated(); 646 647 /** 648 * @see java.awt.peer.ComponentPeer#setBounds 649 */ 650 public void setBounds(int x, int y, int width, int height, int op) { 651 // TODO: Rewrite with WindowDimensions 652 reshape(x, y, width, height, op, true); 653 validateSurface(); 654 } 655 656 // Coordinates are that of the shell 657 void reconfigureContentWindow(WindowDimensions dims) { 658 if (content == null) { 659 insLog.fine("WARNING: Content window is null"); 660 return; 661 } 662 content.setContentBounds(dims); 663 } 664 665 boolean no_reparent_artifacts = false; 666 public void handleConfigureNotifyEvent(XEvent xev) { 667 assert (SunToolkit.isAWTLockHeldByCurrentThread()); 668 XConfigureEvent xe = xev.get_xconfigure(); 669 if (insLog.isLoggable(PlatformLogger.Level.FINE)) { 670 insLog.fine("Configure notify {0}", xe); 671 } 672 673 // XXX: should really only consider synthetic events, but 674 if (isReparented()) { 675 configure_seen = true; 676 } 677 678 if (!isMaximized() 679 && (xe.get_serial() == reparent_serial || xe.get_window() != getShell()) 680 && !no_reparent_artifacts) 681 { 682 insLog.fine("- reparent artifact, skipping"); 683 return; 684 } 685 no_reparent_artifacts = false; 686 687 /** 688 * When there is a WM we receive some CN before being visible and after. 689 * We should skip all CN which are before being visible, because we assume 690 * the gravity is in action while it is not yet. 691 * 692 * When there is no WM we receive CN only _before_ being visible. 693 * We should process these CNs. 694 */ 695 if (!isVisible() && XWM.getWMID() != XWM.NO_WM) { 696 insLog.fine(" - not visible, skipping"); 697 return; 698 } 699 700 /* 701 * Some window managers configure before we are reparented and 702 * the send event flag is set! ugh... (Enlighetenment for one, 703 * possibly MWM as well). If we haven't been reparented yet 704 * this is just the WM shuffling us into position. Ignore 705 * it!!!! or we wind up in a bogus location. 706 */ 707 int runningWM = XWM.getWMID(); 708 if (insLog.isLoggable(PlatformLogger.Level.FINE)) { 709 insLog.fine("reparented={0}, visible={1}, WM={2}, decorations={3}", 710 isReparented(), isVisible(), runningWM, getDecorations()); 711 } 712 if (!isReparented() && isVisible() && runningWM != XWM.NO_WM 713 && !XWM.isNonReparentingWM() 714 && getDecorations() != XWindowAttributesData.AWT_DECOR_NONE) { 715 insLog.fine("- visible but not reparented, skipping"); 716 return; 717 } 718 //Last chance to correct insets 719 if (!insets_corrected && getDecorations() != XWindowAttributesData.AWT_DECOR_NONE) { 720 long parent = XlibUtil.getParentWindow(window); 721 Insets correctWM = (parent != -1) ? XWM.getWM().getInsets(this, window, parent) : null; 722 if (insLog.isLoggable(PlatformLogger.Level.FINER)) { 723 if (correctWM != null) { 724 insLog.finer("Configure notify - insets : " + correctWM); 725 } else { 726 insLog.finer("Configure notify - insets are still not available"); 727 } 728 } 729 if (correctWM != null) { 730 handleCorrectInsets(correctWM); 731 } else { 732 //Only one attempt to correct insets is made (to lower risk) 733 //if insets are still not available we simply set the flag 734 insets_corrected = true; 735 } 736 } 737 738 updateChildrenSizes(); 739 740 Point newLocation = getNewLocation(xe, currentInsets.left, currentInsets.top); 741 WindowDimensions newDimensions = 742 new WindowDimensions(newLocation, 743 new Dimension(scaleDown(xe.get_width()), 744 scaleDown(xe.get_height())), 745 copy(currentInsets), true); 746 747 if (insLog.isLoggable(PlatformLogger.Level.FINER)) { 748 insLog.finer("Insets are {0}, new dimensions {1}", 749 currentInsets, newDimensions); 750 } 751 752 checkIfOnNewScreen(newDimensions.getBounds()); 753 754 Point oldLocation = getLocation(); 755 dimensions = newDimensions; 756 if (!newLocation.equals(oldLocation)) { 757 handleMoved(newDimensions); 758 } 759 reconfigureContentWindow(newDimensions); 760 updateChildrenSizes(); 761 762 repositionSecurityWarning(); 763 } 764 765 private void checkShellRectSize(Rectangle shellRect) { 766 shellRect.width = Math.max(MIN_SIZE, shellRect.width); 767 shellRect.height = Math.max(MIN_SIZE, shellRect.height); 768 } 769 770 private void checkShellRectPos(Rectangle shellRect) { 771 int wm = XWM.getWMID(); 772 if (wm == XWM.MOTIF_WM || wm == XWM.CDE_WM) { 773 if (shellRect.x == 0 && shellRect.y == 0) { 774 shellRect.x = shellRect.y = 1; 775 } 776 } 777 } 778 779 private void checkShellRect(Rectangle shellRect) { 780 checkShellRectSize(shellRect); 781 checkShellRectPos(shellRect); 782 } 783 784 public void setShellBounds(Rectangle rec) { 785 if (insLog.isLoggable(PlatformLogger.Level.FINE)) { 786 insLog.fine("Setting shell bounds on " + this + " to " + rec); 787 } 788 XToolkit.awtLock(); 789 try { 790 updateSizeHints(rec.x, rec.y, rec.width, rec.height); 791 XlibWrapper.XMoveResizeWindow(XToolkit.getDisplay(), getShell(), 792 scaleUp(rec.x), scaleUp(rec.y), 793 scaleUp(rec.width), scaleUp(rec.height)); 794 } 795 finally { 796 XToolkit.awtUnlock(); 797 } 798 } 799 public void setShellSize(Rectangle rec) { 800 if (insLog.isLoggable(PlatformLogger.Level.FINE)) { 801 insLog.fine("Setting shell size on " + this + " to " + rec); 802 } 803 XToolkit.awtLock(); 804 try { 805 updateSizeHints(rec.x, rec.y, rec.width, rec.height); 806 XlibWrapper.XResizeWindow(XToolkit.getDisplay(), getShell(), 807 scaleUp(rec.width), scaleUp(rec.height)); 808 } 809 finally { 810 XToolkit.awtUnlock(); 811 } 812 } 813 public void setShellPosition(Rectangle rec) { 814 if (insLog.isLoggable(PlatformLogger.Level.FINE)) { 815 insLog.fine("Setting shell position on " + this + " to " + rec); 816 } 817 XToolkit.awtLock(); 818 try { 819 updateSizeHints(rec.x, rec.y, rec.width, rec.height); 820 XlibWrapper.XMoveWindow(XToolkit.getDisplay(), getShell(), 821 scaleUp(rec.x), scaleUp(rec.y)); 822 } 823 finally { 824 XToolkit.awtUnlock(); 825 } 826 } 827 828 void initResizability() { 829 setResizable(winAttr.initialResizability); 830 } 831 public void setResizable(boolean resizable) { 832 int fs = winAttr.functions; 833 if (!isResizable() && resizable) { 834 currentInsets = new Insets(0, 0, 0, 0); 835 resetWMSetInsets(); 836 if (!isEmbedded()) { 837 setReparented(false); 838 } 839 winAttr.isResizable = resizable; 840 if ((fs & MWMConstants.MWM_FUNC_ALL) != 0) { 841 fs &= ~(MWMConstants.MWM_FUNC_RESIZE | MWMConstants.MWM_FUNC_MAXIMIZE); 842 } else { 843 fs |= (MWMConstants.MWM_FUNC_RESIZE | MWMConstants.MWM_FUNC_MAXIMIZE); 844 } 845 winAttr.functions = fs; 846 XWM.setShellResizable(this); 847 } else if (isResizable() && !resizable) { 848 currentInsets = new Insets(0, 0, 0, 0); 849 resetWMSetInsets(); 850 if (!isEmbedded()) { 851 setReparented(false); 852 } 853 winAttr.isResizable = resizable; 854 if ((fs & MWMConstants.MWM_FUNC_ALL) != 0) { 855 fs |= (MWMConstants.MWM_FUNC_RESIZE | MWMConstants.MWM_FUNC_MAXIMIZE); 856 } else { 857 fs &= ~(MWMConstants.MWM_FUNC_RESIZE | MWMConstants.MWM_FUNC_MAXIMIZE); 858 } 859 winAttr.functions = fs; 860 XWM.setShellNotResizable(this, dimensions, dimensions.getBounds(), false); 861 } 862 } 863 864 Rectangle getShellBounds() { 865 return dimensions.getClientRect(); 866 } 867 868 public Rectangle getBounds() { 869 return dimensions.getBounds(); 870 } 871 872 public Dimension getSize() { 873 return dimensions.getSize(); 874 } 875 876 public int getX() { 877 return dimensions.getLocation().x; 878 } 879 880 public int getY() { 881 return dimensions.getLocation().y; 882 } 883 884 public Point getLocation() { 885 return dimensions.getLocation(); 886 } 887 888 public int getAbsoluteX() { 889 // NOTE: returning this peer's location which is shell location 890 return dimensions.getScreenBounds().x; 891 } 892 893 public int getAbsoluteY() { 894 // NOTE: returning this peer's location which is shell location 895 return dimensions.getScreenBounds().y; 896 } 897 898 public int getWidth() { 899 return getSize().width; 900 } 901 902 public int getHeight() { 903 return getSize().height; 904 } 905 906 public final WindowDimensions getDimensions() { 907 return dimensions; 908 } 909 910 public Point getLocationOnScreen() { 911 XToolkit.awtLock(); 912 try { 913 if (configure_seen) { 914 return toGlobal(0,0); 915 } else { 916 Point location = target.getLocation(); 917 if (insLog.isLoggable(PlatformLogger.Level.FINE)) { 918 insLog.fine("getLocationOnScreen {0} not reparented: {1} ", 919 this, location); 920 } 921 return location; 922 } 923 } finally { 924 XToolkit.awtUnlock(); 925 } 926 } 927 928 929 /*************************************************************************************** 930 * END OF I N S E T S C O D E 931 **************************************************************************************/ 932 933 protected boolean isEventDisabled(XEvent e) { 934 switch (e.get_type()) { 935 // Do not generate MOVED/RESIZED events since we generate them by ourselves 936 case XConstants.ConfigureNotify: 937 return true; 938 case XConstants.EnterNotify: 939 case XConstants.LeaveNotify: 940 // Disable crossing event on outer borders of Frame so 941 // we receive only one set of cross notifications(first set is from content window) 942 return true; 943 default: 944 return super.isEventDisabled(e); 945 } 946 } 947 948 int getDecorations() { 949 return winAttr.decorations; 950 } 951 952 int getFunctions() { 953 return winAttr.functions; 954 } 955 956 public void setVisible(boolean vis) { 957 if (log.isLoggable(PlatformLogger.Level.FINER)) { 958 log.finer("Setting {0} to visible {1}", this, Boolean.valueOf(vis)); 959 } 960 if (vis && !isVisible()) { 961 XWM.setShellDecor(this); 962 super.setVisible(vis); 963 if (winAttr.isResizable) { 964 //Fix for 4320050: Minimum size for java.awt.Frame is not being enforced. 965 //We need to update frame's minimum size, not to reset it 966 XWM.removeSizeHints(this, XUtilConstants.PMaxSize); 967 updateMinimumSize(); 968 } 969 } else { 970 super.setVisible(vis); 971 } 972 } 973 974 protected void suppressWmTakeFocus(boolean doSuppress) { 975 XAtomList protocols = getWMProtocols(); 976 if (doSuppress) { 977 protocols.remove(wm_take_focus); 978 } else { 979 protocols.add(wm_take_focus); 980 } 981 wm_protocols.setAtomListProperty(this, protocols); 982 } 983 984 public void dispose() { 985 if (content != null) { 986 content.destroy(); 987 } 988 focusProxy.destroy(); 989 990 if (iconWindow != null) { 991 iconWindow.destroy(); 992 } 993 994 super.dispose(); 995 } 996 997 public void handleClientMessage(XEvent xev) { 998 super.handleClientMessage(xev); 999 XClientMessageEvent cl = xev.get_xclient(); 1000 if ((wm_protocols != null) && (cl.get_message_type() == wm_protocols.getAtom())) { 1001 if (cl.get_data(0) == wm_delete_window.getAtom()) { 1002 handleQuit(); 1003 } else if (cl.get_data(0) == wm_take_focus.getAtom()) { 1004 handleWmTakeFocus(cl); 1005 } 1006 } 1007 } 1008 1009 private void handleWmTakeFocus(XClientMessageEvent cl) { 1010 if (focusLog.isLoggable(PlatformLogger.Level.FINE)) { 1011 focusLog.fine("WM_TAKE_FOCUS on {0}", this); 1012 } 1013 1014 if (XWM.getWMID() == XWM.UNITY_COMPIZ_WM) { 1015 // JDK-8159460 1016 Window focusedWindow = XKeyboardFocusManagerPeer.getInstance() 1017 .getCurrentFocusedWindow(); 1018 Window activeWindow = XWindowPeer.getDecoratedOwner(focusedWindow); 1019 if (activeWindow != target) { 1020 requestWindowFocus(cl.get_data(1), true); 1021 } else { 1022 WindowEvent we = new WindowEvent(focusedWindow, 1023 WindowEvent.WINDOW_GAINED_FOCUS); 1024 sendEvent(we); 1025 } 1026 } else { 1027 requestWindowFocus(cl.get_data(1), true); 1028 } 1029 } 1030 1031 /** 1032 * Requests focus to this decorated top-level by requesting X input focus 1033 * to the shell window. 1034 */ 1035 protected void requestXFocus(long time, boolean timeProvided) { 1036 // We have proxied focus mechanism - instead of shell the focus is held 1037 // by "proxy" - invisible mapped window. When we want to set X input focus to 1038 // toplevel set it on proxy instead. 1039 if (focusProxy == null) { 1040 if (focusLog.isLoggable(PlatformLogger.Level.WARNING)) { 1041 focusLog.warning("Focus proxy is null for " + this); 1042 } 1043 } else { 1044 if (focusLog.isLoggable(PlatformLogger.Level.FINE)) { 1045 focusLog.fine("Requesting focus to proxy: " + focusProxy); 1046 } 1047 if (timeProvided) { 1048 focusProxy.xRequestFocus(time); 1049 } else { 1050 focusProxy.xRequestFocus(); 1051 } 1052 } 1053 } 1054 1055 XFocusProxyWindow getFocusProxy() { 1056 return focusProxy; 1057 } 1058 1059 public void handleQuit() { 1060 postEvent(new WindowEvent((Window)target, WindowEvent.WINDOW_CLOSING)); 1061 } 1062 1063 final void dumpMe() { 1064 System.err.println(">>> Peer: " + x + ", " + y + ", " + width + ", " + height); 1065 } 1066 1067 final void dumpTarget() { 1068 AWTAccessor.ComponentAccessor compAccessor = AWTAccessor.getComponentAccessor(); 1069 int getWidth = compAccessor.getWidth(target); 1070 int getHeight = compAccessor.getHeight(target); 1071 int getTargetX = compAccessor.getX(target); 1072 int getTargetY = compAccessor.getY(target); 1073 System.err.println(">>> Target: " + getTargetX + ", " + getTargetY + ", " + getWidth + ", " + getHeight); 1074 } 1075 1076 final void dumpShell() { 1077 dumpWindow("Shell", getShell()); 1078 } 1079 final void dumpContent() { 1080 dumpWindow("Content", getContentWindow()); 1081 } 1082 final void dumpParent() { 1083 long parent = XlibUtil.getParentWindow(getShell()); 1084 if (parent != 0) 1085 { 1086 dumpWindow("Parent", parent); 1087 } 1088 else 1089 { 1090 System.err.println(">>> NO PARENT"); 1091 } 1092 } 1093 1094 final void dumpWindow(String id, long window) { 1095 XWindowAttributes pattr = new XWindowAttributes(); 1096 try { 1097 XToolkit.awtLock(); 1098 try { 1099 int status = 1100 XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(), 1101 window, pattr.pData); 1102 } 1103 finally { 1104 XToolkit.awtUnlock(); 1105 } 1106 System.err.println(">>>> " + id + ": " + pattr.get_x() 1107 + ", " + pattr.get_y() + ", " + pattr.get_width() 1108 + ", " + pattr.get_height()); 1109 } finally { 1110 pattr.dispose(); 1111 } 1112 } 1113 1114 final void dumpAll() { 1115 dumpTarget(); 1116 dumpMe(); 1117 dumpParent(); 1118 dumpShell(); 1119 dumpContent(); 1120 } 1121 1122 boolean isMaximized() { 1123 return false; 1124 } 1125 1126 @Override 1127 boolean isOverrideRedirect() { 1128 return Window.Type.POPUP.equals(getWindowType()); 1129 } 1130 1131 public boolean requestWindowFocus(long time, boolean timeProvided) { 1132 focusLog.fine("Request for decorated window focus"); 1133 // If this is Frame or Dialog we can't assure focus request success - but we still can try 1134 // If this is Window and its owner Frame is active we can be sure request succedded. 1135 Window focusedWindow = XKeyboardFocusManagerPeer.getInstance().getCurrentFocusedWindow(); 1136 Window activeWindow = XWindowPeer.getDecoratedOwner(focusedWindow); 1137 1138 if (focusLog.isLoggable(PlatformLogger.Level.FINER)) { 1139 focusLog.finer("Current window is: active={0}, focused={1}", 1140 Boolean.valueOf(target == activeWindow), 1141 Boolean.valueOf(target == focusedWindow)); 1142 } 1143 1144 XWindowPeer toFocus = this; 1145 while (toFocus.nextTransientFor != null) { 1146 toFocus = toFocus.nextTransientFor; 1147 } 1148 if (toFocus == null || !toFocus.focusAllowedFor()) { 1149 // This might change when WM will have property to determine focus policy. 1150 // Right now, because policy is unknown we can't be sure we succedded 1151 return false; 1152 } 1153 if (this == toFocus) { 1154 if (isWMStateNetHidden()) { 1155 focusLog.fine("The window is unmapped, so rejecting the request"); 1156 return false; 1157 } 1158 if (target == activeWindow && target != focusedWindow) { 1159 // Happens when an owned window is currently focused 1160 focusLog.fine("Focus is on child window - transferring it back to the owner"); 1161 handleWindowFocusInSync(-1); 1162 return true; 1163 } 1164 Window realNativeFocusedWindow = XWindowPeer.getNativeFocusedWindow(); 1165 if (focusLog.isLoggable(PlatformLogger.Level.FINEST)) { 1166 focusLog.finest("Real native focused window: " + realNativeFocusedWindow + 1167 "\nKFM's focused window: " + focusedWindow); 1168 } 1169 1170 // A workaround for Metacity. See 6522725, 6613426, 7147075. 1171 if (target == realNativeFocusedWindow && XWM.getWMID() == XWM.METACITY_WM) { 1172 if (focusLog.isLoggable(PlatformLogger.Level.FINE)) { 1173 focusLog.fine("The window is already natively focused."); 1174 } 1175 return true; 1176 } 1177 } 1178 if (focusLog.isLoggable(PlatformLogger.Level.FINE)) { 1179 focusLog.fine("Requesting focus to " + (this == toFocus ? "this window" : toFocus)); 1180 } 1181 1182 if (timeProvided) { 1183 toFocus.requestXFocus(time); 1184 } else { 1185 toFocus.requestXFocus(); 1186 } 1187 return (this == toFocus); 1188 } 1189 1190 XWindowPeer actualFocusedWindow = null; 1191 void setActualFocusedWindow(XWindowPeer actualFocusedWindow) { 1192 synchronized(getStateLock()) { 1193 this.actualFocusedWindow = actualFocusedWindow; 1194 } 1195 } 1196 1197 boolean requestWindowFocus(XWindowPeer actualFocusedWindow, 1198 long time, boolean timeProvided) 1199 { 1200 setActualFocusedWindow(actualFocusedWindow); 1201 return requestWindowFocus(time, timeProvided); 1202 } 1203 public void handleWindowFocusIn(long serial) { 1204 if (null == actualFocusedWindow) { 1205 super.handleWindowFocusIn(serial); 1206 } else { 1207 /* 1208 * Fix for 6314575. 1209 * If this is a result of clicking on one of the Frame's component 1210 * then 'actualFocusedWindow' shouldn't be focused. A decision of focusing 1211 * it or not should be made after the appropriate Java mouse event (if any) 1212 * is handled by the component where 'actualFocusedWindow' value may be reset. 1213 * 1214 * The fix is based on the empiric fact consisting in that the component 1215 * receives native mouse event nearly at the same time the Frame receives 1216 * WM_TAKE_FOCUS (when FocusIn is generated via XSetInputFocus call) but 1217 * definetely before the Frame gets FocusIn event (when this method is called). 1218 */ 1219 postEvent(new InvocationEvent(target, new Runnable() { 1220 public void run() { 1221 XWindowPeer fw = null; 1222 synchronized (getStateLock()) { 1223 fw = actualFocusedWindow; 1224 actualFocusedWindow = null; 1225 if (null == fw || !fw.isVisible() || !fw.isFocusableWindow()) { 1226 fw = XDecoratedPeer.this; 1227 } 1228 } 1229 fw.handleWindowFocusIn_Dispatch(); 1230 } 1231 })); 1232 } 1233 } 1234 1235 public void handleWindowFocusOut(Window oppositeWindow, long serial) { 1236 Window actualFocusedWindow = XKeyboardFocusManagerPeer.getInstance().getCurrentFocusedWindow(); 1237 1238 // If the actual focused window is not this decorated window then retain it. 1239 if (actualFocusedWindow != null && actualFocusedWindow != target) { 1240 Window owner = XWindowPeer.getDecoratedOwner(actualFocusedWindow); 1241 1242 if (owner != null && owner == target) { 1243 setActualFocusedWindow(AWTAccessor.getComponentAccessor().getPeer(actualFocusedWindow)); 1244 } 1245 } 1246 super.handleWindowFocusOut(oppositeWindow, serial); 1247 } 1248 }