Path: blob/master/src/java.desktop/share/classes/javax/swing/DefaultDesktopManager.java
41153 views
/*1* Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package javax.swing;2627import java.awt.Color;28import java.awt.Component;29import java.awt.Container;30import java.awt.Dimension;31import java.awt.Graphics;32import java.awt.Point;33import java.awt.Rectangle;34import java.awt.Toolkit;35import java.awt.Window;36import java.beans.PropertyVetoException;3738import sun.awt.AWTAccessor;39import sun.awt.SunToolkit;4041/** This is an implementation of the <code>DesktopManager</code>.42* It currently implements the basic behaviors for managing43* <code>JInternalFrame</code>s in an arbitrary parent.44* <code>JInternalFrame</code>s that are not children of a45* <code>JDesktop</code> will use this component46* to handle their desktop-like actions.47* <p>This class provides a policy for the various JInternalFrame methods,48* it is not meant to be called directly rather the various JInternalFrame49* methods will call into the DesktopManager.</p>50* @see JDesktopPane51* @see JInternalFrame52* @author David Kloba53* @author Steve Wilson54* @since 1.255*/56@SuppressWarnings("serial") // No Interesting Non-Transient State57public class DefaultDesktopManager implements DesktopManager, java.io.Serializable {58static final String HAS_BEEN_ICONIFIED_PROPERTY = "wasIconOnce";5960static final int DEFAULT_DRAG_MODE = 0;61static final int OUTLINE_DRAG_MODE = 1;62static final int FASTER_DRAG_MODE = 2;6364int dragMode = DEFAULT_DRAG_MODE;6566private transient Rectangle currentBounds = null;67private transient Graphics desktopGraphics = null;68private transient Rectangle desktopBounds = null;69private transient Rectangle[] floatingItems = {};7071/**72* Set to true when the user actually drags a frame vs clicks on it73* to start the drag operation. This is only used when dragging with74* FASTER_DRAG_MODE.75*/76private transient boolean didDrag;7778/**79* Constructs a {@code DefaultDesktopManager}.80*/81public DefaultDesktopManager() {}8283/** Normally this method will not be called. If it is, it84* tries to determine the appropriate parent from the desktopIcon of the frame.85* Will remove the desktopIcon from its parent if it successfully adds the frame.86*/87public void openFrame(JInternalFrame f) {88if(f.getDesktopIcon().getParent() != null) {89f.getDesktopIcon().getParent().add(f);90removeIconFor(f);91}92}9394/**95* Removes the frame, and, if necessary, the96* <code>desktopIcon</code>, from its parent.97* @param f the <code>JInternalFrame</code> to be removed98*/99public void closeFrame(JInternalFrame f) {100JDesktopPane d = f.getDesktopPane();101if (d == null) {102return;103}104boolean findNext = f.isSelected();105Container c = f.getParent();106JInternalFrame nextFrame = null;107if (findNext) {108nextFrame = d.getNextFrame(f);109try { f.setSelected(false); } catch (PropertyVetoException e2) { }110}111if(c != null) {112c.remove(f); // Removes the focus.113c.repaint(f.getX(), f.getY(), f.getWidth(), f.getHeight());114}115removeIconFor(f);116if(f.getNormalBounds() != null)117f.setNormalBounds(null);118if(wasIcon(f))119setWasIcon(f, null);120if (nextFrame != null) {121try { nextFrame.setSelected(true); }122catch (PropertyVetoException e2) { }123} else if (findNext && d.getComponentCount() == 0) {124// It was selected and was the last component on the desktop.125d.requestFocus();126}127}128129/**130* Resizes the frame to fill its parents bounds.131* @param f the frame to be resized132*/133public void maximizeFrame(JInternalFrame f) {134if (f.isIcon()) {135try {136// In turn calls deiconifyFrame in the desktop manager.137// That method will handle the maximization of the frame.138f.setIcon(false);139} catch (PropertyVetoException e2) {140}141} else {142Container c = f.getParent();143if (c == null) {144return;145}146f.setNormalBounds(f.getBounds());147Rectangle desktopBounds = c.getBounds();148setBoundsForFrame(f, 0, 0,149desktopBounds.width, desktopBounds.height);150}151152// Set the maximized frame as selected.153try {154f.setSelected(true);155} catch (PropertyVetoException e2) {156}157}158159/**160* Restores the frame back to its size and position prior161* to a <code>maximizeFrame</code> call.162* @param f the <code>JInternalFrame</code> to be restored163*/164public void minimizeFrame(JInternalFrame f) {165// If the frame was an icon restore it back to an icon.166if (f.isIcon()) {167iconifyFrame(f);168return;169}170171if ((f.getNormalBounds()) != null) {172Rectangle r = f.getNormalBounds();173f.setNormalBounds(null);174try { f.setSelected(true); } catch (PropertyVetoException e2) { }175setBoundsForFrame(f, r.x, r.y, r.width, r.height);176}177}178179/**180* Removes the frame from its parent and adds its181* <code>desktopIcon</code> to the parent.182* @param f the <code>JInternalFrame</code> to be iconified183*/184public void iconifyFrame(JInternalFrame f) {185JInternalFrame.JDesktopIcon desktopIcon;186Container c = f.getParent();187JDesktopPane d = f.getDesktopPane();188boolean findNext = f.isSelected();189desktopIcon = f.getDesktopIcon();190if(!wasIcon(f)) {191Rectangle r = getBoundsForIconOf(f);192desktopIcon.setBounds(r.x, r.y, r.width, r.height);193// we must validate the hierarchy to not break the hw/lw mixing194desktopIcon.revalidate();195setWasIcon(f, Boolean.TRUE);196}197198if (c == null || d == null) {199return;200}201202if (c instanceof JLayeredPane) {203JLayeredPane lp = (JLayeredPane)c;204int layer = JLayeredPane.getLayer(f);205JLayeredPane.putLayer(desktopIcon, layer);206}207d.setComponentOrderCheckingEnabled(true);208c.remove(f);209c.add(desktopIcon);210if (findNext) {211if (d.selectFrame(true) == null) {212// The icon is the last frame.213f.restoreSubcomponentFocus();214}215}216c.repaint(f.getX(), f.getY(), f.getWidth(), f.getHeight());217}218219/**220* Removes the desktopIcon from its parent and adds its frame221* to the parent.222* @param f the <code>JInternalFrame</code> to be de-iconified223*/224public void deiconifyFrame(JInternalFrame f) {225JInternalFrame.JDesktopIcon desktopIcon = f.getDesktopIcon();226Container c = desktopIcon.getParent();227JDesktopPane d = f.getDesktopPane();228if (c != null && d != null) {229c.add(f);230// If the frame is to be restored to a maximized state make231// sure it still fills the whole desktop.232if (f.isMaximum()) {233Rectangle desktopBounds = c.getBounds();234if (f.getWidth() != desktopBounds.width ||235f.getHeight() != desktopBounds.height) {236setBoundsForFrame(f, 0, 0,237desktopBounds.width, desktopBounds.height);238}239}240removeIconFor(f);241if (f.isSelected()) {242f.moveToFront();243f.restoreSubcomponentFocus();244}245else {246try {247f.setSelected(true);248} catch (PropertyVetoException e2) {}249250}251}252}253254/** This will activate <b>f</b> moving it to the front. It will255* set the current active frame's (if any)256* <code>IS_SELECTED_PROPERTY</code> to <code>false</code>.257* There can be only one active frame across all Layers.258* @param f the <code>JInternalFrame</code> to be activated259*/260public void activateFrame(JInternalFrame f) {261Container p = f.getParent();262Component[] c;263JDesktopPane d = f.getDesktopPane();264JInternalFrame currentlyActiveFrame =265(d == null) ? null : d.getSelectedFrame();266// fix for bug: 4162443267if(p == null) {268// If the frame is not in parent, its icon maybe, check it269p = f.getDesktopIcon().getParent();270if(p == null)271return;272}273// we only need to keep track of the currentActive InternalFrame, if any274if (currentlyActiveFrame == null){275if (d != null) { d.setSelectedFrame(f);}276} else if (currentlyActiveFrame != f) {277// if not the same frame as the current active278// we deactivate the current279if (currentlyActiveFrame.isSelected()) {280try {281currentlyActiveFrame.setSelected(false);282}283catch(PropertyVetoException e2) {}284}285if (d != null) { d.setSelectedFrame(f);}286}287f.moveToFront();288}289290// implements javax.swing.DesktopManager291public void deactivateFrame(JInternalFrame f) {292JDesktopPane d = f.getDesktopPane();293JInternalFrame currentlyActiveFrame =294(d == null) ? null : d.getSelectedFrame();295if (currentlyActiveFrame == f)296d.setSelectedFrame(null);297}298299// implements javax.swing.DesktopManager300public void beginDraggingFrame(JComponent f) {301setupDragMode(f);302303if (dragMode == FASTER_DRAG_MODE) {304Component desktop = f.getParent();305floatingItems = findFloatingItems(f);306currentBounds = f.getBounds();307if (desktop instanceof JComponent) {308desktopBounds = ((JComponent)desktop).getVisibleRect();309}310else {311desktopBounds = desktop.getBounds();312desktopBounds.x = desktopBounds.y = 0;313}314desktopGraphics = JComponent.safelyGetGraphics(desktop);315((JInternalFrame)f).isDragging = true;316didDrag = false;317}318319}320321private void setupDragMode(JComponent f) {322JDesktopPane p = getDesktopPane(f);323Container parent = f.getParent();324dragMode = DEFAULT_DRAG_MODE;325if (p != null) {326String mode = (String)p.getClientProperty("JDesktopPane.dragMode");327Window window = SwingUtilities.getWindowAncestor(f);328if (window != null && !window.isOpaque()) {329dragMode = DEFAULT_DRAG_MODE;330} else if (mode != null && mode.equals("outline")) {331dragMode = OUTLINE_DRAG_MODE;332} else if (mode != null && mode.equals("faster")333&& f instanceof JInternalFrame334&& ((JInternalFrame)f).isOpaque() &&335(parent == null || parent.isOpaque())) {336dragMode = FASTER_DRAG_MODE;337} else {338if (p.getDragMode() == JDesktopPane.OUTLINE_DRAG_MODE ) {339dragMode = OUTLINE_DRAG_MODE;340} else if ( p.getDragMode() == JDesktopPane.LIVE_DRAG_MODE341&& f instanceof JInternalFrame342&& ((JInternalFrame)f).isOpaque()) {343dragMode = FASTER_DRAG_MODE;344} else {345dragMode = DEFAULT_DRAG_MODE;346}347}348}349}350351private transient Point currentLoc = null;352353/**354* Moves the visible location of the frame being dragged355* to the location specified. The means by which this occurs can vary depending356* on the dragging algorithm being used. The actual logical location of the frame357* might not change until <code>endDraggingFrame</code> is called.358*/359public void dragFrame(JComponent f, int newX, int newY) {360361if (dragMode == OUTLINE_DRAG_MODE) {362JDesktopPane desktopPane = getDesktopPane(f);363if (desktopPane != null){364Graphics g = JComponent.safelyGetGraphics(desktopPane);365366g.setXORMode(Color.white);367if (currentLoc != null) {368g.drawRect(currentLoc.x, currentLoc.y,369f.getWidth()-1, f.getHeight()-1);370}371g.drawRect( newX, newY, f.getWidth()-1, f.getHeight()-1);372/* Work around for 6635462: XOR mode may cause a SurfaceLost on first use.373* Swing doesn't expect that its XOR drawRect did374* not complete, so believes that on re-entering at375* the next update location, that there is an XOR rect376* to draw out at "currentLoc". But in fact377* its now got a new clean surface without that rect,378* so drawing it "out" in fact draws it on, leaving garbage.379* So only update/set currentLoc if the draw completed.380*/381sun.java2d.SurfaceData sData =382((sun.java2d.SunGraphics2D)g).getSurfaceData();383384if (!sData.isSurfaceLost()) {385currentLoc = new Point (newX, newY);386}387;388g.dispose();389}390} else if (dragMode == FASTER_DRAG_MODE) {391dragFrameFaster(f, newX, newY);392} else {393setBoundsForFrame(f, newX, newY, f.getWidth(), f.getHeight());394}395}396397// implements javax.swing.DesktopManager398public void endDraggingFrame(JComponent f) {399if ( dragMode == OUTLINE_DRAG_MODE && currentLoc != null) {400setBoundsForFrame(f, currentLoc.x, currentLoc.y, f.getWidth(), f.getHeight() );401currentLoc = null;402} else if (dragMode == FASTER_DRAG_MODE) {403currentBounds = null;404if (desktopGraphics != null) {405desktopGraphics.dispose();406desktopGraphics = null;407}408desktopBounds = null;409((JInternalFrame)f).isDragging = false;410}411}412413// implements javax.swing.DesktopManager414public void beginResizingFrame(JComponent f, int direction) {415setupDragMode(f);416}417418/**419* Calls <code>setBoundsForFrame</code> with the new values.420* @param f the component to be resized421* @param newX the new x-coordinate422* @param newY the new y-coordinate423* @param newWidth the new width424* @param newHeight the new height425*/426public void resizeFrame(JComponent f, int newX, int newY, int newWidth, int newHeight) {427428if ( dragMode == DEFAULT_DRAG_MODE || dragMode == FASTER_DRAG_MODE ) {429setBoundsForFrame(f, newX, newY, newWidth, newHeight);430} else {431JDesktopPane desktopPane = getDesktopPane(f);432if (desktopPane != null){433Graphics g = JComponent.safelyGetGraphics(desktopPane);434435g.setXORMode(Color.white);436if (currentBounds != null) {437g.drawRect( currentBounds.x, currentBounds.y, currentBounds.width-1, currentBounds.height-1);438}439g.drawRect( newX, newY, newWidth-1, newHeight-1);440441// Work around for 6635462, see comment in dragFrame()442sun.java2d.SurfaceData sData =443((sun.java2d.SunGraphics2D)g).getSurfaceData();444if (!sData.isSurfaceLost()) {445currentBounds = new Rectangle (newX, newY, newWidth, newHeight);446}447448g.setPaintMode();449g.dispose();450}451}452453}454455// implements javax.swing.DesktopManager456public void endResizingFrame(JComponent f) {457if ( dragMode == OUTLINE_DRAG_MODE && currentBounds != null) {458setBoundsForFrame(f, currentBounds.x, currentBounds.y, currentBounds.width, currentBounds.height );459currentBounds = null;460}461}462463464/** This moves the <code>JComponent</code> and repaints the damaged areas. */465public void setBoundsForFrame(JComponent f, int newX, int newY, int newWidth, int newHeight) {466f.setBounds(newX, newY, newWidth, newHeight);467// we must validate the hierarchy to not break the hw/lw mixing468f.revalidate();469}470471/**472* Convenience method to remove the desktopIcon of <b>f</b> is necessary.473*474* @param f the {@code JInternalFrame} for which to remove the475* {@code desktopIcon}476*/477protected void removeIconFor(JInternalFrame f) {478JInternalFrame.JDesktopIcon di = f.getDesktopIcon();479Container c = di.getParent();480if(c != null) {481c.remove(di);482c.repaint(di.getX(), di.getY(), di.getWidth(), di.getHeight());483}484}485486/**487* The {@code iconifyFrame()} code calls this to determine the proper bounds488* for the desktopIcon.489*490* @param f the {@code JInternalFrame} of interest491* @return a {@code Rectangle} containing bounds for the {@code desktopIcon}492*/493protected Rectangle getBoundsForIconOf(JInternalFrame f) {494//495// Get the icon for this internal frame and its preferred size496//497498JInternalFrame.JDesktopIcon icon = f.getDesktopIcon();499Dimension prefSize = icon.getPreferredSize();500//501// Get the parent bounds and child components.502//503504Container c = f.getParent();505if (c == null) {506c = f.getDesktopIcon().getParent();507}508509if (c == null) {510/* the frame has not yet been added to the parent; how about (0,0) ?*/511return new Rectangle(0, 0, prefSize.width, prefSize.height);512}513514Rectangle parentBounds = c.getBounds();515Component [] components = c.getComponents();516517518//519// Iterate through valid default icon locations and return the520// first one that does not intersect any other icons.521//522523Rectangle availableRectangle = null;524JInternalFrame.JDesktopIcon currentIcon = null;525526int x = 0;527int y = parentBounds.height - prefSize.height;528int w = prefSize.width;529int h = prefSize.height;530531boolean found = false;532533while (!found) {534535availableRectangle = new Rectangle(x,y,w,h);536537found = true;538539for ( int i=0; i<components.length; i++ ) {540541//542// Get the icon for this component543//544545if ( components[i] instanceof JInternalFrame ) {546currentIcon = ((JInternalFrame)components[i]).getDesktopIcon();547}548else if ( components[i] instanceof JInternalFrame.JDesktopIcon ){549currentIcon = (JInternalFrame.JDesktopIcon)components[i];550} else551/* found a child that's neither an internal frame nor552an icon. I don't believe this should happen, but at553present it does and causes a null pointer exception.554Even when that gets fixed, this code protects against555the npe. hania */556continue;557558//559// If this icon intersects the current location, get next location.560//561562if ( !currentIcon.equals(icon) ) {563if ( availableRectangle.intersects(currentIcon.getBounds()) ) {564found = false;565break;566}567}568}569570if (currentIcon == null)571/* didn't find any useful children above. This probably shouldn't572happen, but this check protects against an npe if it ever does573(and it's happening now) */574return availableRectangle;575576x += currentIcon.getBounds().width;577578if ( x + w > parentBounds.width ) {579x = 0;580y -= h;581}582}583584return(availableRectangle);585}586587/**588* Stores the bounds of the component just before a maximize call.589* @param f the component about to be resized590* @param r the normal bounds to be saved away591*/592protected void setPreviousBounds(JInternalFrame f, Rectangle r) {593f.setNormalBounds(r);594}595596/**597* Gets the normal bounds of the component prior to the component598* being maximized.599* @param f the <code>JInternalFrame</code> of interest600* @return the normal bounds of the component601*/602protected Rectangle getPreviousBounds(JInternalFrame f) {603return f.getNormalBounds();604}605606/**607* Sets that the component has been iconized and the bounds of the608* <code>desktopIcon</code> are valid.609*610* @param f the {@code JInternalFrame} of interest611* @param value a {@code Boolean} signifying if component has been iconized612*/613protected void setWasIcon(JInternalFrame f, Boolean value) {614if (value != null) {615f.putClientProperty(HAS_BEEN_ICONIFIED_PROPERTY, value);616}617}618619/**620* Returns <code>true</code> if the component has been iconized621* and the bounds of the <code>desktopIcon</code> are valid,622* otherwise returns <code>false</code>.623*624* @param f the <code>JInternalFrame</code> of interest625* @return <code>true</code> if the component has been iconized;626* otherwise returns <code>false</code>627*/628protected boolean wasIcon(JInternalFrame f) {629return (f.getClientProperty(HAS_BEEN_ICONIFIED_PROPERTY) == Boolean.TRUE);630}631632633JDesktopPane getDesktopPane( JComponent frame ) {634JDesktopPane pane = null;635Component c = frame.getParent();636637// Find the JDesktopPane638while ( pane == null ) {639if ( c instanceof JDesktopPane ) {640pane = (JDesktopPane)c;641}642else if ( c == null ) {643break;644}645else {646c = c.getParent();647}648}649650return pane;651}652653654// =========== stuff for faster frame dragging ===================655656private void dragFrameFaster(JComponent f, int newX, int newY) {657658Rectangle previousBounds = new Rectangle(currentBounds.x,659currentBounds.y,660currentBounds.width,661currentBounds.height);662663// move the frame664currentBounds.x = newX;665currentBounds.y = newY;666667if (didDrag) {668// Only initiate cleanup if we have actually done a drag.669emergencyCleanup(f);670}671else {672didDrag = true;673// We reset the danger field as until now we haven't actually674// moved the internal frame so we don't need to initiate repaint.675((JInternalFrame)f).danger = false;676}677678boolean floaterCollision = isFloaterCollision(previousBounds, currentBounds);679680JComponent parent = (JComponent)f.getParent();681Rectangle visBounds = previousBounds.intersection(desktopBounds);682683RepaintManager currentManager = RepaintManager.currentManager(f);684685currentManager.beginPaint();686try {687if(!floaterCollision) {688currentManager.copyArea(parent, desktopGraphics, visBounds.x,689visBounds.y,690visBounds.width,691visBounds.height,692newX - previousBounds.x,693newY - previousBounds.y,694true);695}696697f.setBounds(currentBounds);698699if (!floaterCollision) {700Rectangle r = currentBounds;701currentManager.notifyRepaintPerformed(parent, r.x, r.y, r.width, r.height);702}703704if(floaterCollision) {705// since we couldn't blit we just redraw as fast as possible706// the isDragging mucking is to avoid activating emergency707// cleanup708((JInternalFrame)f).isDragging = false;709parent.paintImmediately(currentBounds);710((JInternalFrame)f).isDragging = true;711}712713// fake out the repaint manager. We'll take care of everything714715currentManager.markCompletelyClean(parent);716currentManager.markCompletelyClean(f);717718// compute the minimal newly exposed area719// if the rects intersect then we use computeDifference. Otherwise720// we'll repaint the entire previous bounds721Rectangle[] dirtyRects = null;722if ( previousBounds.intersects(currentBounds) ) {723dirtyRects = SwingUtilities.computeDifference(previousBounds,724currentBounds);725} else {726dirtyRects = new Rectangle[1];727dirtyRects[0] = previousBounds;728};729730// Fix the damage731for (int i = 0; i < dirtyRects.length; i++) {732parent.paintImmediately(dirtyRects[i]);733Rectangle r = dirtyRects[i];734currentManager.notifyRepaintPerformed(parent, r.x, r.y, r.width, r.height);735}736737// new areas of blit were exposed738if ( !(visBounds.equals(previousBounds)) ) {739dirtyRects = SwingUtilities.computeDifference(previousBounds,740desktopBounds);741for (int i = 0; i < dirtyRects.length; i++) {742dirtyRects[i].x += newX - previousBounds.x;743dirtyRects[i].y += newY - previousBounds.y;744((JInternalFrame)f).isDragging = false;745parent.paintImmediately(dirtyRects[i]);746((JInternalFrame)f).isDragging = true;747Rectangle r = dirtyRects[i];748currentManager.notifyRepaintPerformed(parent, r.x, r.y, r.width, r.height);749}750751}752} finally {753currentManager.endPaint();754}755756// update window if it's non-opaque757Window topLevel = SwingUtilities.getWindowAncestor(f);758Toolkit tk = Toolkit.getDefaultToolkit();759if (!topLevel.isOpaque() &&760(tk instanceof SunToolkit) &&761((SunToolkit)tk).needUpdateWindow())762{763AWTAccessor.getWindowAccessor().updateWindow(topLevel);764}765}766767private boolean isFloaterCollision(Rectangle moveFrom, Rectangle moveTo) {768if (floatingItems.length == 0) {769// System.out.println("no floaters");770return false;771}772773for (int i = 0; i < floatingItems.length; i++) {774boolean intersectsFrom = moveFrom.intersects(floatingItems[i]);775if (intersectsFrom) {776return true;777}778boolean intersectsTo = moveTo.intersects(floatingItems[i]);779if (intersectsTo) {780return true;781}782}783784return false;785}786787private Rectangle[] findFloatingItems(JComponent f) {788Container desktop = f.getParent();789Component[] children = desktop.getComponents();790int i = 0;791for (i = 0; i < children.length; i++) {792if (children[i] == f) {793break;794}795}796// System.out.println(i);797Rectangle[] floaters = new Rectangle[i];798for (i = 0; i < floaters.length; i++) {799floaters[i] = children[i].getBounds();800}801802return floaters;803}804805/**806* This method is here to clean up problems associated807* with a race condition which can occur when the full contents808* of a copyArea's source argument is not available onscreen.809* This uses brute force to clean up in case of possible damage810*/811private void emergencyCleanup(final JComponent f) {812813if ( ((JInternalFrame)f).danger ) {814815SwingUtilities.invokeLater( new Runnable(){816public void run(){817818((JInternalFrame)f).isDragging = false;819f.paintImmediately(0,0,820f.getWidth(),821f.getHeight());822823//finalFrame.repaint();824((JInternalFrame)f).isDragging = true;825// System.out.println("repair complete");826}});827828((JInternalFrame)f).danger = false;829}830831}832833834}835836837