1 /* 2 * Copyright (c) 2002, 2016, 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.AWTEvent; 28 import java.awt.AWTException; 29 import java.awt.BufferCapabilities; 30 import java.awt.Color; 31 import java.awt.Component; 32 import java.awt.Container; 33 import java.awt.Cursor; 34 import java.awt.Dimension; 35 import java.awt.Font; 36 import java.awt.FontMetrics; 37 import java.awt.Graphics; 38 import java.awt.GraphicsConfiguration; 39 import java.awt.Image; 40 import java.awt.Insets; 41 import java.awt.Rectangle; 42 import java.awt.SystemColor; 43 import java.awt.Toolkit; 44 import java.awt.Window; 45 import java.awt.dnd.DropTarget; 46 import java.awt.dnd.peer.DropTargetPeer; 47 import java.awt.event.FocusEvent; 48 import java.awt.event.InputEvent; 49 import java.awt.event.InputMethodEvent; 50 import java.awt.event.KeyEvent; 51 import java.awt.event.MouseEvent; 52 import java.awt.event.MouseWheelEvent; 53 import java.awt.event.PaintEvent; 54 import java.awt.event.WindowEvent; 55 import java.awt.image.ImageObserver; 56 import java.awt.image.ImageProducer; 57 import java.awt.image.VolatileImage; 58 import java.awt.peer.ComponentPeer; 59 import java.awt.peer.ContainerPeer; 60 import java.util.Collection; 61 import java.util.Objects; 62 import java.util.Set; 63 64 import sun.awt.AWTAccessor.ComponentAccessor; 65 import sun.util.logging.PlatformLogger; 66 import sun.awt.*; 67 import sun.awt.event.IgnorePaintEvent; 68 import sun.awt.image.SunVolatileImage; 69 import sun.awt.image.ToolkitImage; 70 import sun.java2d.BackBufferCapsProvider; 71 import sun.java2d.pipe.Region; 72 73 74 public class XComponentPeer extends XWindow implements ComponentPeer, DropTargetPeer, 75 BackBufferCapsProvider 76 { 77 private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.X11.XComponentPeer"); 78 private static final PlatformLogger buffersLog = PlatformLogger.getLogger("sun.awt.X11.XComponentPeer.multibuffer"); 79 private static final PlatformLogger focusLog = PlatformLogger.getLogger("sun.awt.X11.focus.XComponentPeer"); 80 private static final PlatformLogger fontLog = PlatformLogger.getLogger("sun.awt.X11.font.XComponentPeer"); 81 private static final PlatformLogger enableLog = PlatformLogger.getLogger("sun.awt.X11.enable.XComponentPeer"); 82 private static final PlatformLogger shapeLog = PlatformLogger.getLogger("sun.awt.X11.shape.XComponentPeer"); 83 84 boolean paintPending = false; 85 boolean isLayouting = false; 86 private boolean enabled; 87 88 // Actually used only by XDecoratedPeer 89 protected int boundsOperation; 90 91 Color foreground; 92 Color background; 93 94 // Colors calculated as on Motif using MotifColorUtilties. 95 // If you use these, call updateMotifColors() in the peer's Constructor and 96 // setBackground(). Examples are XCheckboxPeer and XButtonPeer. 97 Color darkShadow; 98 Color lightShadow; 99 Color selectColor; 100 101 Font font; 102 private long backBuffer = 0; 103 private VolatileImage xBackBuffer = null; 104 105 static Color[] systemColors; 106 107 XComponentPeer() { 108 } 109 110 XComponentPeer (XCreateWindowParams params) { 111 super(params); 112 } 113 114 XComponentPeer(Component target, long parentWindow, Rectangle bounds) { 115 super(target, parentWindow, bounds); 116 } 117 118 /** 119 * Standard peer constructor, with corresponding Component 120 */ 121 XComponentPeer(Component target) { 122 super(target); 123 } 124 125 126 void preInit(XCreateWindowParams params) { 127 super.preInit(params); 128 boundsOperation = DEFAULT_OPERATION; 129 } 130 void postInit(XCreateWindowParams params) { 131 super.postInit(params); 132 133 pSetCursor(target.getCursor()); 134 135 foreground = target.getForeground(); 136 background = target.getBackground(); 137 font = target.getFont(); 138 139 if (isInitialReshape()) { 140 Rectangle r = target.getBounds(); 141 reshape(r.x, r.y, r.width, r.height); 142 } 143 144 setEnabled(target.isEnabled()); 145 146 if (target.isVisible()) { 147 setVisible(true); 148 } 149 } 150 151 protected boolean isInitialReshape() { 152 return true; 153 } 154 155 public void reparent(ContainerPeer newNativeParent) { 156 XComponentPeer newPeer = (XComponentPeer)newNativeParent; 157 XToolkit.awtLock(); 158 try { 159 XlibWrapper.XReparentWindow(XToolkit.getDisplay(), 160 getWindow(), newPeer.getContentWindow(), 161 scaleUp(x), scaleUp(y)); 162 parentWindow = newPeer; 163 } finally { 164 XToolkit.awtUnlock(); 165 } 166 } 167 public boolean isReparentSupported() { 168 return System.getProperty("sun.awt.X11.XComponentPeer.reparentNotSupported", "false").equals("false"); 169 } 170 171 @SuppressWarnings("deprecation") 172 public boolean isObscured() { 173 Container container = (target instanceof Container) ? 174 (Container)target : target.getParent(); 175 176 if (container == null) { 177 return true; 178 } 179 180 Container parent; 181 while ((parent = container.getParent()) != null) { 182 container = parent; 183 } 184 185 if (container instanceof Window) { 186 XWindowPeer wpeer = AWTAccessor.getComponentAccessor() 187 .getPeer(container); 188 if (wpeer != null) { 189 return (wpeer.winAttr.visibilityState != 190 XWindowAttributesData.AWT_UNOBSCURED); 191 } 192 } 193 return true; 194 } 195 196 public boolean canDetermineObscurity() { 197 return true; 198 } 199 200 /************************************************* 201 * FOCUS STUFF 202 *************************************************/ 203 204 /** 205 * Keeps the track of focused state of the _NATIVE_ window 206 */ 207 boolean bHasFocus = false; 208 209 /** 210 * Descendants should use this method to determine whether or not native window 211 * has focus. 212 */ 213 public final boolean hasFocus() { 214 return bHasFocus; 215 } 216 217 /** 218 * Called when component receives focus 219 */ 220 public void focusGained(FocusEvent e) { 221 if (focusLog.isLoggable(PlatformLogger.Level.FINE)) { 222 focusLog.fine("{0}", e); 223 } 224 bHasFocus = true; 225 } 226 227 /** 228 * Called when component loses focus 229 */ 230 public void focusLost(FocusEvent e) { 231 if (focusLog.isLoggable(PlatformLogger.Level.FINE)) { 232 focusLog.fine("{0}", e); 233 } 234 bHasFocus = false; 235 } 236 237 public boolean isFocusable() { 238 /* should be implemented by other sub-classes */ 239 return false; 240 } 241 242 static final AWTEvent wrapInSequenced(AWTEvent event) { 243 return AWTAccessor.getSequencedEventAccessor().create(event); 244 } 245 246 // TODO: consider moving it to KeyboardFocusManagerPeerImpl 247 @SuppressWarnings("deprecation") 248 public final boolean requestFocus(Component lightweightChild, boolean temporary, 249 boolean focusedWindowChangeAllowed, long time, 250 FocusEvent.Cause cause) 251 { 252 if (XKeyboardFocusManagerPeer. 253 processSynchronousLightweightTransfer(target, lightweightChild, temporary, 254 focusedWindowChangeAllowed, time)) 255 { 256 return true; 257 } 258 259 int result = XKeyboardFocusManagerPeer. 260 shouldNativelyFocusHeavyweight(target, lightweightChild, 261 temporary, focusedWindowChangeAllowed, 262 time, cause); 263 264 switch (result) { 265 case XKeyboardFocusManagerPeer.SNFH_FAILURE: 266 return false; 267 case XKeyboardFocusManagerPeer.SNFH_SUCCESS_PROCEED: 268 // Currently we just generate focus events like we deal with lightweight instead of calling 269 // XSetInputFocus on native window 270 if (focusLog.isLoggable(PlatformLogger.Level.FINER)) { 271 focusLog.finer("Proceeding with request to " + 272 lightweightChild + " in " + target); 273 } 274 /** 275 * The problems with requests in non-focused window arise because shouldNativelyFocusHeavyweight 276 * checks that native window is focused while appropriate WINDOW_GAINED_FOCUS has not yet 277 * been processed - it is in EventQueue. Thus, SNFH allows native request and stores request record 278 * in requests list - and it breaks our requests sequence as first record on WGF should be the last 279 * focus owner which had focus before WLF. So, we should not add request record for such requests 280 * but store this component in mostRecent - and return true as before for compatibility. 281 */ 282 Window parentWindow = SunToolkit.getContainingWindow(target); 283 if (parentWindow == null) { 284 return rejectFocusRequestHelper("WARNING: Parent window is null"); 285 } 286 XWindowPeer wpeer = AWTAccessor.getComponentAccessor() 287 .getPeer(parentWindow); 288 if (wpeer == null) { 289 return rejectFocusRequestHelper("WARNING: Parent window's peer is null"); 290 } 291 /* 292 * Passing null 'actualFocusedWindow' as we don't want to restore focus on it 293 * when a component inside a Frame is requesting focus. 294 * See 6314575 for details. 295 */ 296 boolean res = wpeer.requestWindowFocus(null); 297 298 if (focusLog.isLoggable(PlatformLogger.Level.FINER)) { 299 focusLog.finer("Requested window focus: " + res); 300 } 301 // If parent window can be made focused and has been made focused(synchronously) 302 // then we can proceed with children, otherwise we retreat. 303 if (!(res && parentWindow.isFocused())) { 304 return rejectFocusRequestHelper("Waiting for asynchronous processing of the request"); 305 } 306 return XKeyboardFocusManagerPeer.deliverFocus(lightweightChild, 307 target, 308 temporary, 309 focusedWindowChangeAllowed, 310 time, cause); 311 // Motif compatibility code 312 case XKeyboardFocusManagerPeer.SNFH_SUCCESS_HANDLED: 313 // Either lightweight or excessive request - all events are generated. 314 return true; 315 } 316 return false; 317 } 318 319 private boolean rejectFocusRequestHelper(String logMsg) { 320 if (focusLog.isLoggable(PlatformLogger.Level.FINER)) { 321 focusLog.finer(logMsg); 322 } 323 XKeyboardFocusManagerPeer.removeLastFocusRequest(target); 324 return false; 325 } 326 327 void handleJavaFocusEvent(AWTEvent e) { 328 if (focusLog.isLoggable(PlatformLogger.Level.FINER)) { 329 focusLog.finer(e.toString()); 330 } 331 if (e.getID() == FocusEvent.FOCUS_GAINED) { 332 focusGained((FocusEvent)e); 333 } else { 334 focusLost((FocusEvent)e); 335 } 336 } 337 338 void handleJavaWindowFocusEvent(AWTEvent e) { 339 } 340 341 /************************************************* 342 * END OF FOCUS STUFF 343 *************************************************/ 344 345 346 347 public void setVisible(boolean b) { 348 xSetVisible(b); 349 } 350 351 public void hide() { 352 setVisible(false); 353 } 354 355 /** 356 * @see java.awt.peer.ComponentPeer 357 */ 358 public void setEnabled(final boolean value) { 359 if (enableLog.isLoggable(PlatformLogger.Level.FINE)) { 360 enableLog.fine("{0}ing {1}", (value ? "Enabl" : "Disabl"), this); 361 } 362 boolean status = value; 363 // If any of our heavyweight ancestors are disable, we should be too 364 // See 6176875 for more information 365 final Container cp = SunToolkit.getNativeContainer(target); 366 final ComponentAccessor acc = AWTAccessor.getComponentAccessor(); 367 if (cp != null) { 368 status &= acc.<XComponentPeer>getPeer(cp).isEnabled(); 369 } 370 synchronized (getStateLock()) { 371 if (enabled == status) { 372 return; 373 } 374 enabled = status; 375 } 376 377 if (target instanceof Container) { 378 final Component[] list = ((Container) target).getComponents(); 379 for (final Component child : list) { 380 final ComponentPeer p = acc.getPeer(child); 381 if (p != null) { 382 p.setEnabled(status && child.isEnabled()); 383 } 384 } 385 } 386 repaint(); 387 } 388 389 // 390 // public so aw/Window can call it 391 // 392 public final boolean isEnabled() { 393 synchronized (getStateLock()) { 394 return enabled; 395 } 396 } 397 398 @Override 399 public void paint(final Graphics g) { 400 super.paint(g); 401 // allow target to change the picture 402 target.paint(g); 403 } 404 405 public Graphics getGraphics() { 406 return getGraphics(surfaceData, getPeerForeground(), getPeerBackground(), getPeerFont()); 407 } 408 public void print(Graphics g) { 409 // clear rect here to emulate X clears rect before Expose 410 g.setColor(target.getBackground()); 411 g.fillRect(0, 0, target.getWidth(), target.getHeight()); 412 g.setColor(target.getForeground()); 413 // paint peer 414 paintPeer(g); 415 // allow target to change the picture 416 target.print(g); 417 } 418 419 public void setBounds(int x, int y, int width, int height, int op) { 420 this.x = x; 421 this.y = y; 422 this.width = width; 423 this.height = height; 424 xSetBounds(x,y,width,height); 425 validateSurface(); 426 layout(); 427 } 428 429 public void reshape(int x, int y, int width, int height) { 430 setBounds(x, y, width, height, SET_BOUNDS); 431 } 432 433 public void coalescePaintEvent(PaintEvent e) { 434 Rectangle r = e.getUpdateRect(); 435 if (!(e instanceof IgnorePaintEvent)) { 436 paintArea.add(r, e.getID()); 437 } 438 if (true) { 439 switch(e.getID()) { 440 case PaintEvent.UPDATE: 441 if (log.isLoggable(PlatformLogger.Level.FINER)) { 442 log.finer("XCP coalescePaintEvent : UPDATE : add : x = " + 443 r.x + ", y = " + r.y + ", width = " + r.width + ",height = " + r.height); 444 } 445 return; 446 case PaintEvent.PAINT: 447 if (log.isLoggable(PlatformLogger.Level.FINER)) { 448 log.finer("XCP coalescePaintEvent : PAINT : add : x = " + 449 r.x + ", y = " + r.y + ", width = " + r.width + ",height = " + r.height); 450 } 451 return; 452 } 453 } 454 } 455 456 XWindowPeer getParentTopLevel() { 457 ComponentAccessor compAccessor = AWTAccessor.getComponentAccessor(); 458 Container parent = (target instanceof Container) ? ((Container)target) : (compAccessor.getParent(target)); 459 // Search for parent window 460 while (parent != null && !(parent instanceof Window)) { 461 parent = compAccessor.getParent(parent); 462 } 463 if (parent != null) { 464 return (XWindowPeer)compAccessor.getPeer(parent); 465 } else { 466 return null; 467 } 468 } 469 470 /* This method is intended to be over-ridden by peers to perform user interaction */ 471 void handleJavaMouseEvent(MouseEvent e) { 472 switch (e.getID()) { 473 case MouseEvent.MOUSE_PRESSED: 474 if (target == e.getSource() && 475 !target.isFocusOwner() && 476 XKeyboardFocusManagerPeer.shouldFocusOnClick(target)) 477 { 478 XWindowPeer parentXWindow = getParentTopLevel(); 479 Window parentWindow = ((Window)parentXWindow.getTarget()); 480 // Simple windows are non-focusable in X terms but focusable in Java terms. 481 // As X-non-focusable they don't receive any focus events - we should generate them 482 // by ourselfves. 483 // if (parentXWindow.isFocusableWindow() /*&& parentXWindow.isSimpleWindow()*/ && 484 // !(getCurrentNativeFocusedWindow() == parentWindow)) 485 // { 486 // setCurrentNativeFocusedWindow(parentWindow); 487 // WindowEvent wfg = new WindowEvent(parentWindow, WindowEvent.WINDOW_GAINED_FOCUS); 488 // parentWindow.dispatchEvent(wfg); 489 // } 490 XKeyboardFocusManagerPeer.requestFocusFor(target, FocusEvent.Cause.MOUSE_EVENT); 491 } 492 break; 493 } 494 } 495 496 /* This method is intended to be over-ridden by peers to perform user interaction */ 497 void handleJavaKeyEvent(KeyEvent e) { 498 } 499 500 /* This method is intended to be over-ridden by peers to perform user interaction */ 501 void handleJavaMouseWheelEvent(MouseWheelEvent e) { 502 } 503 504 505 /* This method is intended to be over-ridden by peers to perform user interaction */ 506 void handleJavaInputMethodEvent(InputMethodEvent e) { 507 } 508 509 void handleF10JavaKeyEvent(KeyEvent e) { 510 if (e.getID() == KeyEvent.KEY_PRESSED && e.getKeyCode() == KeyEvent.VK_F10) { 511 XWindowPeer winPeer = this.getToplevelXWindow(); 512 if (winPeer instanceof XFramePeer) { 513 XMenuBarPeer mPeer = ((XFramePeer)winPeer).getMenubarPeer(); 514 if (mPeer != null) { 515 mPeer.handleF10KeyPress(e); 516 } 517 } 518 } 519 } 520 521 @SuppressWarnings("fallthrough") 522 public void handleEvent(java.awt.AWTEvent e) { 523 if ((e instanceof InputEvent) && !((InputEvent)e).isConsumed() && target.isEnabled()) { 524 if (e instanceof MouseEvent) { 525 if (e instanceof MouseWheelEvent) { 526 handleJavaMouseWheelEvent((MouseWheelEvent) e); 527 } 528 else 529 handleJavaMouseEvent((MouseEvent) e); 530 } 531 else if (e instanceof KeyEvent) { 532 handleF10JavaKeyEvent((KeyEvent)e); 533 handleJavaKeyEvent((KeyEvent)e); 534 } 535 } 536 else if (e instanceof KeyEvent && !((InputEvent)e).isConsumed()) { 537 // even if target is disabled. 538 handleF10JavaKeyEvent((KeyEvent)e); 539 } 540 else if (e instanceof InputMethodEvent) { 541 handleJavaInputMethodEvent((InputMethodEvent) e); 542 } 543 544 int id = e.getID(); 545 546 switch(id) { 547 case PaintEvent.PAINT: 548 // Got native painting 549 paintPending = false; 550 // Fallthrough to next statement 551 case PaintEvent.UPDATE: 552 // Skip all painting while layouting and all UPDATEs 553 // while waiting for native paint 554 if (!isLayouting && !paintPending) { 555 paintArea.paint(target,false); 556 } 557 return; 558 case FocusEvent.FOCUS_LOST: 559 case FocusEvent.FOCUS_GAINED: 560 handleJavaFocusEvent(e); 561 break; 562 case WindowEvent.WINDOW_LOST_FOCUS: 563 case WindowEvent.WINDOW_GAINED_FOCUS: 564 handleJavaWindowFocusEvent(e); 565 break; 566 default: 567 break; 568 } 569 570 } 571 572 public Dimension getMinimumSize() { 573 return target.getSize(); 574 } 575 576 public Dimension getPreferredSize() { 577 return getMinimumSize(); 578 } 579 580 public void layout() {} 581 582 void updateMotifColors(Color bg) { 583 int red = bg.getRed(); 584 int green = bg.getGreen(); 585 int blue = bg.getBlue(); 586 587 darkShadow = new Color(MotifColorUtilities.calculateBottomShadowFromBackground(red,green,blue)); 588 lightShadow = new Color(MotifColorUtilities.calculateTopShadowFromBackground(red,green,blue)); 589 selectColor= new Color(MotifColorUtilities.calculateSelectFromBackground(red,green,blue)); 590 } 591 592 /* 593 * Draw a 3D rectangle using the Motif colors. 594 * "Normal" rectangles have shadows on the bottom. 595 * "Depressed" rectangles (such as pressed buttons) have shadows on the top, 596 * in which case true should be passed for topShadow. 597 */ 598 public void drawMotif3DRect(Graphics g, 599 int x, int y, int width, int height, 600 boolean topShadow) { 601 g.setColor(topShadow ? darkShadow : lightShadow); 602 g.drawLine(x, y, x+width, y); // top 603 g.drawLine(x, y+height, x, y); // left 604 605 g.setColor(topShadow ? lightShadow : darkShadow ); 606 g.drawLine(x+1, y+height, x+width, y+height); // bottom 607 g.drawLine(x+width, y+height, x+width, y+1); // right 608 } 609 610 @Override 611 public void setBackground(Color c) { 612 if (log.isLoggable(PlatformLogger.Level.FINE)) { 613 log.fine("Set background to " + c); 614 } 615 synchronized (getStateLock()) { 616 if (Objects.equals(background, c)) { 617 return; 618 } 619 background = c; 620 } 621 super.setBackground(c); 622 repaint(); 623 } 624 625 @Override 626 public void setForeground(Color c) { 627 if (log.isLoggable(PlatformLogger.Level.FINE)) { 628 log.fine("Set foreground to " + c); 629 } 630 synchronized (getStateLock()) { 631 if (Objects.equals(foreground, c)) { 632 return; 633 } 634 foreground = c; 635 } 636 repaint(); 637 } 638 639 /** 640 * Gets the font metrics for the specified font. 641 * @param font the font for which font metrics is to be 642 * obtained 643 * @return the font metrics for {@code font} 644 * @see #getFont 645 * @see java.awt.peer.ComponentPeer#getFontMetrics(Font) 646 * @see Toolkit#getFontMetrics(Font) 647 * @since 1.0 648 */ 649 public FontMetrics getFontMetrics(Font font) { 650 if (fontLog.isLoggable(PlatformLogger.Level.FINE)) { 651 fontLog.fine("Getting font metrics for " + font); 652 } 653 return sun.font.FontDesignMetrics.getMetrics(font); 654 } 655 656 @Override 657 public void setFont(Font f) { 658 if (f == null) { 659 f = XWindow.getDefaultFont(); 660 } 661 synchronized (getStateLock()) { 662 if (f.equals(font)) { 663 return; 664 } 665 font = f; 666 } 667 // as it stands currently we don't need to do layout since 668 // layout is done in the Component upon setFont. 669 //layout(); 670 repaint(); 671 } 672 673 public Font getFont() { 674 return font; 675 } 676 677 public void updateCursorImmediately() { 678 XGlobalCursorManager.getCursorManager().updateCursorImmediately(); 679 } 680 681 public final void pSetCursor(Cursor cursor) { 682 this.pSetCursor(cursor, true); 683 } 684 685 /* 686 * The method changes the cursor. 687 * @param cursor a new cursor to change to. 688 * @param ignoreSubComponents if {@code true} is passed then 689 * the new cursor will be installed on window. 690 * if {@code false} is passed then 691 * subsequent components will try to handle 692 * this request and install their cursor. 693 */ 694 //ignoreSubComponents not used here 695 public void pSetCursor(Cursor cursor, boolean ignoreSubComponents) { 696 XToolkit.awtLock(); 697 try { 698 long xcursor = XGlobalCursorManager.getCursor(cursor); 699 700 XSetWindowAttributes xwa = new XSetWindowAttributes(); 701 xwa.set_cursor(xcursor); 702 703 long valuemask = XConstants.CWCursor; 704 705 XlibWrapper.XChangeWindowAttributes(XToolkit.getDisplay(),getWindow(),valuemask,xwa.pData); 706 XlibWrapper.XFlush(XToolkit.getDisplay()); 707 xwa.dispose(); 708 } finally { 709 XToolkit.awtUnlock(); 710 } 711 } 712 713 public Image createImage(ImageProducer producer) { 714 return new ToolkitImage(producer); 715 } 716 717 public Image createImage(int width, int height) { 718 return graphicsConfig.createAcceleratedImage(target, width, height); 719 } 720 721 public VolatileImage createVolatileImage(int width, int height) { 722 return new SunVolatileImage(target, width, height); 723 } 724 725 public boolean prepareImage(Image img, int w, int h, ImageObserver o) { 726 return Toolkit.getDefaultToolkit().prepareImage(img, w, h, o); 727 } 728 729 public int checkImage(Image img, int w, int h, ImageObserver o) { 730 return Toolkit.getDefaultToolkit().checkImage(img, w, h, o); 731 } 732 733 public Dimension preferredSize() { 734 return getPreferredSize(); 735 } 736 737 public Dimension minimumSize() { 738 return getMinimumSize(); 739 } 740 741 public Insets getInsets() { 742 return new Insets(0, 0, 0, 0); 743 } 744 745 public void beginValidate() { 746 } 747 748 public void endValidate() { 749 } 750 751 752 /** 753 * DEPRECATED: Replaced by getInsets(). 754 */ 755 756 public Insets insets() { 757 return getInsets(); 758 } 759 760 // Returns true if we are inside begin/endLayout and 761 // are waiting for native painting 762 public boolean isPaintPending() { 763 return paintPending && isLayouting; 764 } 765 766 public boolean handlesWheelScrolling() { 767 return false; 768 } 769 770 public void beginLayout() { 771 // Skip all painting till endLayout 772 isLayouting = true; 773 774 } 775 776 public void endLayout() { 777 if (!paintPending && !paintArea.isEmpty() 778 && !AWTAccessor.getComponentAccessor().getIgnoreRepaint(target)) 779 { 780 // if not waiting for native painting repaint damaged area 781 postEvent(new PaintEvent(target, PaintEvent.PAINT, 782 new Rectangle())); 783 } 784 isLayouting = false; 785 } 786 787 public Color getWinBackground() { 788 return getPeerBackground(); 789 } 790 791 static int[] getRGBvals(Color c) { 792 793 int rgbvals[] = new int[3]; 794 795 rgbvals[0] = c.getRed(); 796 rgbvals[1] = c.getGreen(); 797 rgbvals[2] = c.getBlue(); 798 799 return rgbvals; 800 } 801 802 static final int BACKGROUND_COLOR = 0; 803 static final int HIGHLIGHT_COLOR = 1; 804 static final int SHADOW_COLOR = 2; 805 static final int FOREGROUND_COLOR = 3; 806 807 public Color[] getGUIcolors() { 808 Color c[] = new Color[4]; 809 float backb, highb, shadowb, hue, saturation; 810 c[BACKGROUND_COLOR] = getWinBackground(); 811 if (c[BACKGROUND_COLOR] == null) { 812 c[BACKGROUND_COLOR] = super.getWinBackground(); 813 } 814 if (c[BACKGROUND_COLOR] == null) { 815 c[BACKGROUND_COLOR] = Color.lightGray; 816 } 817 818 int[] rgb = getRGBvals(c[BACKGROUND_COLOR]); 819 820 float[] hsb = Color.RGBtoHSB(rgb[0],rgb[1],rgb[2],null); 821 822 hue = hsb[0]; 823 saturation = hsb[1]; 824 backb = hsb[2]; 825 826 827 /* Calculate Highlight Brightness */ 828 829 highb = backb + 0.2f; 830 shadowb = backb - 0.4f; 831 if ((highb > 1.0) ) { 832 if ((1.0 - backb) < 0.05) { 833 highb = shadowb + 0.25f; 834 } else { 835 highb = 1.0f; 836 } 837 } else { 838 if (shadowb < 0.0) { 839 if ((backb - 0.0) < 0.25) { 840 highb = backb + 0.75f; 841 shadowb = highb - 0.2f; 842 } else { 843 shadowb = 0.0f; 844 } 845 } 846 } 847 c[HIGHLIGHT_COLOR] = Color.getHSBColor(hue,saturation,highb); 848 c[SHADOW_COLOR] = Color.getHSBColor(hue,saturation,shadowb); 849 850 851 /* 852 c[SHADOW_COLOR] = c[BACKGROUND_COLOR].darker(); 853 int r2 = c[SHADOW_COLOR].getRed(); 854 int g2 = c[SHADOW_COLOR].getGreen(); 855 int b2 = c[SHADOW_COLOR].getBlue(); 856 */ 857 858 c[FOREGROUND_COLOR] = getPeerForeground(); 859 if (c[FOREGROUND_COLOR] == null) { 860 c[FOREGROUND_COLOR] = Color.black; 861 } 862 /* 863 if ((c[BACKGROUND_COLOR].equals(c[HIGHLIGHT_COLOR])) 864 && (c[BACKGROUND_COLOR].equals(c[SHADOW_COLOR]))) { 865 c[SHADOW_COLOR] = new Color(c[BACKGROUND_COLOR].getRed() + 75, 866 c[BACKGROUND_COLOR].getGreen() + 75, 867 c[BACKGROUND_COLOR].getBlue() + 75); 868 c[HIGHLIGHT_COLOR] = c[SHADOW_COLOR].brighter(); 869 } else if (c[BACKGROUND_COLOR].equals(c[HIGHLIGHT_COLOR])) { 870 c[HIGHLIGHT_COLOR] = c[SHADOW_COLOR]; 871 c[SHADOW_COLOR] = c[SHADOW_COLOR].darker(); 872 } 873 */ 874 if (! isEnabled()) { 875 c[BACKGROUND_COLOR] = c[BACKGROUND_COLOR].darker(); 876 // Reduce the contrast 877 // Calculate the NTSC gray (NB: REC709 L* might be better!) 878 // for foreground and background; then multiply the foreground 879 // by the average lightness 880 881 882 Color tc = c[BACKGROUND_COLOR]; 883 int bg = tc.getRed() * 30 + tc.getGreen() * 59 + tc.getBlue() * 11; 884 885 tc = c[FOREGROUND_COLOR]; 886 int fg = tc.getRed() * 30 + tc.getGreen() * 59 + tc.getBlue() * 11; 887 888 float ave = (float) ((fg + bg) / 51000.0); 889 // 255 * 100 * 2 890 891 Color newForeground = new Color((int) (tc.getRed() * ave), 892 (int) (tc.getGreen() * ave), 893 (int) (tc.getBlue() * ave)); 894 895 if (newForeground.equals(c[FOREGROUND_COLOR])) { 896 // This probably means the foreground color is black or white 897 newForeground = new Color(ave, ave, ave); 898 } 899 c[FOREGROUND_COLOR] = newForeground; 900 901 } 902 903 904 return c; 905 } 906 907 /** 908 * Returns an array of Colors similar to getGUIcolors(), but using the 909 * System colors. This is useful if pieces of a Component (such as 910 * the integrated scrollbars of a List) should retain the System color 911 * instead of the background color set by Component.setBackground(). 912 */ 913 static Color[] getSystemColors() { 914 if (systemColors == null) { 915 systemColors = new Color[4]; 916 systemColors[BACKGROUND_COLOR] = SystemColor.window; 917 systemColors[HIGHLIGHT_COLOR] = SystemColor.controlLtHighlight; 918 systemColors[SHADOW_COLOR] = SystemColor.controlShadow; 919 systemColors[FOREGROUND_COLOR] = SystemColor.windowText; 920 } 921 return systemColors; 922 } 923 924 /** 925 * Draw a 3D oval. 926 */ 927 public void draw3DOval(Graphics g, Color colors[], 928 int x, int y, int w, int h, boolean raised) 929 { 930 Color c = g.getColor(); 931 g.setColor(raised ? colors[HIGHLIGHT_COLOR] : colors[SHADOW_COLOR]); 932 g.drawArc(x, y, w, h, 45, 180); 933 g.setColor(raised ? colors[SHADOW_COLOR] : colors[HIGHLIGHT_COLOR]); 934 g.drawArc(x, y, w, h, 225, 180); 935 g.setColor(c); 936 } 937 938 public void draw3DRect(Graphics g, Color colors[], 939 int x, int y, int width, int height, boolean raised) 940 { 941 Color c = g.getColor(); 942 g.setColor(raised ? colors[HIGHLIGHT_COLOR] : colors[SHADOW_COLOR]); 943 g.drawLine(x, y, x, y + height); 944 g.drawLine(x + 1, y, x + width - 1, y); 945 g.setColor(raised ? colors[SHADOW_COLOR] : colors[HIGHLIGHT_COLOR]); 946 g.drawLine(x + 1, y + height, x + width, y + height); 947 g.drawLine(x + width, y, x + width, y + height - 1); 948 g.setColor(c); 949 } 950 951 /* 952 * drawXXX() methods are used to print the native components by 953 * rendering the Motif look ourselves. 954 * ToDo(aim): needs to query native motif for more accurate color 955 * information. 956 */ 957 void draw3DOval(Graphics g, Color bg, 958 int x, int y, int w, int h, boolean raised) 959 { 960 Color c = g.getColor(); 961 Color shadow = bg.darker(); 962 Color highlight = bg.brighter(); 963 964 g.setColor(raised ? highlight : shadow); 965 g.drawArc(x, y, w, h, 45, 180); 966 g.setColor(raised ? shadow : highlight); 967 g.drawArc(x, y, w, h, 225, 180); 968 g.setColor(c); 969 } 970 971 void draw3DRect(Graphics g, Color bg, 972 int x, int y, int width, int height, 973 boolean raised) { 974 Color c = g.getColor(); 975 Color shadow = bg.darker(); 976 Color highlight = bg.brighter(); 977 978 g.setColor(raised ? highlight : shadow); 979 g.drawLine(x, y, x, y + height); 980 g.drawLine(x + 1, y, x + width - 1, y); 981 g.setColor(raised ? shadow : highlight); 982 g.drawLine(x + 1, y + height, x + width, y + height); 983 g.drawLine(x + width, y, x + width, y + height - 1); 984 g.setColor(c); 985 } 986 987 void drawScrollbar(Graphics g, Color bg, int thickness, int length, 988 int min, int max, int val, int vis, boolean horizontal) { 989 Color c = g.getColor(); 990 double f = (double)(length - 2*(thickness-1)) / Math.max(1, ((max - min) + vis)); 991 int v1 = thickness + (int)(f * (val - min)); 992 int v2 = (int)(f * vis); 993 int w2 = thickness-4; 994 int tpts_x[] = new int[3]; 995 int tpts_y[] = new int[3]; 996 997 if (length < 3*w2 ) { 998 v1 = v2 = 0; 999 if (length < 2*w2 + 2) { 1000 w2 = (length-2)/2; 1001 } 1002 } else if (v2 < 7) { 1003 // enforce a minimum handle size 1004 v1 = Math.max(0, v1 - ((7 - v2)>>1)); 1005 v2 = 7; 1006 } 1007 1008 int ctr = thickness/2; 1009 int sbmin = ctr - w2/2; 1010 int sbmax = ctr + w2/2; 1011 1012 // paint the background slightly darker 1013 { 1014 Color d = new Color((int) (bg.getRed() * 0.85), 1015 (int) (bg.getGreen() * 0.85), 1016 (int) (bg.getBlue() * 0.85)); 1017 1018 g.setColor(d); 1019 if (horizontal) { 1020 g.fillRect(0, 0, length, thickness); 1021 } else { 1022 g.fillRect(0, 0, thickness, length); 1023 } 1024 } 1025 1026 // paint the thumb and arrows in the normal background color 1027 g.setColor(bg); 1028 if (v1 > 0) { 1029 if (horizontal) { 1030 g.fillRect(v1, 3, v2, thickness-3); 1031 } else { 1032 g.fillRect(3, v1, thickness-3, v2); 1033 } 1034 } 1035 1036 tpts_x[0] = ctr; tpts_y[0] = 2; 1037 tpts_x[1] = sbmin; tpts_y[1] = w2; 1038 tpts_x[2] = sbmax; tpts_y[2] = w2; 1039 if (horizontal) { 1040 g.fillPolygon(tpts_y, tpts_x, 3); 1041 } else { 1042 g.fillPolygon(tpts_x, tpts_y, 3); 1043 } 1044 1045 tpts_y[0] = length-2; 1046 tpts_y[1] = length-w2; 1047 tpts_y[2] = length-w2; 1048 if (horizontal) { 1049 g.fillPolygon(tpts_y, tpts_x, 3); 1050 } else { 1051 g.fillPolygon(tpts_x, tpts_y, 3); 1052 } 1053 1054 Color highlight = bg.brighter(); 1055 1056 // // // // draw the "highlighted" edges 1057 g.setColor(highlight); 1058 1059 // outline & arrows 1060 if (horizontal) { 1061 g.drawLine(1, thickness, length - 1, thickness); 1062 g.drawLine(length - 1, 1, length - 1, thickness); 1063 1064 // arrows 1065 g.drawLine(1, ctr, w2, sbmin); 1066 g.drawLine(length - w2, sbmin, length - w2, sbmax); 1067 g.drawLine(length - w2, sbmin, length - 2, ctr); 1068 1069 } else { 1070 g.drawLine(thickness, 1, thickness, length - 1); 1071 g.drawLine(1, length - 1, thickness, length - 1); 1072 1073 // arrows 1074 g.drawLine(ctr, 1, sbmin, w2); 1075 g.drawLine(sbmin, length - w2, sbmax, length - w2); 1076 g.drawLine(sbmin, length - w2, ctr, length - 2); 1077 } 1078 1079 // thumb 1080 if (v1 > 0) { 1081 if (horizontal) { 1082 g.drawLine(v1, 2, v1 + v2, 2); 1083 g.drawLine(v1, 2, v1, thickness-3); 1084 } else { 1085 g.drawLine(2, v1, 2, v1 + v2); 1086 g.drawLine(2, v1, thickness-3, v1); 1087 } 1088 } 1089 1090 Color shadow = bg.darker(); 1091 1092 // // // // draw the "shadowed" edges 1093 g.setColor(shadow); 1094 1095 // outline && arrows 1096 if (horizontal) { 1097 g.drawLine(0, 0, 0, thickness); 1098 g.drawLine(0, 0, length - 1, 0); 1099 1100 // arrows 1101 g.drawLine(w2, sbmin, w2, sbmax); 1102 g.drawLine(w2, sbmax, 1, ctr); 1103 g.drawLine(length-2, ctr, length-w2, sbmax); 1104 1105 } else { 1106 g.drawLine(0, 0, thickness, 0); 1107 g.drawLine(0, 0, 0, length - 1); 1108 1109 // arrows 1110 g.drawLine(sbmin, w2, sbmax, w2); 1111 g.drawLine(sbmax, w2, ctr, 1); 1112 g.drawLine(ctr, length-2, sbmax, length-w2); 1113 } 1114 1115 // thumb 1116 if (v1 > 0) { 1117 if (horizontal) { 1118 g.drawLine(v1 + v2, 2, v1 + v2, thickness-2); 1119 g.drawLine(v1, thickness-2, v1 + v2, thickness-2); 1120 } else { 1121 g.drawLine(2, v1 + v2, thickness-2, v1 + v2); 1122 g.drawLine(thickness-2, v1, thickness-2, v1 + v2); 1123 } 1124 } 1125 g.setColor(c); 1126 } 1127 1128 /** 1129 * The following multibuffering-related methods delegate to our 1130 * associated GraphicsConfig (X11 or GLX) to handle the appropriate 1131 * native windowing system specific actions. 1132 */ 1133 1134 private BufferCapabilities backBufferCaps; 1135 1136 public void createBuffers(int numBuffers, BufferCapabilities caps) 1137 throws AWTException 1138 { 1139 if (buffersLog.isLoggable(PlatformLogger.Level.FINE)) { 1140 buffersLog.fine("createBuffers(" + numBuffers + ", " + caps + ")"); 1141 } 1142 // set the caps first, they're used when creating the bb 1143 backBufferCaps = caps; 1144 backBuffer = graphicsConfig.createBackBuffer(this, numBuffers, caps); 1145 xBackBuffer = graphicsConfig.createBackBufferImage(target, 1146 backBuffer); 1147 } 1148 1149 @Override 1150 public BufferCapabilities getBackBufferCaps() { 1151 return backBufferCaps; 1152 } 1153 1154 public void flip(int x1, int y1, int x2, int y2, 1155 BufferCapabilities.FlipContents flipAction) 1156 { 1157 if (buffersLog.isLoggable(PlatformLogger.Level.FINE)) { 1158 buffersLog.fine("flip(" + flipAction + ")"); 1159 } 1160 if (backBuffer == 0) { 1161 throw new IllegalStateException("Buffers have not been created"); 1162 } 1163 graphicsConfig.flip(this, target, xBackBuffer, 1164 x1, y1, x2, y2, flipAction); 1165 } 1166 1167 public Image getBackBuffer() { 1168 if (buffersLog.isLoggable(PlatformLogger.Level.FINE)) { 1169 buffersLog.fine("getBackBuffer()"); 1170 } 1171 if (backBuffer == 0) { 1172 throw new IllegalStateException("Buffers have not been created"); 1173 } 1174 return xBackBuffer; 1175 } 1176 1177 public void destroyBuffers() { 1178 if (buffersLog.isLoggable(PlatformLogger.Level.FINE)) { 1179 buffersLog.fine("destroyBuffers()"); 1180 } 1181 graphicsConfig.destroyBackBuffer(backBuffer); 1182 backBuffer = 0; 1183 xBackBuffer = null; 1184 } 1185 1186 // End of multi-buffering 1187 1188 public void notifyTextComponentChange(boolean add){ 1189 Container parent = AWTAccessor.getComponentAccessor().getParent(target); 1190 while(!(parent == null || 1191 parent instanceof java.awt.Frame || 1192 parent instanceof java.awt.Dialog)) { 1193 parent = AWTAccessor.getComponentAccessor().getParent(parent); 1194 } 1195 1196 /* FIX ME - FIX ME need to implement InputMethods 1197 if (parent instanceof java.awt.Frame || 1198 parent instanceof java.awt.Dialog) { 1199 if (add) 1200 ((MInputMethodControl)parent.getPeer()).addTextComponent((MComponentPeer)this); 1201 else 1202 ((MInputMethodControl)parent.getPeer()).removeTextComponent((MComponentPeer)this); 1203 } 1204 */ 1205 } 1206 1207 /** 1208 * Returns true if this event is disabled and shouldn't be processed by window 1209 * Currently if target component is disabled the following event will be disabled on window: 1210 * ButtonPress, ButtonRelease, KeyPress, KeyRelease, EnterNotify, LeaveNotify, MotionNotify 1211 */ 1212 protected boolean isEventDisabled(XEvent e) { 1213 if (enableLog.isLoggable(PlatformLogger.Level.FINEST)) { 1214 enableLog.finest("Component is {1}, checking for disabled event {0}", e, (isEnabled()?"enabled":"disable")); 1215 } 1216 if (!isEnabled()) { 1217 switch (e.get_type()) { 1218 case XConstants.ButtonPress: 1219 case XConstants.ButtonRelease: 1220 case XConstants.KeyPress: 1221 case XConstants.KeyRelease: 1222 case XConstants.EnterNotify: 1223 case XConstants.LeaveNotify: 1224 case XConstants.MotionNotify: 1225 if (enableLog.isLoggable(PlatformLogger.Level.FINER)) { 1226 enableLog.finer("Event {0} is disable", e); 1227 } 1228 return true; 1229 } 1230 } 1231 switch(e.get_type()) { 1232 case XConstants.MapNotify: 1233 case XConstants.UnmapNotify: 1234 return true; 1235 } 1236 return super.isEventDisabled(e); 1237 } 1238 1239 Color getPeerBackground() { 1240 return background; 1241 } 1242 1243 Color getPeerForeground() { 1244 return foreground; 1245 } 1246 1247 Font getPeerFont() { 1248 return font; 1249 } 1250 1251 Dimension getPeerSize() { 1252 return new Dimension(width,height); 1253 } 1254 1255 public void setBoundsOperation(int operation) { 1256 synchronized(getStateLock()) { 1257 if (boundsOperation == DEFAULT_OPERATION) { 1258 boundsOperation = operation; 1259 } else if (operation == RESET_OPERATION) { 1260 boundsOperation = DEFAULT_OPERATION; 1261 } 1262 } 1263 } 1264 1265 static String operationToString(int operation) { 1266 switch (operation) { 1267 case SET_LOCATION: 1268 return "SET_LOCATION"; 1269 case SET_SIZE: 1270 return "SET_SIZE"; 1271 case SET_CLIENT_SIZE: 1272 return "SET_CLIENT_SIZE"; 1273 default: 1274 case SET_BOUNDS: 1275 return "SET_BOUNDS"; 1276 } 1277 } 1278 1279 /** 1280 * Lowers this component at the bottom of the above HW peer. If the above parameter 1281 * is null then the method places this component at the top of the Z-order. 1282 */ 1283 public void setZOrder(ComponentPeer above) { 1284 long aboveWindow = (above != null) ? ((XComponentPeer)above).getWindow() : 0; 1285 1286 XToolkit.awtLock(); 1287 try{ 1288 XlibWrapper.SetZOrder(XToolkit.getDisplay(), getWindow(), aboveWindow); 1289 }finally{ 1290 XToolkit.awtUnlock(); 1291 } 1292 } 1293 1294 private void addTree(Collection<Long> order, Set<Long> set, Container cont) { 1295 for (int i = 0; i < cont.getComponentCount(); i++) { 1296 Component comp = cont.getComponent(i); 1297 Object peer = AWTAccessor.getComponentAccessor().getPeer(comp); 1298 if (peer instanceof XComponentPeer) { 1299 Long window = Long.valueOf(((XComponentPeer)peer).getWindow()); 1300 if (!set.contains(window)) { 1301 set.add(window); 1302 order.add(window); 1303 } 1304 } else if (comp instanceof Container) { 1305 // It is lightweight container, it might contain heavyweight components attached to this 1306 // peer 1307 addTree(order, set, (Container)comp); 1308 } 1309 } 1310 } 1311 1312 /****** DropTargetPeer implementation ********************/ 1313 1314 public void addDropTarget(DropTarget dt) { 1315 Component comp = target; 1316 while(!(comp == null || comp instanceof Window)) { 1317 comp = comp.getParent(); 1318 } 1319 1320 if (comp instanceof Window) { 1321 XWindowPeer wpeer = AWTAccessor.getComponentAccessor().getPeer(comp); 1322 if (wpeer != null) { 1323 wpeer.addDropTarget(); 1324 } 1325 } 1326 } 1327 1328 public void removeDropTarget(DropTarget dt) { 1329 Component comp = target; 1330 while(!(comp == null || comp instanceof Window)) { 1331 comp = comp.getParent(); 1332 } 1333 1334 if (comp instanceof Window) { 1335 XWindowPeer wpeer = AWTAccessor.getComponentAccessor() 1336 .getPeer(comp); 1337 if (wpeer != null) { 1338 wpeer.removeDropTarget(); 1339 } 1340 } 1341 } 1342 1343 /** 1344 * Applies the shape to the X-window. 1345 * @since 1.7 1346 */ 1347 public void applyShape(Region shape) { 1348 if (XlibUtil.isShapingSupported()) { 1349 if (shapeLog.isLoggable(PlatformLogger.Level.FINER)) { 1350 shapeLog.finer( 1351 "*** INFO: Setting shape: PEER: " + this 1352 + "; WINDOW: " + getWindow() 1353 + "; TARGET: " + target 1354 + "; SHAPE: " + shape); 1355 } 1356 XToolkit.awtLock(); 1357 try { 1358 if (shape != null) { 1359 1360 int scale = getScale(); 1361 if (scale != 1) { 1362 shape = shape.getScaledRegion(scale, scale); 1363 } 1364 1365 XlibWrapper.SetRectangularShape( 1366 XToolkit.getDisplay(), 1367 getWindow(), 1368 shape.getLoX(), shape.getLoY(), 1369 shape.getHiX(), shape.getHiY(), 1370 (shape.isRectangular() ? null : shape) 1371 ); 1372 } else { 1373 XlibWrapper.SetRectangularShape( 1374 XToolkit.getDisplay(), 1375 getWindow(), 1376 0, 0, 1377 0, 0, 1378 null 1379 ); 1380 } 1381 } finally { 1382 XToolkit.awtUnlock(); 1383 } 1384 } else { 1385 if (shapeLog.isLoggable(PlatformLogger.Level.FINER)) { 1386 shapeLog.finer("*** WARNING: Shaping is NOT supported!"); 1387 } 1388 } 1389 } 1390 1391 public boolean updateGraphicsData(GraphicsConfiguration gc) { 1392 int oldVisual = -1, newVisual = -1; 1393 1394 if (graphicsConfig != null) { 1395 oldVisual = graphicsConfig.getVisual(); 1396 } 1397 if (gc != null && gc instanceof X11GraphicsConfig) { 1398 newVisual = ((X11GraphicsConfig)gc).getVisual(); 1399 } 1400 1401 // If the new visual differs from the old one, the peer must be 1402 // recreated because X11 does not allow changing the visual on the fly. 1403 // So we even skip the initGraphicsConfiguration() call. 1404 // The initial assignment should happen though, hence the != -1 thing. 1405 if (oldVisual != -1 && oldVisual != newVisual) { 1406 return true; 1407 } 1408 1409 initGraphicsConfiguration(); 1410 doValidateSurface(); 1411 return false; 1412 } 1413 }