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