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