1 /* 2 * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javax.swing; 27 28 import java.awt.Color; 29 import java.awt.Component; 30 import java.awt.Container; 31 import java.awt.Dimension; 32 import java.awt.Graphics; 33 import java.awt.Point; 34 import java.awt.Rectangle; 35 import java.awt.Toolkit; 36 import java.awt.Window; 37 import java.beans.PropertyVetoException; 38 39 import sun.awt.AWTAccessor; 40 import sun.awt.SunToolkit; 41 42 /** This is an implementation of the <code>DesktopManager</code>. 43 * It currently implements the basic behaviors for managing 44 * <code>JInternalFrame</code>s in an arbitrary parent. 45 * <code>JInternalFrame</code>s that are not children of a 46 * <code>JDesktop</code> will use this component 47 * to handle their desktop-like actions. 48 * <p>This class provides a policy for the various JInternalFrame methods, 49 * it is not meant to be called directly rather the various JInternalFrame 50 * methods will call into the DesktopManager.</p> 51 * @see JDesktopPane 52 * @see JInternalFrame 53 * @author David Kloba 54 * @author Steve Wilson 55 * @since 1.2 56 */ 57 @SuppressWarnings("serial") // No Interesting Non-Transient State 58 public class DefaultDesktopManager implements DesktopManager, java.io.Serializable { 59 static final String HAS_BEEN_ICONIFIED_PROPERTY = "wasIconOnce"; 60 61 static final int DEFAULT_DRAG_MODE = 0; 62 static final int OUTLINE_DRAG_MODE = 1; 63 static final int FASTER_DRAG_MODE = 2; 64 65 int dragMode = DEFAULT_DRAG_MODE; 66 67 private transient Rectangle currentBounds = null; 68 private transient Graphics desktopGraphics = null; 69 private transient Rectangle desktopBounds = null; 70 private transient Rectangle[] floatingItems = {}; 71 72 /** 73 * Set to true when the user actually drags a frame vs clicks on it 74 * to start the drag operation. This is only used when dragging with 75 * FASTER_DRAG_MODE. 76 */ 77 private transient boolean didDrag; 78 79 /** Normally this method will not be called. If it is, it 80 * tries to determine the appropriate parent from the desktopIcon of the frame. 81 * Will remove the desktopIcon from its parent if it successfully adds the frame. 82 */ openFrame(JInternalFrame f)83 public void openFrame(JInternalFrame f) { 84 if(f.getDesktopIcon().getParent() != null) { 85 f.getDesktopIcon().getParent().add(f); 86 removeIconFor(f); 87 } 88 } 89 90 /** 91 * Removes the frame, and, if necessary, the 92 * <code>desktopIcon</code>, from its parent. 93 * @param f the <code>JInternalFrame</code> to be removed 94 */ closeFrame(JInternalFrame f)95 public void closeFrame(JInternalFrame f) { 96 JDesktopPane d = f.getDesktopPane(); 97 if (d == null) { 98 return; 99 } 100 boolean findNext = f.isSelected(); 101 Container c = f.getParent(); 102 JInternalFrame nextFrame = null; 103 if (findNext) { 104 nextFrame = d.getNextFrame(f); 105 try { f.setSelected(false); } catch (PropertyVetoException e2) { } 106 } 107 if(c != null) { 108 c.remove(f); // Removes the focus. 109 c.repaint(f.getX(), f.getY(), f.getWidth(), f.getHeight()); 110 } 111 removeIconFor(f); 112 if(f.getNormalBounds() != null) 113 f.setNormalBounds(null); 114 if(wasIcon(f)) 115 setWasIcon(f, null); 116 if (nextFrame != null) { 117 try { nextFrame.setSelected(true); } 118 catch (PropertyVetoException e2) { } 119 } else if (findNext && d.getComponentCount() == 0) { 120 // It was selected and was the last component on the desktop. 121 d.requestFocus(); 122 } 123 } 124 125 /** 126 * Resizes the frame to fill its parents bounds. 127 * @param f the frame to be resized 128 */ maximizeFrame(JInternalFrame f)129 public void maximizeFrame(JInternalFrame f) { 130 if (f.isIcon()) { 131 try { 132 // In turn calls deiconifyFrame in the desktop manager. 133 // That method will handle the maximization of the frame. 134 f.setIcon(false); 135 } catch (PropertyVetoException e2) { 136 } 137 } else { 138 Container c = f.getParent(); 139 if (c == null) { 140 return; 141 } 142 f.setNormalBounds(f.getBounds()); 143 Rectangle desktopBounds = c.getBounds(); 144 setBoundsForFrame(f, 0, 0, 145 desktopBounds.width, desktopBounds.height); 146 } 147 148 // Set the maximized frame as selected. 149 try { 150 f.setSelected(true); 151 } catch (PropertyVetoException e2) { 152 } 153 } 154 155 /** 156 * Restores the frame back to its size and position prior 157 * to a <code>maximizeFrame</code> call. 158 * @param f the <code>JInternalFrame</code> to be restored 159 */ minimizeFrame(JInternalFrame f)160 public void minimizeFrame(JInternalFrame f) { 161 // If the frame was an icon restore it back to an icon. 162 if (f.isIcon()) { 163 iconifyFrame(f); 164 return; 165 } 166 167 if ((f.getNormalBounds()) != null) { 168 Rectangle r = f.getNormalBounds(); 169 f.setNormalBounds(null); 170 try { f.setSelected(true); } catch (PropertyVetoException e2) { } 171 setBoundsForFrame(f, r.x, r.y, r.width, r.height); 172 } 173 } 174 175 /** 176 * Removes the frame from its parent and adds its 177 * <code>desktopIcon</code> to the parent. 178 * @param f the <code>JInternalFrame</code> to be iconified 179 */ iconifyFrame(JInternalFrame f)180 public void iconifyFrame(JInternalFrame f) { 181 JInternalFrame.JDesktopIcon desktopIcon; 182 Container c = f.getParent(); 183 JDesktopPane d = f.getDesktopPane(); 184 boolean findNext = f.isSelected(); 185 desktopIcon = f.getDesktopIcon(); 186 if(!wasIcon(f)) { 187 Rectangle r = getBoundsForIconOf(f); 188 desktopIcon.setBounds(r.x, r.y, r.width, r.height); 189 // we must validate the hierarchy to not break the hw/lw mixing 190 desktopIcon.revalidate(); 191 setWasIcon(f, Boolean.TRUE); 192 } 193 194 if (c == null || d == null) { 195 return; 196 } 197 198 if (c instanceof JLayeredPane) { 199 JLayeredPane lp = (JLayeredPane)c; 200 int layer = JLayeredPane.getLayer(f); 201 JLayeredPane.putLayer(desktopIcon, layer); 202 } 203 d.setComponentOrderCheckingEnabled(true); 204 c.remove(f); 205 c.add(desktopIcon); 206 if (findNext) { 207 if (d.selectFrame(true) == null) { 208 // The icon is the last frame. 209 f.restoreSubcomponentFocus(); 210 } 211 } 212 c.repaint(f.getX(), f.getY(), f.getWidth(), f.getHeight()); 213 } 214 215 /** 216 * Removes the desktopIcon from its parent and adds its frame 217 * to the parent. 218 * @param f the <code>JInternalFrame</code> to be de-iconified 219 */ deiconifyFrame(JInternalFrame f)220 public void deiconifyFrame(JInternalFrame f) { 221 JInternalFrame.JDesktopIcon desktopIcon = f.getDesktopIcon(); 222 Container c = desktopIcon.getParent(); 223 JDesktopPane d = f.getDesktopPane(); 224 if (c != null && d != null) { 225 c.add(f); 226 // If the frame is to be restored to a maximized state make 227 // sure it still fills the whole desktop. 228 if (f.isMaximum()) { 229 Rectangle desktopBounds = c.getBounds(); 230 if (f.getWidth() != desktopBounds.width || 231 f.getHeight() != desktopBounds.height) { 232 setBoundsForFrame(f, 0, 0, 233 desktopBounds.width, desktopBounds.height); 234 } 235 } 236 removeIconFor(f); 237 if (f.isSelected()) { 238 f.moveToFront(); 239 f.restoreSubcomponentFocus(); 240 } 241 else { 242 try { 243 f.setSelected(true); 244 } catch (PropertyVetoException e2) {} 245 246 } 247 } 248 } 249 250 /** This will activate <b>f</b> moving it to the front. It will 251 * set the current active frame's (if any) 252 * <code>IS_SELECTED_PROPERTY</code> to <code>false</code>. 253 * There can be only one active frame across all Layers. 254 * @param f the <code>JInternalFrame</code> to be activated 255 */ activateFrame(JInternalFrame f)256 public void activateFrame(JInternalFrame f) { 257 Container p = f.getParent(); 258 Component[] c; 259 JDesktopPane d = f.getDesktopPane(); 260 JInternalFrame currentlyActiveFrame = 261 (d == null) ? null : d.getSelectedFrame(); 262 // fix for bug: 4162443 263 if(p == null) { 264 // If the frame is not in parent, its icon maybe, check it 265 p = f.getDesktopIcon().getParent(); 266 if(p == null) 267 return; 268 } 269 // we only need to keep track of the currentActive InternalFrame, if any 270 if (currentlyActiveFrame == null){ 271 if (d != null) { d.setSelectedFrame(f);} 272 } else if (currentlyActiveFrame != f) { 273 // if not the same frame as the current active 274 // we deactivate the current 275 if (currentlyActiveFrame.isSelected()) { 276 try { 277 currentlyActiveFrame.setSelected(false); 278 } 279 catch(PropertyVetoException e2) {} 280 } 281 if (d != null) { d.setSelectedFrame(f);} 282 } 283 f.moveToFront(); 284 } 285 286 // implements javax.swing.DesktopManager deactivateFrame(JInternalFrame f)287 public void deactivateFrame(JInternalFrame f) { 288 JDesktopPane d = f.getDesktopPane(); 289 JInternalFrame currentlyActiveFrame = 290 (d == null) ? null : d.getSelectedFrame(); 291 if (currentlyActiveFrame == f) 292 d.setSelectedFrame(null); 293 } 294 295 // implements javax.swing.DesktopManager beginDraggingFrame(JComponent f)296 public void beginDraggingFrame(JComponent f) { 297 setupDragMode(f); 298 299 if (dragMode == FASTER_DRAG_MODE) { 300 Component desktop = f.getParent(); 301 floatingItems = findFloatingItems(f); 302 currentBounds = f.getBounds(); 303 if (desktop instanceof JComponent) { 304 desktopBounds = ((JComponent)desktop).getVisibleRect(); 305 } 306 else { 307 desktopBounds = desktop.getBounds(); 308 desktopBounds.x = desktopBounds.y = 0; 309 } 310 desktopGraphics = JComponent.safelyGetGraphics(desktop); 311 ((JInternalFrame)f).isDragging = true; 312 didDrag = false; 313 } 314 315 } 316 setupDragMode(JComponent f)317 private void setupDragMode(JComponent f) { 318 JDesktopPane p = getDesktopPane(f); 319 Container parent = f.getParent(); 320 dragMode = DEFAULT_DRAG_MODE; 321 if (p != null) { 322 String mode = (String)p.getClientProperty("JDesktopPane.dragMode"); 323 Window window = SwingUtilities.getWindowAncestor(f); 324 if (window != null && !window.isOpaque()) { 325 dragMode = DEFAULT_DRAG_MODE; 326 } else if (mode != null && mode.equals("outline")) { 327 dragMode = OUTLINE_DRAG_MODE; 328 } else if (mode != null && mode.equals("faster") 329 && f instanceof JInternalFrame 330 && ((JInternalFrame)f).isOpaque() && 331 (parent == null || parent.isOpaque())) { 332 dragMode = FASTER_DRAG_MODE; 333 } else { 334 if (p.getDragMode() == JDesktopPane.OUTLINE_DRAG_MODE ) { 335 dragMode = OUTLINE_DRAG_MODE; 336 } else if ( p.getDragMode() == JDesktopPane.LIVE_DRAG_MODE 337 && f instanceof JInternalFrame 338 && ((JInternalFrame)f).isOpaque()) { 339 dragMode = FASTER_DRAG_MODE; 340 } else { 341 dragMode = DEFAULT_DRAG_MODE; 342 } 343 } 344 } 345 } 346 347 private transient Point currentLoc = null; 348 349 /** 350 * Moves the visible location of the frame being dragged 351 * to the location specified. The means by which this occurs can vary depending 352 * on the dragging algorithm being used. The actual logical location of the frame 353 * might not change until <code>endDraggingFrame</code> is called. 354 */ dragFrame(JComponent f, int newX, int newY)355 public void dragFrame(JComponent f, int newX, int newY) { 356 357 if (dragMode == OUTLINE_DRAG_MODE) { 358 JDesktopPane desktopPane = getDesktopPane(f); 359 if (desktopPane != null){ 360 Graphics g = JComponent.safelyGetGraphics(desktopPane); 361 362 g.setXORMode(Color.white); 363 if (currentLoc != null) { 364 g.drawRect(currentLoc.x, currentLoc.y, 365 f.getWidth()-1, f.getHeight()-1); 366 } 367 g.drawRect( newX, newY, f.getWidth()-1, f.getHeight()-1); 368 /* Work around for 6635462: XOR mode may cause a SurfaceLost on first use. 369 * Swing doesn't expect that its XOR drawRect did 370 * not complete, so believes that on re-entering at 371 * the next update location, that there is an XOR rect 372 * to draw out at "currentLoc". But in fact 373 * its now got a new clean surface without that rect, 374 * so drawing it "out" in fact draws it on, leaving garbage. 375 * So only update/set currentLoc if the draw completed. 376 */ 377 sun.java2d.SurfaceData sData = 378 ((sun.java2d.SunGraphics2D)g).getSurfaceData(); 379 380 if (!sData.isSurfaceLost()) { 381 currentLoc = new Point (newX, newY); 382 } 383 ; 384 g.dispose(); 385 } 386 } else if (dragMode == FASTER_DRAG_MODE) { 387 dragFrameFaster(f, newX, newY); 388 } else { 389 setBoundsForFrame(f, newX, newY, f.getWidth(), f.getHeight()); 390 } 391 } 392 393 // implements javax.swing.DesktopManager endDraggingFrame(JComponent f)394 public void endDraggingFrame(JComponent f) { 395 if ( dragMode == OUTLINE_DRAG_MODE && currentLoc != null) { 396 setBoundsForFrame(f, currentLoc.x, currentLoc.y, f.getWidth(), f.getHeight() ); 397 currentLoc = null; 398 } else if (dragMode == FASTER_DRAG_MODE) { 399 currentBounds = null; 400 if (desktopGraphics != null) { 401 desktopGraphics.dispose(); 402 desktopGraphics = null; 403 } 404 desktopBounds = null; 405 ((JInternalFrame)f).isDragging = false; 406 } 407 } 408 409 // implements javax.swing.DesktopManager beginResizingFrame(JComponent f, int direction)410 public void beginResizingFrame(JComponent f, int direction) { 411 setupDragMode(f); 412 } 413 414 /** 415 * Calls <code>setBoundsForFrame</code> with the new values. 416 * @param f the component to be resized 417 * @param newX the new x-coordinate 418 * @param newY the new y-coordinate 419 * @param newWidth the new width 420 * @param newHeight the new height 421 */ resizeFrame(JComponent f, int newX, int newY, int newWidth, int newHeight)422 public void resizeFrame(JComponent f, int newX, int newY, int newWidth, int newHeight) { 423 424 if ( dragMode == DEFAULT_DRAG_MODE || dragMode == FASTER_DRAG_MODE ) { 425 setBoundsForFrame(f, newX, newY, newWidth, newHeight); 426 } else { 427 JDesktopPane desktopPane = getDesktopPane(f); 428 if (desktopPane != null){ 429 Graphics g = JComponent.safelyGetGraphics(desktopPane); 430 431 g.setXORMode(Color.white); 432 if (currentBounds != null) { 433 g.drawRect( currentBounds.x, currentBounds.y, currentBounds.width-1, currentBounds.height-1); 434 } 435 g.drawRect( newX, newY, newWidth-1, newHeight-1); 436 437 // Work around for 6635462, see comment in dragFrame() 438 sun.java2d.SurfaceData sData = 439 ((sun.java2d.SunGraphics2D)g).getSurfaceData(); 440 if (!sData.isSurfaceLost()) { 441 currentBounds = new Rectangle (newX, newY, newWidth, newHeight); 442 } 443 444 g.setPaintMode(); 445 g.dispose(); 446 } 447 } 448 449 } 450 451 // implements javax.swing.DesktopManager endResizingFrame(JComponent f)452 public void endResizingFrame(JComponent f) { 453 if ( dragMode == OUTLINE_DRAG_MODE && currentBounds != null) { 454 setBoundsForFrame(f, currentBounds.x, currentBounds.y, currentBounds.width, currentBounds.height ); 455 currentBounds = null; 456 } 457 } 458 459 460 /** This moves the <code>JComponent</code> and repaints the damaged areas. */ setBoundsForFrame(JComponent f, int newX, int newY, int newWidth, int newHeight)461 public void setBoundsForFrame(JComponent f, int newX, int newY, int newWidth, int newHeight) { 462 f.setBounds(newX, newY, newWidth, newHeight); 463 // we must validate the hierarchy to not break the hw/lw mixing 464 f.revalidate(); 465 } 466 467 /** 468 * Convenience method to remove the desktopIcon of <b>f</b> is necessary. 469 * 470 * @param f the {@code JInternalFrame} for which to remove the 471 * {@code desktopIcon} 472 */ removeIconFor(JInternalFrame f)473 protected void removeIconFor(JInternalFrame f) { 474 JInternalFrame.JDesktopIcon di = f.getDesktopIcon(); 475 Container c = di.getParent(); 476 if(c != null) { 477 c.remove(di); 478 c.repaint(di.getX(), di.getY(), di.getWidth(), di.getHeight()); 479 } 480 } 481 482 /** 483 * The {@code iconifyFrame()} code calls this to determine the proper bounds 484 * for the desktopIcon. 485 * 486 * @param f the {@code JInternalFrame} of interest 487 * @return a {@code Rectangle} containing bounds for the {@code desktopIcon} 488 */ getBoundsForIconOf(JInternalFrame f)489 protected Rectangle getBoundsForIconOf(JInternalFrame f) { 490 // 491 // Get the icon for this internal frame and its preferred size 492 // 493 494 JInternalFrame.JDesktopIcon icon = f.getDesktopIcon(); 495 Dimension prefSize = icon.getPreferredSize(); 496 // 497 // Get the parent bounds and child components. 498 // 499 500 Container c = f.getParent(); 501 if (c == null) { 502 c = f.getDesktopIcon().getParent(); 503 } 504 505 if (c == null) { 506 /* the frame has not yet been added to the parent; how about (0,0) ?*/ 507 return new Rectangle(0, 0, prefSize.width, prefSize.height); 508 } 509 510 Rectangle parentBounds = c.getBounds(); 511 Component [] components = c.getComponents(); 512 513 514 // 515 // Iterate through valid default icon locations and return the 516 // first one that does not intersect any other icons. 517 // 518 519 Rectangle availableRectangle = null; 520 JInternalFrame.JDesktopIcon currentIcon = null; 521 522 int x = 0; 523 int y = parentBounds.height - prefSize.height; 524 int w = prefSize.width; 525 int h = prefSize.height; 526 527 boolean found = false; 528 529 while (!found) { 530 531 availableRectangle = new Rectangle(x,y,w,h); 532 533 found = true; 534 535 for ( int i=0; i<components.length; i++ ) { 536 537 // 538 // Get the icon for this component 539 // 540 541 if ( components[i] instanceof JInternalFrame ) { 542 currentIcon = ((JInternalFrame)components[i]).getDesktopIcon(); 543 } 544 else if ( components[i] instanceof JInternalFrame.JDesktopIcon ){ 545 currentIcon = (JInternalFrame.JDesktopIcon)components[i]; 546 } else 547 /* found a child that's neither an internal frame nor 548 an icon. I don't believe this should happen, but at 549 present it does and causes a null pointer exception. 550 Even when that gets fixed, this code protects against 551 the npe. hania */ 552 continue; 553 554 // 555 // If this icon intersects the current location, get next location. 556 // 557 558 if ( !currentIcon.equals(icon) ) { 559 if ( availableRectangle.intersects(currentIcon.getBounds()) ) { 560 found = false; 561 break; 562 } 563 } 564 } 565 566 if (currentIcon == null) 567 /* didn't find any useful children above. This probably shouldn't 568 happen, but this check protects against an npe if it ever does 569 (and it's happening now) */ 570 return availableRectangle; 571 572 x += currentIcon.getBounds().width; 573 574 if ( x + w > parentBounds.width ) { 575 x = 0; 576 y -= h; 577 } 578 } 579 580 return(availableRectangle); 581 } 582 583 /** 584 * Stores the bounds of the component just before a maximize call. 585 * @param f the component about to be resized 586 * @param r the normal bounds to be saved away 587 */ setPreviousBounds(JInternalFrame f, Rectangle r)588 protected void setPreviousBounds(JInternalFrame f, Rectangle r) { 589 f.setNormalBounds(r); 590 } 591 592 /** 593 * Gets the normal bounds of the component prior to the component 594 * being maximized. 595 * @param f the <code>JInternalFrame</code> of interest 596 * @return the normal bounds of the component 597 */ getPreviousBounds(JInternalFrame f)598 protected Rectangle getPreviousBounds(JInternalFrame f) { 599 return f.getNormalBounds(); 600 } 601 602 /** 603 * Sets that the component has been iconized and the bounds of the 604 * <code>desktopIcon</code> are valid. 605 * 606 * @param f the {@code JInternalFrame} of interest 607 * @param value a {@code Boolean} signifying if component has been iconized 608 */ setWasIcon(JInternalFrame f, Boolean value)609 protected void setWasIcon(JInternalFrame f, Boolean value) { 610 if (value != null) { 611 f.putClientProperty(HAS_BEEN_ICONIFIED_PROPERTY, value); 612 } 613 } 614 615 /** 616 * Returns <code>true</code> if the component has been iconized 617 * and the bounds of the <code>desktopIcon</code> are valid, 618 * otherwise returns <code>false</code>. 619 * 620 * @param f the <code>JInternalFrame</code> of interest 621 * @return <code>true</code> if the component has been iconized; 622 * otherwise returns <code>false</code> 623 */ wasIcon(JInternalFrame f)624 protected boolean wasIcon(JInternalFrame f) { 625 return (f.getClientProperty(HAS_BEEN_ICONIFIED_PROPERTY) == Boolean.TRUE); 626 } 627 628 getDesktopPane( JComponent frame )629 JDesktopPane getDesktopPane( JComponent frame ) { 630 JDesktopPane pane = null; 631 Component c = frame.getParent(); 632 633 // Find the JDesktopPane 634 while ( pane == null ) { 635 if ( c instanceof JDesktopPane ) { 636 pane = (JDesktopPane)c; 637 } 638 else if ( c == null ) { 639 break; 640 } 641 else { 642 c = c.getParent(); 643 } 644 } 645 646 return pane; 647 } 648 649 650 // =========== stuff for faster frame dragging =================== 651 dragFrameFaster(JComponent f, int newX, int newY)652 private void dragFrameFaster(JComponent f, int newX, int newY) { 653 654 Rectangle previousBounds = new Rectangle(currentBounds.x, 655 currentBounds.y, 656 currentBounds.width, 657 currentBounds.height); 658 659 // move the frame 660 currentBounds.x = newX; 661 currentBounds.y = newY; 662 663 if (didDrag) { 664 // Only initiate cleanup if we have actually done a drag. 665 emergencyCleanup(f); 666 } 667 else { 668 didDrag = true; 669 // We reset the danger field as until now we haven't actually 670 // moved the internal frame so we don't need to initiate repaint. 671 ((JInternalFrame)f).danger = false; 672 } 673 674 boolean floaterCollision = isFloaterCollision(previousBounds, currentBounds); 675 676 JComponent parent = (JComponent)f.getParent(); 677 Rectangle visBounds = previousBounds.intersection(desktopBounds); 678 679 RepaintManager currentManager = RepaintManager.currentManager(f); 680 681 currentManager.beginPaint(); 682 try { 683 if(!floaterCollision) { 684 currentManager.copyArea(parent, desktopGraphics, visBounds.x, 685 visBounds.y, 686 visBounds.width, 687 visBounds.height, 688 newX - previousBounds.x, 689 newY - previousBounds.y, 690 true); 691 } 692 693 f.setBounds(currentBounds); 694 695 if (!floaterCollision) { 696 Rectangle r = currentBounds; 697 currentManager.notifyRepaintPerformed(parent, r.x, r.y, r.width, r.height); 698 } 699 700 if(floaterCollision) { 701 // since we couldn't blit we just redraw as fast as possible 702 // the isDragging mucking is to avoid activating emergency 703 // cleanup 704 ((JInternalFrame)f).isDragging = false; 705 parent.paintImmediately(currentBounds); 706 ((JInternalFrame)f).isDragging = true; 707 } 708 709 // fake out the repaint manager. We'll take care of everything 710 711 currentManager.markCompletelyClean(parent); 712 currentManager.markCompletelyClean(f); 713 714 // compute the minimal newly exposed area 715 // if the rects intersect then we use computeDifference. Otherwise 716 // we'll repaint the entire previous bounds 717 Rectangle[] dirtyRects = null; 718 if ( previousBounds.intersects(currentBounds) ) { 719 dirtyRects = SwingUtilities.computeDifference(previousBounds, 720 currentBounds); 721 } else { 722 dirtyRects = new Rectangle[1]; 723 dirtyRects[0] = previousBounds; 724 }; 725 726 // Fix the damage 727 for (int i = 0; i < dirtyRects.length; i++) { 728 parent.paintImmediately(dirtyRects[i]); 729 Rectangle r = dirtyRects[i]; 730 currentManager.notifyRepaintPerformed(parent, r.x, r.y, r.width, r.height); 731 } 732 733 // new areas of blit were exposed 734 if ( !(visBounds.equals(previousBounds)) ) { 735 dirtyRects = SwingUtilities.computeDifference(previousBounds, 736 desktopBounds); 737 for (int i = 0; i < dirtyRects.length; i++) { 738 dirtyRects[i].x += newX - previousBounds.x; 739 dirtyRects[i].y += newY - previousBounds.y; 740 ((JInternalFrame)f).isDragging = false; 741 parent.paintImmediately(dirtyRects[i]); 742 ((JInternalFrame)f).isDragging = true; 743 Rectangle r = dirtyRects[i]; 744 currentManager.notifyRepaintPerformed(parent, r.x, r.y, r.width, r.height); 745 } 746 747 } 748 } finally { 749 currentManager.endPaint(); 750 } 751 752 // update window if it's non-opaque 753 Window topLevel = SwingUtilities.getWindowAncestor(f); 754 Toolkit tk = Toolkit.getDefaultToolkit(); 755 if (!topLevel.isOpaque() && 756 (tk instanceof SunToolkit) && 757 ((SunToolkit)tk).needUpdateWindow()) 758 { 759 AWTAccessor.getWindowAccessor().updateWindow(topLevel); 760 } 761 } 762 isFloaterCollision(Rectangle moveFrom, Rectangle moveTo)763 private boolean isFloaterCollision(Rectangle moveFrom, Rectangle moveTo) { 764 if (floatingItems.length == 0) { 765 // System.out.println("no floaters"); 766 return false; 767 } 768 769 for (int i = 0; i < floatingItems.length; i++) { 770 boolean intersectsFrom = moveFrom.intersects(floatingItems[i]); 771 if (intersectsFrom) { 772 return true; 773 } 774 boolean intersectsTo = moveTo.intersects(floatingItems[i]); 775 if (intersectsTo) { 776 return true; 777 } 778 } 779 780 return false; 781 } 782 findFloatingItems(JComponent f)783 private Rectangle[] findFloatingItems(JComponent f) { 784 Container desktop = f.getParent(); 785 Component[] children = desktop.getComponents(); 786 int i = 0; 787 for (i = 0; i < children.length; i++) { 788 if (children[i] == f) { 789 break; 790 } 791 } 792 // System.out.println(i); 793 Rectangle[] floaters = new Rectangle[i]; 794 for (i = 0; i < floaters.length; i++) { 795 floaters[i] = children[i].getBounds(); 796 } 797 798 return floaters; 799 } 800 801 /** 802 * This method is here to clean up problems associated 803 * with a race condition which can occur when the full contents 804 * of a copyArea's source argument is not available onscreen. 805 * This uses brute force to clean up in case of possible damage 806 */ emergencyCleanup(final JComponent f)807 private void emergencyCleanup(final JComponent f) { 808 809 if ( ((JInternalFrame)f).danger ) { 810 811 SwingUtilities.invokeLater( new Runnable(){ 812 public void run(){ 813 814 ((JInternalFrame)f).isDragging = false; 815 f.paintImmediately(0,0, 816 f.getWidth(), 817 f.getHeight()); 818 819 //finalFrame.repaint(); 820 ((JInternalFrame)f).isDragging = true; 821 // System.out.println("repair complete"); 822 }}); 823 824 ((JInternalFrame)f).danger = false; 825 } 826 827 } 828 829 830 } 831