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