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