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