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