1 /* 2 * Copyright (c) 2003, 2007, 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.awt.X11; 27 28 import java.awt.*; 29 import sun.awt.*; 30 import java.util.logging.*; 31 import java.util.*; 32 33 public class XBaseWindow implements XConstants, XUtilConstants { 34 private static final Logger log = Logger.getLogger("sun.awt.X11.XBaseWindow"); 35 private static final Logger insLog = Logger.getLogger("sun.awt.X11.insets.XBaseWindow"); 36 private static final Logger eventLog = Logger.getLogger("sun.awt.X11.event.XBaseWindow"); 37 private static final Logger focusLog = Logger.getLogger("sun.awt.X11.focus.XBaseWindow"); 38 private static final Logger grabLog = Logger.getLogger("sun.awt.X11.grab.XBaseWindow"); 39 40 public static final String 41 PARENT_WINDOW = "parent window", // parent window, Long 42 BOUNDS = "bounds", // bounds of the window, Rectangle 43 OVERRIDE_REDIRECT = "overrideRedirect", // override_redirect setting, Boolean 44 EVENT_MASK = "event mask", // event mask, Integer 45 VALUE_MASK = "value mask", // value mask, Long 46 BORDER_PIXEL = "border pixel", // border pixel value, Integer 47 COLORMAP = "color map", // color map, Long 48 DEPTH = "visual depth", // depth, Integer 49 VISUAL_CLASS = "visual class", // visual class, Integer 50 VISUAL = "visual", // visual, Long 51 EMBEDDED = "embedded", // is embedded?, Boolean 52 DELAYED = "delayed", // is creation delayed?, Boolean 53 PARENT = "parent", // parent peer 54 BACKGROUND_PIXMAP = "pixmap", // background pixmap 55 VISIBLE = "visible", // whether it is visible by default 56 SAVE_UNDER = "save under", // save content under this window 57 BACKING_STORE = "backing store", // enables double buffering 58 BIT_GRAVITY = "bit gravity"; // copy old content on geometry change 59 private XCreateWindowParams delayedParams; 60 61 Set<Long> children = new HashSet<Long>(); 62 long window; 63 boolean visible; 64 boolean mapped; 65 boolean embedded; 66 Rectangle maxBounds; 67 volatile XBaseWindow parentWindow; 68 69 private boolean disposed; 70 71 private long screen; 72 private XSizeHints hints; 73 private XWMHints wmHints; 74 75 final static int MIN_SIZE = 1; 76 final static int DEF_LOCATION = 1; 77 78 private static XAtom wm_client_leader; 79 80 static enum InitialiseState { 81 INITIALISING, 82 NOT_INITIALISED, 83 INITIALISED, 84 FAILED_INITIALISATION 85 }; 86 87 private InitialiseState initialising; 88 89 int x; 90 int y; 91 int width; 92 int height; 93 94 void awtLock() { 95 XToolkit.awtLock(); 96 } 97 98 void awtUnlock() { 99 XToolkit.awtUnlock(); 100 } 101 102 void awtLockNotifyAll() { 103 XToolkit.awtLockNotifyAll(); 104 } 105 106 void awtLockWait() throws InterruptedException { 107 XToolkit.awtLockWait(); 108 } 109 110 // To prevent errors from overriding obsolete methods 111 protected final void init(long parentWindow, Rectangle bounds) {} 112 protected final void preInit() {} 113 protected final void postInit() {} 114 115 // internal lock for synchronizing state changes and paint calls, initialized in preInit. 116 // the order with other locks: AWTLock -> stateLock 117 static class StateLock extends Object { } 118 protected StateLock state_lock; 119 120 /** 121 * Called for delayed inits during construction 122 */ 123 void instantPreInit(XCreateWindowParams params) { 124 state_lock = new StateLock(); 125 initialising = InitialiseState.NOT_INITIALISED; 126 } 127 128 /** 129 * Called before window creation, descendants should override to initialize the data, 130 * initialize params. 131 */ 132 void preInit(XCreateWindowParams params) { 133 state_lock = new StateLock(); 134 initialising = InitialiseState.NOT_INITIALISED; 135 embedded = Boolean.TRUE.equals(params.get(EMBEDDED)); 136 visible = Boolean.TRUE.equals(params.get(VISIBLE)); 137 138 Object parent = params.get(PARENT); 139 if (parent instanceof XBaseWindow) { 140 parentWindow = (XBaseWindow)parent; 141 } else { 142 Long parentWindowID = (Long)params.get(PARENT_WINDOW); 143 if (parentWindowID != null) { 144 parentWindow = XToolkit.windowToXWindow(parentWindowID); 145 } 146 } 147 148 Long eventMask = (Long)params.get(EVENT_MASK); 149 if (eventMask != null) { 150 long mask = eventMask.longValue(); 151 mask |= SubstructureNotifyMask; 152 params.put(EVENT_MASK, mask); 153 } 154 155 screen = -1; 156 } 157 158 /** 159 * Called after window creation, descendants should override to initialize Window 160 * with class-specific values and perform post-initialization actions. 161 */ 162 void postInit(XCreateWindowParams params) { 163 if (log.isLoggable(Level.FINE)) log.fine("WM name is " + getWMName()); 164 updateWMName(); 165 166 // Set WM_CLIENT_LEADER property 167 initClientLeader(); 168 } 169 170 /** 171 * Creates window using parameters <code>params</code> 172 * If params contain flag DELAYED doesn't do anything. 173 * Note: Descendants can call this method to create the window 174 * at the time different to instance construction. 175 */ 176 protected final void init(XCreateWindowParams params) { 177 awtLock(); 178 initialising = InitialiseState.INITIALISING; 179 awtUnlock(); 180 181 try { 182 if (!Boolean.TRUE.equals(params.get(DELAYED))) { 183 preInit(params); 184 create(params); 185 postInit(params); 186 } else { 187 instantPreInit(params); 188 delayedParams = params; 189 } 190 awtLock(); 191 initialising = InitialiseState.INITIALISED; 192 awtLockNotifyAll(); 193 awtUnlock(); 194 } catch (RuntimeException re) { 195 awtLock(); 196 initialising = InitialiseState.FAILED_INITIALISATION; 197 awtLockNotifyAll(); 198 awtUnlock(); 199 throw re; 200 } catch (Throwable t) { 201 log.log(Level.WARNING, "Exception during peer initialization", t); 202 awtLock(); 203 initialising = InitialiseState.FAILED_INITIALISATION; 204 awtLockNotifyAll(); 205 awtUnlock(); 206 } 207 } 208 209 public boolean checkInitialised() { 210 awtLock(); 211 try { 212 switch (initialising) { 213 case INITIALISED: 214 return true; 215 case INITIALISING: 216 try { 217 while (initialising != InitialiseState.INITIALISED) { 218 awtLockWait(); 219 } 220 } catch (InterruptedException ie) { 221 return false; 222 } 223 return true; 224 case NOT_INITIALISED: 225 case FAILED_INITIALISATION: 226 return false; 227 default: 228 return false; 229 } 230 } finally { 231 awtUnlock(); 232 } 233 } 234 235 /* 236 * Creates an invisible InputOnly window without an associated Component. 237 */ 238 XBaseWindow() { 239 this(new XCreateWindowParams()); 240 } 241 242 /** 243 * Creates normal child window 244 */ 245 XBaseWindow(long parentWindow, Rectangle bounds) { 246 this(new XCreateWindowParams(new Object[] { 247 BOUNDS, bounds, 248 PARENT_WINDOW, Long.valueOf(parentWindow)})); 249 } 250 251 /** 252 * Creates top-level window 253 */ 254 XBaseWindow(Rectangle bounds) { 255 this(new XCreateWindowParams(new Object[] { 256 BOUNDS, bounds 257 })); 258 } 259 260 public XBaseWindow (XCreateWindowParams params) { 261 init(params); 262 } 263 264 /* This create is used by the XEmbeddedFramePeer since it has to create the window 265 as a child of the netscape window. This netscape window is passed in as wid */ 266 XBaseWindow(long parentWindow) { 267 this(new XCreateWindowParams(new Object[] { 268 PARENT_WINDOW, Long.valueOf(parentWindow), 269 EMBEDDED, Boolean.TRUE 270 })); 271 } 272 273 /** 274 * Verifies that all required parameters are set. If not, sets them to default values. 275 * Verifies values of critical parameters, adjust their values when needed. 276 * @throws IllegalArgumentException if params is null 277 */ 278 protected void checkParams(XCreateWindowParams params) { 279 if (params == null) { 280 throw new IllegalArgumentException("Window creation parameters are null"); 281 } 282 params.putIfNull(PARENT_WINDOW, Long.valueOf(XToolkit.getDefaultRootWindow())); 283 params.putIfNull(BOUNDS, new Rectangle(DEF_LOCATION, DEF_LOCATION, MIN_SIZE, MIN_SIZE)); 284 params.putIfNull(DEPTH, Integer.valueOf((int)XlibWrapper.CopyFromParent)); 285 params.putIfNull(VISUAL, Long.valueOf(XlibWrapper.CopyFromParent)); 286 params.putIfNull(VISUAL_CLASS, Integer.valueOf((int)XlibWrapper.InputOnly)); 287 params.putIfNull(VALUE_MASK, Long.valueOf(XlibWrapper.CWEventMask)); 288 Rectangle bounds = (Rectangle)params.get(BOUNDS); 289 bounds.width = Math.max(MIN_SIZE, bounds.width); 290 bounds.height = Math.max(MIN_SIZE, bounds.height); 291 292 Long eventMaskObj = (Long)params.get(EVENT_MASK); 293 long eventMask = eventMaskObj != null ? eventMaskObj.longValue() : 0; 294 // We use our own synthetic grab see XAwtState.getGrabWindow() 295 // (see X vol. 1, 8.3.3.2) 296 eventMask |= PropertyChangeMask | OwnerGrabButtonMask; 297 params.put(EVENT_MASK, Long.valueOf(eventMask)); 298 } 299 300 /** 301 * Creates window with parameters specified by <code>params</code> 302 * @see #init 303 */ 304 private final void create(XCreateWindowParams params) { 305 XToolkit.awtLock(); 306 try { 307 XSetWindowAttributes xattr = new XSetWindowAttributes(); 308 try { 309 checkParams(params); 310 311 long value_mask = ((Long)params.get(VALUE_MASK)).longValue(); 312 313 Long eventMask = (Long)params.get(EVENT_MASK); 314 xattr.set_event_mask(eventMask.longValue()); 315 value_mask |= XlibWrapper.CWEventMask; 316 317 Long border_pixel = (Long)params.get(BORDER_PIXEL); 318 if (border_pixel != null) { 319 xattr.set_border_pixel(border_pixel.longValue()); 320 value_mask |= XlibWrapper.CWBorderPixel; 321 } 322 323 Long colormap = (Long)params.get(COLORMAP); 324 if (colormap != null) { 325 xattr.set_colormap(colormap.longValue()); 326 value_mask |= XlibWrapper.CWColormap; 327 } 328 Long background_pixmap = (Long)params.get(BACKGROUND_PIXMAP); 329 if (background_pixmap != null) { 330 xattr.set_background_pixmap(background_pixmap.longValue()); 331 value_mask |= XlibWrapper.CWBackPixmap; 332 } 333 334 Long parentWindow = (Long)params.get(PARENT_WINDOW); 335 Rectangle bounds = (Rectangle)params.get(BOUNDS); 336 Integer depth = (Integer)params.get(DEPTH); 337 Integer visual_class = (Integer)params.get(VISUAL_CLASS); 338 Long visual = (Long)params.get(VISUAL); 339 Boolean overrideRedirect = (Boolean)params.get(OVERRIDE_REDIRECT); 340 if (overrideRedirect != null) { 341 xattr.set_override_redirect(overrideRedirect.booleanValue()); 342 value_mask |= XlibWrapper.CWOverrideRedirect; 343 } 344 345 Boolean saveUnder = (Boolean)params.get(SAVE_UNDER); 346 if (saveUnder != null) { 347 xattr.set_save_under(saveUnder.booleanValue()); 348 value_mask |= XlibWrapper.CWSaveUnder; 349 } 350 351 Integer backingStore = (Integer)params.get(BACKING_STORE); 352 if (backingStore != null) { 353 xattr.set_backing_store(backingStore.intValue()); 354 value_mask |= XlibWrapper.CWBackingStore; 355 } 356 357 Integer bitGravity = (Integer)params.get(BIT_GRAVITY); 358 if (bitGravity != null) { 359 xattr.set_bit_gravity(bitGravity.intValue()); 360 value_mask |= XlibWrapper.CWBitGravity; 361 } 362 363 if (log.isLoggable(Level.FINE)) { 364 log.fine("Creating window for " + this + " with the following attributes: \n" + params); 365 } 366 /* X does not allow setting heights or widths to 0: this will cause a BadValue 367 * error. Lets set them to something close enough */ 368 int width = bounds.width; 369 if (width <= 0) 370 width = 1; 371 int height = bounds.height; 372 if (height <= 0) 373 height = 1; 374 window = XlibWrapper.XCreateWindow(XToolkit.getDisplay(), 375 parentWindow.longValue(), 376 bounds.x, bounds.y, // location 377 width, height, // size 378 0, // border 379 depth.intValue(), // depth 380 visual_class.intValue(), // class 381 visual.longValue(), // visual 382 value_mask, // value mask 383 xattr.pData); // attributes 384 385 if (window == 0) { 386 throw new IllegalStateException("Couldn't create window because of wrong parameters. Run with NOISY_AWT to see details"); 387 } 388 XToolkit.addToWinMap(window, this); 389 } finally { 390 xattr.dispose(); 391 } 392 } finally { 393 XToolkit.awtUnlock(); 394 } 395 } 396 397 public XCreateWindowParams getDelayedParams() { 398 return delayedParams; 399 } 400 401 protected String getWMName() { 402 return XToolkit.getCorrectXIDString(getClass().getName()); 403 } 404 405 protected void initClientLeader() { 406 XToolkit.awtLock(); 407 try { 408 if (wm_client_leader == null) { 409 wm_client_leader = XAtom.get("WM_CLIENT_LEADER"); 410 } 411 wm_client_leader.setWindowProperty(this, getXAWTRootWindow()); 412 } finally { 413 XToolkit.awtUnlock(); 414 } 415 } 416 417 static XRootWindow getXAWTRootWindow() { 418 return XRootWindow.getInstance(); 419 } 420 421 void destroy() { 422 XToolkit.awtLock(); 423 try { 424 if (hints != null) { 425 XlibWrapper.XFree(hints.pData); 426 hints = null; 427 } 428 XToolkit.removeFromWinMap(getWindow(), this); 429 XlibWrapper.XDestroyWindow(XToolkit.getDisplay(), getWindow()); 430 if (XPropertyCache.isCachingSupported()) { 431 XPropertyCache.clearCache(window); 432 } 433 window = -1; 434 if( !isDisposed() ) { 435 setDisposed( true ); 436 } 437 438 XAwtState.getGrabWindow(); // Magic - getGrabWindow clear state if grabbing window is disposed of. 439 } finally { 440 XToolkit.awtUnlock(); 441 } 442 } 443 444 void flush() { 445 XToolkit.awtLock(); 446 try { 447 XlibWrapper.XFlush(XToolkit.getDisplay()); 448 } finally { 449 XToolkit.awtUnlock(); 450 } 451 } 452 453 /** 454 * Helper function to set W 455 */ 456 public final void setWMHints(XWMHints hints) { 457 XToolkit.awtLock(); 458 try { 459 XlibWrapper.XSetWMHints(XToolkit.getDisplay(), getWindow(), hints.pData); 460 } finally { 461 XToolkit.awtUnlock(); 462 } 463 } 464 465 public XWMHints getWMHints() { 466 if (wmHints == null) { 467 wmHints = new XWMHints(XlibWrapper.XAllocWMHints()); 468 // XlibWrapper.XGetWMHints(XToolkit.getDisplay(), 469 // getWindow(), 470 // wmHints.pData); 471 } 472 return wmHints; 473 } 474 475 476 /* 477 * Call this method under AWTLock. 478 * The lock should be acquired untill all operations with XSizeHints are completed. 479 */ 480 public XSizeHints getHints() { 481 if (hints == null) { 482 long p_hints = XlibWrapper.XAllocSizeHints(); 483 hints = new XSizeHints(p_hints); 484 // XlibWrapper.XGetWMNormalHints(XToolkit.getDisplay(), getWindow(), p_hints, XlibWrapper.larg1); 485 // TODO: Shouldn't we listen for WM updates on this property? 486 } 487 return hints; 488 } 489 490 public void setSizeHints(long flags, int x, int y, int width, int height) { 491 if (insLog.isLoggable(Level.FINER)) insLog.finer("Setting hints, flags " + XlibWrapper.hintsToString(flags)); 492 XToolkit.awtLock(); 493 try { 494 XSizeHints hints = getHints(); 495 // Note: if PPosition is not set in flags this means that 496 // we want to reset PPosition in hints. This is necessary 497 // for locationByPlatform functionality 498 if ((flags & XlibWrapper.PPosition) != 0) { 499 hints.set_x(x); 500 hints.set_y(y); 501 } 502 if ((flags & XlibWrapper.PSize) != 0) { 503 hints.set_width(width); 504 hints.set_height(height); 505 } else if ((hints.get_flags() & XlibWrapper.PSize) != 0) { 506 flags |= XlibWrapper.PSize; 507 } 508 if ((flags & XlibWrapper.PMinSize) != 0) { 509 hints.set_min_width(width); 510 hints.set_min_height(height); 511 } else if ((hints.get_flags() & XlibWrapper.PMinSize) != 0) { 512 flags |= XlibWrapper.PMinSize; 513 //Fix for 4320050: Minimum size for java.awt.Frame is not being enforced. 514 //We don't need to reset minimum size if it's already set 515 } 516 if ((flags & XlibWrapper.PMaxSize) != 0) { 517 if (maxBounds != null) { 518 if (maxBounds.width != Integer.MAX_VALUE) { 519 hints.set_max_width(maxBounds.width); 520 } else { 521 hints.set_max_width(XToolkit.getDefaultScreenWidth()); 522 } 523 if (maxBounds.height != Integer.MAX_VALUE) { 524 hints.set_max_height(maxBounds.height); 525 } else { 526 hints.set_max_height(XToolkit.getDefaultScreenHeight()); 527 } 528 } else { 529 hints.set_max_width(width); 530 hints.set_max_height(height); 531 } 532 } else if ((hints.get_flags() & XlibWrapper.PMaxSize) != 0) { 533 flags |= XlibWrapper.PMaxSize; 534 if (maxBounds != null) { 535 if (maxBounds.width != Integer.MAX_VALUE) { 536 hints.set_max_width(maxBounds.width); 537 } else { 538 hints.set_max_width(XToolkit.getDefaultScreenWidth()); 539 } 540 if (maxBounds.height != Integer.MAX_VALUE) { 541 hints.set_max_height(maxBounds.height); 542 } else { 543 hints.set_max_height(XToolkit.getDefaultScreenHeight()); 544 } 545 } else { 546 // Leave intact 547 } 548 } 549 flags |= XlibWrapper.PWinGravity; 550 hints.set_flags(flags); 551 hints.set_win_gravity((int)XlibWrapper.NorthWestGravity); 552 if (insLog.isLoggable(Level.FINER)) insLog.finer("Setting hints, resulted flags " + XlibWrapper.hintsToString(flags) + 553 ", values " + hints); 554 XlibWrapper.XSetWMNormalHints(XToolkit.getDisplay(), getWindow(), hints.pData); 555 } finally { 556 XToolkit.awtUnlock(); 557 } 558 } 559 560 public boolean isMinSizeSet() { 561 XSizeHints hints = getHints(); 562 long flags = hints.get_flags(); 563 return ((flags & XlibWrapper.PMinSize) == XlibWrapper.PMinSize); 564 } 565 566 /** 567 * This lock object can be used to protect instance data from concurrent access 568 * by two threads. If both state lock and AWT lock are taken, AWT Lock should be taken first. 569 */ 570 Object getStateLock() { 571 return state_lock; 572 } 573 574 public long getWindow() { 575 return window; 576 } 577 public long getContentWindow() { 578 return window; 579 } 580 581 public XBaseWindow getContentXWindow() { 582 return XToolkit.windowToXWindow(getContentWindow()); 583 } 584 585 public Rectangle getBounds() { 586 return new Rectangle(x, y, width, height); 587 } 588 public Dimension getSize() { 589 return new Dimension(width, height); 590 } 591 592 593 public void toFront() { 594 XToolkit.awtLock(); 595 try { 596 XlibWrapper.XRaiseWindow(XToolkit.getDisplay(), getWindow()); 597 } finally { 598 XToolkit.awtUnlock(); 599 } 600 } 601 public void xRequestFocus(long time) { 602 XToolkit.awtLock(); 603 try { 604 if (focusLog.isLoggable(Level.FINER)) focusLog.finer("XSetInputFocus on " + Long.toHexString(getWindow()) + " with time " + time); 605 XlibWrapper.XSetInputFocus2(XToolkit.getDisplay(), getWindow(), time); 606 } finally { 607 XToolkit.awtUnlock(); 608 } 609 } 610 public void xRequestFocus() { 611 XToolkit.awtLock(); 612 try { 613 if (focusLog.isLoggable(Level.FINER)) focusLog.finer("XSetInputFocus on " + Long.toHexString(getWindow())); 614 XlibWrapper.XSetInputFocus(XToolkit.getDisplay(), getWindow()); 615 } finally { 616 XToolkit.awtUnlock(); 617 } 618 } 619 620 public static long xGetInputFocus() { 621 XToolkit.awtLock(); 622 try { 623 return XlibWrapper.XGetInputFocus(XToolkit.getDisplay()); 624 } finally { 625 XToolkit.awtUnlock(); 626 } 627 } 628 629 public void xSetVisible(boolean visible) { 630 if (log.isLoggable(Level.FINE)) log.fine("Setting visible on " + this + " to " + visible); 631 XToolkit.awtLock(); 632 try { 633 this.visible = visible; 634 if (visible) { 635 XlibWrapper.XMapWindow(XToolkit.getDisplay(), getWindow()); 636 } 637 else { 638 XlibWrapper.XUnmapWindow(XToolkit.getDisplay(), getWindow()); 639 } 640 XlibWrapper.XFlush(XToolkit.getDisplay()); 641 } finally { 642 XToolkit.awtUnlock(); 643 } 644 } 645 646 boolean isMapped() { 647 return mapped; 648 } 649 650 void updateWMName() { 651 String name = getWMName(); 652 XToolkit.awtLock(); 653 try { 654 if (name == null) { 655 name = " "; 656 } 657 XAtom nameAtom = XAtom.get(XAtom.XA_WM_NAME); 658 nameAtom.setProperty(getWindow(), name); 659 XAtom netNameAtom = XAtom.get("_NET_WM_NAME"); 660 netNameAtom.setPropertyUTF8(getWindow(), name); 661 } finally { 662 XToolkit.awtUnlock(); 663 } 664 } 665 void setWMClass(String[] cl) { 666 if (cl.length != 2) { 667 throw new IllegalArgumentException("WM_CLASS_NAME consists of exactly two strings"); 668 } 669 XToolkit.awtLock(); 670 try { 671 XAtom xa = XAtom.get(XAtom.XA_WM_CLASS); 672 xa.setProperty8(getWindow(), cl[0] + '\0' + cl[1]); 673 } finally { 674 XToolkit.awtUnlock(); 675 } 676 } 677 678 boolean isVisible() { 679 return visible; 680 } 681 682 static long getScreenOfWindow(long window) { 683 XToolkit.awtLock(); 684 try { 685 return XlibWrapper.getScreenOfWindow(XToolkit.getDisplay(), window); 686 } finally { 687 XToolkit.awtUnlock(); 688 } 689 } 690 long getScreenNumber() { 691 XToolkit.awtLock(); 692 try { 693 return XlibWrapper.XScreenNumberOfScreen(getScreen()); 694 } finally { 695 XToolkit.awtUnlock(); 696 } 697 } 698 699 long getScreen() { 700 if (screen == -1) { // Not initialized 701 screen = getScreenOfWindow(window); 702 } 703 return screen; 704 } 705 706 public void xSetBounds(Rectangle bounds) { 707 xSetBounds(bounds.x, bounds.y, bounds.width, bounds.height); 708 } 709 710 public void xSetBounds(int x, int y, int width, int height) { 711 if (getWindow() == 0) { 712 insLog.warning("Attempt to resize uncreated window"); 713 throw new IllegalStateException("Attempt to resize uncreated window"); 714 } 715 insLog.fine("Setting bounds on " + this + " to (" + x + ", " + y + "), " + width + "x" + height); 716 if (width <= 0) { 717 width = 1; 718 } 719 if (height <= 0) { 720 height = 1; 721 } 722 XToolkit.awtLock(); 723 try { 724 XlibWrapper.XMoveResizeWindow(XToolkit.getDisplay(), getWindow(), x,y,width,height); 725 } finally { 726 XToolkit.awtUnlock(); 727 } 728 } 729 730 /** 731 * Translate coordinates from one window into another. Optimized 732 * for XAWT - uses cached data when possible. Preferable over 733 * pure XTranslateCoordinates. 734 * @return coordinates relative to dst, or null if error happened 735 */ 736 static Point toOtherWindow(long src, long dst, int x, int y) { 737 Point rpt = new Point(0, 0); 738 739 // Check if both windows belong to XAWT - then no X calls are necessary 740 741 XBaseWindow srcPeer = XToolkit.windowToXWindow(src); 742 XBaseWindow dstPeer = XToolkit.windowToXWindow(dst); 743 744 if (srcPeer != null && dstPeer != null) { 745 // (x, y) is relative to src 746 rpt.x = x + srcPeer.getAbsoluteX() - dstPeer.getAbsoluteX(); 747 rpt.y = y + srcPeer.getAbsoluteY() - dstPeer.getAbsoluteY(); 748 } else if (dstPeer != null && XlibUtil.isRoot(src, dstPeer.getScreenNumber())) { 749 // from root into peer 750 rpt.x = x - dstPeer.getAbsoluteX(); 751 rpt.y = y - dstPeer.getAbsoluteY(); 752 } else if (srcPeer != null && XlibUtil.isRoot(dst, srcPeer.getScreenNumber())) { 753 // from peer into root 754 rpt.x = x + srcPeer.getAbsoluteX(); 755 rpt.y = y + srcPeer.getAbsoluteY(); 756 } else { 757 rpt = XlibUtil.translateCoordinates(src, dst, new Point(x, y)); 758 } 759 return rpt; 760 } 761 762 /* 763 * Convert to global coordinates. 764 */ 765 Rectangle toGlobal(Rectangle rec) { 766 Point p = toGlobal(rec.getLocation()); 767 Rectangle newRec = new Rectangle(rec); 768 if (p != null) { 769 newRec.setLocation(p); 770 } 771 return newRec; 772 } 773 774 Point toGlobal(Point pt) { 775 Point p = toGlobal(pt.x, pt.y); 776 if (p != null) { 777 return p; 778 } else { 779 return new Point(pt); 780 } 781 } 782 783 Point toGlobal(int x, int y) { 784 long root; 785 XToolkit.awtLock(); 786 try { 787 root = XlibWrapper.RootWindow(XToolkit.getDisplay(), 788 getScreenNumber()); 789 } finally { 790 XToolkit.awtUnlock(); 791 } 792 Point p = toOtherWindow(getContentWindow(), root, x, y); 793 if (p != null) { 794 return p; 795 } else { 796 return new Point(x, y); 797 } 798 } 799 800 /* 801 * Convert to local coordinates. 802 */ 803 Point toLocal(Point pt) { 804 Point p = toLocal(pt.x, pt.y); 805 if (p != null) { 806 return p; 807 } else { 808 return new Point(pt); 809 } 810 } 811 812 Point toLocal(int x, int y) { 813 long root; 814 XToolkit.awtLock(); 815 try { 816 root = XlibWrapper.RootWindow(XToolkit.getDisplay(), 817 getScreenNumber()); 818 } finally { 819 XToolkit.awtUnlock(); 820 } 821 Point p = toOtherWindow(root, getContentWindow(), x, y); 822 if (p != null) { 823 return p; 824 } else { 825 return new Point(x, y); 826 } 827 } 828 829 /** 830 * We should always grab both keyboard and pointer to control event flow 831 * on popups. This also simplifies synthetic grab implementation. 832 * The active grab overrides activated automatic grab. 833 */ 834 public boolean grabInput() { 835 if (grabLog.isLoggable(Level.FINE)) { 836 grabLog.log(Level.FINE, "Grab input on {0}", new Object[] {String.valueOf(this)}); 837 } 838 839 XToolkit.awtLock(); 840 try { 841 if (XAwtState.getGrabWindow() == this && 842 XAwtState.isManualGrab()) 843 { 844 grabLog.fine(" Already Grabbed"); 845 return true; 846 } 847 //6273031: PIT. Choice drop down does not close once it is right clicked to show a popup menu 848 //remember previous window having grab and if it's not null ungrab it. 849 XBaseWindow prevGrabWindow = XAwtState.getGrabWindow(); 850 final int eventMask = (int) (ButtonPressMask | ButtonReleaseMask 851 | EnterWindowMask | LeaveWindowMask | PointerMotionMask 852 | ButtonMotionMask); 853 final int ownerEvents = 1; 854 855 int ptrGrab = XlibWrapper.XGrabPointer(XToolkit.getDisplay(), 856 getContentWindow(), ownerEvents, eventMask, GrabModeAsync, 857 GrabModeAsync, None, (XWM.isMotif() ? XToolkit.arrowCursor : None), 858 CurrentTime); 859 // Check grab results to be consistent with X server grab 860 if (ptrGrab != GrabSuccess) { 861 XlibWrapper.XUngrabPointer(XToolkit.getDisplay(), CurrentTime); 862 XAwtState.setGrabWindow(null); 863 grabLog.fine(" Grab Failure - mouse"); 864 return false; 865 } 866 867 int keyGrab = XlibWrapper.XGrabKeyboard(XToolkit.getDisplay(), 868 getContentWindow(), ownerEvents, GrabModeAsync, GrabModeAsync, 869 CurrentTime); 870 if (keyGrab != GrabSuccess) { 871 XlibWrapper.XUngrabPointer(XToolkit.getDisplay(), CurrentTime); 872 XlibWrapper.XUngrabKeyboard(XToolkit.getDisplay(), CurrentTime); 873 XAwtState.setGrabWindow(null); 874 grabLog.fine(" Grab Failure - keyboard"); 875 return false; 876 } 877 if (prevGrabWindow != null) { 878 prevGrabWindow.ungrabInputImpl(); 879 } 880 XAwtState.setGrabWindow(this); 881 grabLog.fine(" Grab - success"); 882 return true; 883 } finally { 884 XToolkit.awtUnlock(); 885 } 886 } 887 888 static void ungrabInput() { 889 XToolkit.awtLock(); 890 try { 891 XBaseWindow grabWindow = XAwtState.getGrabWindow(); 892 if (grabLog.isLoggable(Level.FINE)) { 893 grabLog.log(Level.FINE, "UnGrab input on {0}", 894 new Object[] {String.valueOf(grabWindow)}); 895 } 896 if (grabWindow != null) { 897 grabWindow.ungrabInputImpl(); 898 XlibWrapper.XUngrabPointer(XToolkit.getDisplay(), CurrentTime); 899 XlibWrapper.XUngrabKeyboard(XToolkit.getDisplay(), CurrentTime); 900 XAwtState.setGrabWindow(null); 901 // we need to call XFlush() here to force ungrab 902 // see 6384219 for details 903 XlibWrapper.XFlush(XToolkit.getDisplay()); 904 } 905 } finally { 906 XToolkit.awtUnlock(); 907 } 908 } 909 910 // called from ungrabInput, used in popup windows to hide theirselfs in ungrabbing 911 void ungrabInputImpl() { 912 } 913 914 static void checkSecurity() { 915 if (XToolkit.isSecurityWarningEnabled() && XToolkit.isToolkitThread()) { 916 StackTraceElement stack[] = (new Throwable()).getStackTrace(); 917 log.warning(stack[1] + ": Security violation: calling user code on toolkit thread"); 918 } 919 } 920 921 public Set<Long> getChildren() { 922 synchronized (getStateLock()) { 923 return new HashSet<Long>(children); 924 } 925 } 926 927 // -------------- Event handling ---------------- 928 public void handleMapNotifyEvent(XEvent xev) { 929 mapped = true; 930 } 931 public void handleUnmapNotifyEvent(XEvent xev) { 932 mapped = false; 933 } 934 public void handleReparentNotifyEvent(XEvent xev) { 935 if (eventLog.isLoggable(Level.FINER)) { 936 XReparentEvent msg = xev.get_xreparent(); 937 eventLog.finer(msg.toString()); 938 } 939 } 940 public void handlePropertyNotify(XEvent xev) { 941 XPropertyEvent msg = xev.get_xproperty(); 942 if (XPropertyCache.isCachingSupported()) { 943 XPropertyCache.clearCache(window, XAtom.get(msg.get_atom())); 944 } 945 if (eventLog.isLoggable(Level.FINER)) { 946 eventLog.log(Level.FINER, "{0}", new Object[] {String.valueOf(msg)}); 947 } 948 } 949 950 public void handleDestroyNotify(XEvent xev) { 951 XAnyEvent xany = xev.get_xany(); 952 if (xany.get_window() == getWindow()) { 953 XToolkit.removeFromWinMap(getWindow(), this); 954 if (XPropertyCache.isCachingSupported()) { 955 XPropertyCache.clearCache(getWindow()); 956 } 957 } 958 if (xany.get_window() != getWindow()) { 959 synchronized (getStateLock()) { 960 children.remove(xany.get_window()); 961 } 962 } 963 } 964 965 public void handleCreateNotify(XEvent xev) { 966 XAnyEvent xany = xev.get_xany(); 967 if (xany.get_window() != getWindow()) { 968 synchronized (getStateLock()) { 969 children.add(xany.get_window()); 970 } 971 } 972 } 973 974 public void handleClientMessage(XEvent xev) { 975 if (eventLog.isLoggable(Level.FINER)) { 976 XClientMessageEvent msg = xev.get_xclient(); 977 eventLog.finer(msg.toString()); 978 } 979 } 980 981 public void handleVisibilityEvent(XEvent xev) { 982 } 983 public void handleKeyPress(XEvent xev) { 984 } 985 public void handleKeyRelease(XEvent xev) { 986 } 987 public void handleExposeEvent(XEvent xev) { 988 } 989 /** 990 * Activate automatic grab on first ButtonPress, 991 * deactivate on full mouse release 992 */ 993 public void handleButtonPressRelease(XEvent xev) { 994 XButtonEvent xbe = xev.get_xbutton(); 995 final int buttonState = xbe.get_state() & (Button1Mask | Button2Mask 996 | Button3Mask | Button4Mask | Button5Mask); 997 switch (xev.get_type()) { 998 case ButtonPress: 999 if (buttonState == 0) { 1000 XAwtState.setAutoGrabWindow(this); 1001 } 1002 break; 1003 case ButtonRelease: 1004 if (isFullRelease(buttonState, xbe.get_button())) { 1005 XAwtState.setAutoGrabWindow(null); 1006 } 1007 break; 1008 } 1009 } 1010 public void handleMotionNotify(XEvent xev) { 1011 } 1012 public void handleXCrossingEvent(XEvent xev) { 1013 } 1014 public void handleConfigureNotifyEvent(XEvent xev) { 1015 XConfigureEvent xe = xev.get_xconfigure(); 1016 if (insLog.isLoggable(Level.FINER)) { 1017 insLog.log(Level.FINER, "Configure, {0}", 1018 new Object[] {String.valueOf(xe)}); 1019 } 1020 x = xe.get_x(); 1021 y = xe.get_y(); 1022 width = xe.get_width(); 1023 height = xe.get_height(); 1024 } 1025 /** 1026 * Checks ButtonRelease released all Mouse buttons 1027 */ 1028 static boolean isFullRelease(int buttonState, int button) { 1029 switch (button) { 1030 case Button1: 1031 return buttonState == Button1Mask; 1032 case Button2: 1033 return buttonState == Button2Mask; 1034 case Button3: 1035 return buttonState == Button3Mask; 1036 case Button4: 1037 return buttonState == Button4Mask; 1038 case Button5: 1039 return buttonState == Button5Mask; 1040 } 1041 return buttonState == 0; 1042 } 1043 1044 static boolean isGrabbedEvent(XEvent ev, XBaseWindow target) { 1045 switch (ev.get_type()) { 1046 case ButtonPress: 1047 case ButtonRelease: 1048 case MotionNotify: 1049 case KeyPress: 1050 case KeyRelease: 1051 return true; 1052 case LeaveNotify: 1053 case EnterNotify: 1054 // We shouldn't dispatch this events to the grabbed components (see 6317481) 1055 // But this logic is important if the grabbed component is top-level (see realSync) 1056 return (target instanceof XWindowPeer); 1057 default: 1058 return false; 1059 } 1060 } 1061 /** 1062 * Dispatches event to the grab Window or event source window depending 1063 * on whether the grab is active and on the event type 1064 */ 1065 static void dispatchToWindow(XEvent ev) { 1066 XBaseWindow target = XAwtState.getGrabWindow(); 1067 if (target == null || !isGrabbedEvent(ev, target)) { 1068 target = XToolkit.windowToXWindow(ev.get_xany().get_window()); 1069 } 1070 if (target != null && target.checkInitialised()) { 1071 target.dispatchEvent(ev); 1072 } 1073 } 1074 1075 public void dispatchEvent(XEvent xev) { 1076 if (eventLog.isLoggable(Level.FINEST)) eventLog.finest(xev.toString()); 1077 int type = xev.get_type(); 1078 1079 if (isDisposed()) { 1080 return; 1081 } 1082 1083 switch (type) 1084 { 1085 case VisibilityNotify: 1086 handleVisibilityEvent(xev); 1087 break; 1088 case ClientMessage: 1089 handleClientMessage(xev); 1090 break; 1091 case Expose : 1092 case GraphicsExpose : 1093 handleExposeEvent(xev); 1094 break; 1095 case ButtonPress: 1096 case ButtonRelease: 1097 handleButtonPressRelease(xev); 1098 break; 1099 1100 case MotionNotify: 1101 handleMotionNotify(xev); 1102 break; 1103 case KeyPress: 1104 handleKeyPress(xev); 1105 break; 1106 case KeyRelease: 1107 handleKeyRelease(xev); 1108 break; 1109 case EnterNotify: 1110 case LeaveNotify: 1111 handleXCrossingEvent(xev); 1112 break; 1113 case ConfigureNotify: 1114 handleConfigureNotifyEvent(xev); 1115 break; 1116 case MapNotify: 1117 handleMapNotifyEvent(xev); 1118 break; 1119 case UnmapNotify: 1120 handleUnmapNotifyEvent(xev); 1121 break; 1122 case ReparentNotify: 1123 handleReparentNotifyEvent(xev); 1124 break; 1125 case PropertyNotify: 1126 handlePropertyNotify(xev); 1127 break; 1128 case DestroyNotify: 1129 handleDestroyNotify(xev); 1130 break; 1131 case CreateNotify: 1132 handleCreateNotify(xev); 1133 break; 1134 } 1135 } 1136 protected boolean isEventDisabled(XEvent e) { 1137 return false; 1138 } 1139 1140 int getX() { 1141 return x; 1142 } 1143 1144 int getY() { 1145 return y; 1146 } 1147 1148 int getWidth() { 1149 return width; 1150 } 1151 1152 int getHeight() { 1153 return height; 1154 } 1155 1156 void setDisposed(boolean d) { 1157 disposed = d; 1158 } 1159 1160 boolean isDisposed() { 1161 return disposed; 1162 } 1163 1164 public int getAbsoluteX() { 1165 XBaseWindow pw = getParentWindow(); 1166 if (pw != null) { 1167 return pw.getAbsoluteX() + getX(); 1168 } else { 1169 // Overridden for top-levels as their (x,y) is Java (x, y), not native location 1170 return getX(); 1171 } 1172 } 1173 1174 public int getAbsoluteY() { 1175 XBaseWindow pw = getParentWindow(); 1176 if (pw != null) { 1177 return pw.getAbsoluteY() + getY(); 1178 } else { 1179 return getY(); 1180 } 1181 } 1182 1183 public XBaseWindow getParentWindow() { 1184 return parentWindow; 1185 } 1186 1187 public XWindowPeer getToplevelXWindow() { 1188 XBaseWindow bw = this; 1189 while (bw != null && !(bw instanceof XWindowPeer)) { 1190 bw = bw.getParentWindow(); 1191 } 1192 return (XWindowPeer)bw; 1193 } 1194 public String toString() { 1195 return super.toString() + "(" + Long.toString(getWindow(), 16) + ")"; 1196 } 1197 1198 /** 1199 * Returns whether the given point is inside of the window. Coordinates are local. 1200 */ 1201 public boolean contains(int x, int y) { 1202 return x >= 0 && y >= 0 && x < getWidth() && y < getHeight(); 1203 } 1204 1205 /** 1206 * Returns whether the given point is inside of the window. Coordinates are global. 1207 */ 1208 public boolean containsGlobal(int x, int y) { 1209 return x >= getAbsoluteX() && y >= getAbsoluteY() && x < (getAbsoluteX()+getWidth()) && y < (getAbsoluteY()+getHeight()); 1210 } 1211 1212 }