In theory this should work (modulo some particularly fiddly bits that I'm going
to have to think about), but it's totally untested. That comes next! git-svn-id: svn+ssh://src.earth.threerings.net/nenya/trunk@115 ed5b42cb-e716-0410-a449-f6a68f950b19
This commit is contained in:
@@ -47,18 +47,17 @@ import com.samskivert.util.RunAnywhere;
|
|||||||
import com.samskivert.util.StringUtil;
|
import com.samskivert.util.StringUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to get Swing's repainting to jive with our active rendering
|
* Used to get Swing's repainting to jive with our active rendering strategy.
|
||||||
* strategy.
|
|
||||||
*
|
*
|
||||||
* @see FrameManager
|
* @see FrameManager
|
||||||
*/
|
*/
|
||||||
public class ActiveRepaintManager extends RepaintManager
|
public class ActiveRepaintManager extends RepaintManager
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Components that are rooted in this component (which must be a {@link
|
* Components that are rooted in this component (which must be a {@link Window} or an {@link
|
||||||
* Window} or an {@link Applet}) will be rendered into the offscreen buffer
|
* Applet}) will be rendered into the offscreen buffer managed by the frame manager. Other
|
||||||
* managed by the frame manager. Other components will be rendered into
|
* components will be rendered into separate offscreen buffers and repainted in the normal
|
||||||
* separate offscreen buffers and repainted in the normal Swing manner.
|
* Swing manner.
|
||||||
*/
|
*/
|
||||||
public ActiveRepaintManager (Component root)
|
public ActiveRepaintManager (Component root)
|
||||||
{
|
{
|
||||||
@@ -75,9 +74,8 @@ public class ActiveRepaintManager extends RepaintManager
|
|||||||
|
|
||||||
// locate the validation root for this component
|
// locate the validation root for this component
|
||||||
for (Component c = comp; c != null; c = c.getParent()) {
|
for (Component c = comp; c != null; c = c.getParent()) {
|
||||||
// if the component is not part of an active widget hierarcy,
|
// if the component is not part of an active widget hierarcy, we can stop now; if the
|
||||||
// we can stop now; if the component is a cell render pane,
|
// component is a cell render pane, we're apparently supposed to ignore it as wel
|
||||||
// we're apparently supposed to ignore it as wel
|
|
||||||
if (!c.isDisplayable() || c instanceof CellRendererPane) {
|
if (!c.isDisplayable() || c instanceof CellRendererPane) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -87,26 +85,23 @@ public class ActiveRepaintManager extends RepaintManager
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we find our validate root, we can stop looking; NOTE:
|
// if we find our validate root, we can stop looking; NOTE: JTextField incorrectly
|
||||||
// JTextField incorrectly claims to be a validate root thereby
|
// claims to be a validate root thereby fucking up the program something serious; we
|
||||||
// fucking up the program something serious; we jovially
|
// jovially ignore it's claims here and restore order to the universe; see bug #403550
|
||||||
// ignore it's claims here and restore order to the universe;
|
// for more fallout from Sun's fuckup
|
||||||
// see bug #403550 for more fallout from Sun's fuckup
|
if (!(c instanceof JTextField) && !(c instanceof JScrollPane) &&
|
||||||
if (!(c instanceof JTextField) &&
|
|
||||||
!(c instanceof JScrollPane) &&
|
|
||||||
((JComponent)c).isValidateRoot()) {
|
((JComponent)c).isValidateRoot()) {
|
||||||
vroot = c;
|
vroot = c;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we found no validation root we can abort as this component
|
// if we found no validation root we can abort as this component is not part of any valid
|
||||||
// is not part of any valid widget hierarchy
|
// widget hierarchy
|
||||||
if (vroot == null) {
|
if (vroot == null) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.info("Skipping vrootless component: " + toString(comp));
|
Log.info("Skipping vrootless component: " + toString(comp));
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,34 +109,29 @@ public class ActiveRepaintManager extends RepaintManager
|
|||||||
// that is showing
|
// that is showing
|
||||||
if (getRoot(vroot) == null) {
|
if (getRoot(vroot) == null) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.info("Skipping rootless component " +
|
Log.info("Skipping rootless component [comp=" + toString(comp) +
|
||||||
"[comp=" + toString(comp) +
|
|
||||||
", vroot=" + toString(vroot) + "].");
|
", vroot=" + toString(vroot) + "].");
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// add the invalid component to our list and we'll validate it on
|
// add the invalid component to our list and we'll validate it on the next frame
|
||||||
// the next frame
|
|
||||||
if (!ListUtil.containsRef(_invalid, vroot)) {
|
if (!ListUtil.containsRef(_invalid, vroot)) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.info("Invalidating " + toString(vroot) + ".");
|
Log.info("Invalidating " + toString(vroot) + ".");
|
||||||
}
|
}
|
||||||
_invalid = ListUtil.add(_invalid, vroot);
|
_invalid = ListUtil.add(_invalid, vroot);
|
||||||
|
|
||||||
// on the mac, components frequently do not repaint themselves
|
// on the mac, components frequently do not repaint themselves after being invalidated
|
||||||
// after being invalidated so we have to force a repaint from
|
// so we have to force a repaint from the validation roon on down
|
||||||
// the validation roon on down
|
|
||||||
if (RunAnywhere.isMacOS() && vroot instanceof JComponent) {
|
if (RunAnywhere.isMacOS() && vroot instanceof JComponent) {
|
||||||
addDirtyRegion((JComponent)vroot, 0, 0,
|
addDirtyRegion((JComponent)vroot, 0, 0, vroot.getWidth(), vroot.getHeight());
|
||||||
vroot.getWidth(), vroot.getHeight());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// documentation inherited
|
// documentation inherited
|
||||||
public synchronized void addDirtyRegion (
|
public synchronized void addDirtyRegion (JComponent comp, int x, int y, int width, int height)
|
||||||
JComponent comp, int x, int y, int width, int height)
|
|
||||||
{
|
{
|
||||||
// ignore invalid requests
|
// ignore invalid requests
|
||||||
if ((width <= 0) || (height <= 0) || (comp == null) ||
|
if ((width <= 0) || (height <= 0) || (comp == null) ||
|
||||||
@@ -151,8 +141,7 @@ public class ActiveRepaintManager extends RepaintManager
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if this component is already dirty, simply expand their
|
// if this component is already dirty, simply expand their existing dirty rectangle
|
||||||
// existing dirty rectangle
|
|
||||||
Rectangle drect = (Rectangle)_dirty.get(comp);
|
Rectangle drect = (Rectangle)_dirty.get(comp);
|
||||||
if (drect != null) {
|
if (drect != null) {
|
||||||
drect.add(x, y);
|
drect.add(x, y);
|
||||||
@@ -168,28 +157,25 @@ public class ActiveRepaintManager extends RepaintManager
|
|||||||
|
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.info("Dirtying component [comp=" + toString(comp) +
|
Log.info("Dirtying component [comp=" + toString(comp) +
|
||||||
", drect=" + StringUtil.toString(
|
", drect=" + StringUtil.toString(new Rectangle(x, y, width, height)) + "].");
|
||||||
new Rectangle(x, y, width, height)) + "].");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we made it this far, we can queue up a dirty region for this
|
// if we made it this far, we can queue up a dirty region for this component to be
|
||||||
// component to be repainted on the next tick
|
// repainted on the next tick
|
||||||
_dirty.put(comp, new Rectangle(x, y, width, height));
|
_dirty.put(comp, new Rectangle(x, y, width, height));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the root component for the supplied component or null if it
|
* Returns the root component for the supplied component or null if it is not part of a rooted
|
||||||
* is not part of a rooted hierarchy or if any parent along the way is
|
* hierarchy or if any parent along the way is found to be hidden or without a peer.
|
||||||
* found to be hidden or without a peer.
|
|
||||||
*/
|
*/
|
||||||
protected Component getRoot (Component comp)
|
protected Component getRoot (Component comp)
|
||||||
{
|
{
|
||||||
for (Component c = comp; c != null; c = c.getParent()) {
|
for (Component c = comp; c != null; c = c.getParent()) {
|
||||||
boolean hidden = !c.isDisplayable();
|
boolean hidden = !c.isDisplayable();
|
||||||
// on the mac, the JRootPane is invalidated before it is
|
// on the mac, the JRootPane is invalidated before it is visible and is never again
|
||||||
// visible and is never again invalidated or repainted, so we
|
// invalidated or repainted, so we punt and allow all invisible components to be
|
||||||
// punt and allow all invisible components to be invalidated
|
// invalidated and revalidated
|
||||||
// and revalidated
|
|
||||||
if (!RunAnywhere.isMacOS()) {
|
if (!RunAnywhere.isMacOS()) {
|
||||||
hidden |= !c.isVisible();
|
hidden |= !c.isVisible();
|
||||||
}
|
}
|
||||||
@@ -207,10 +193,9 @@ public class ActiveRepaintManager extends RepaintManager
|
|||||||
public synchronized Rectangle getDirtyRegion (JComponent comp)
|
public synchronized Rectangle getDirtyRegion (JComponent comp)
|
||||||
{
|
{
|
||||||
Rectangle drect = (Rectangle)_dirty.get(comp);
|
Rectangle drect = (Rectangle)_dirty.get(comp);
|
||||||
// copy the rectangle if we found one, otherwise create an empty
|
// copy the rectangle if we found one, otherwise create an empty rectangle because we don't
|
||||||
// rectangle because we don't want them leaving empty handed
|
// want them leaving empty handed
|
||||||
return (drect == null) ?
|
return (drect == null) ? new Rectangle(0, 0, 0, 0) : new Rectangle(drect);
|
||||||
new Rectangle(0, 0, 0, 0) : new Rectangle(drect);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// documentation inherited
|
// documentation inherited
|
||||||
@@ -220,8 +205,7 @@ public class ActiveRepaintManager extends RepaintManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validates the invalid components that have been queued up since the
|
* Validates the invalid components that have been queued up since the last frame tick.
|
||||||
* last frame tick.
|
|
||||||
*/
|
*/
|
||||||
public void validateComponents ()
|
public void validateComponents ()
|
||||||
{
|
{
|
||||||
@@ -268,11 +252,10 @@ public class ActiveRepaintManager extends RepaintManager
|
|||||||
_dirty = tmap;
|
_dirty = tmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
// scan through the list, looking for components for whom a parent
|
// scan through the list, looking for components for whom a parent component is also dirty.
|
||||||
// component is also dirty. in such a case, the dirty rectangle
|
// in such a case, the dirty rectangle for the parent component is expanded to contain the
|
||||||
// for the parent component is expanded to contain the dirty
|
// dirty rectangle of the child and the child is removed from the repaint list (painting
|
||||||
// rectangle of the child and the child is removed from the
|
// the parent will repaint the child)
|
||||||
// repaint list (painting the parent will repaint the child)
|
|
||||||
Iterator iter = _spare.entrySet().iterator();
|
Iterator iter = _spare.entrySet().iterator();
|
||||||
PRUNE:
|
PRUNE:
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
@@ -281,31 +264,26 @@ public class ActiveRepaintManager extends RepaintManager
|
|||||||
Rectangle drect = (Rectangle)entry.getValue();
|
Rectangle drect = (Rectangle)entry.getValue();
|
||||||
int x = comp.getX() + drect.x, y = comp.getY() + drect.y;
|
int x = comp.getX() + drect.x, y = comp.getY() + drect.y;
|
||||||
|
|
||||||
// climb up the parent hierarchy, looking for the first opaque
|
// climb up the parent hierarchy, looking for the first opaque parent as well as the
|
||||||
// parent as well as the root component
|
// root component
|
||||||
for (Component c = comp.getParent(); c != null; c = c.getParent()) {
|
for (Component c = comp.getParent(); c != null; c = c.getParent()) {
|
||||||
// stop looking for combinable parents for non-visible or
|
// stop looking for combinable parents for non-visible or non-JComponents
|
||||||
// non-JComponents
|
if (!c.isVisible() || !c.isDisplayable() || !(c instanceof JComponent)) {
|
||||||
if (!c.isVisible() || !c.isDisplayable() ||
|
|
||||||
!(c instanceof JComponent)) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check to see if this parent is dirty
|
// check to see if this parent is dirty
|
||||||
Rectangle prect = (Rectangle)_spare.get(c);
|
Rectangle prect = (Rectangle)_spare.get(c);
|
||||||
if (prect != null) {
|
if (prect != null) {
|
||||||
// that we were going to merge it with its parent and
|
// that we were going to merge it with its parent and blow it away
|
||||||
// blow it away
|
|
||||||
drect.x = x;
|
drect.x = x;
|
||||||
drect.y = y;
|
drect.y = y;
|
||||||
|
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.info("Found dirty parent " +
|
Log.info("Found dirty parent [comp=" + toString(comp) +
|
||||||
"[comp=" + toString(comp) +
|
|
||||||
", drect=" + StringUtil.toString(drect) +
|
", drect=" + StringUtil.toString(drect) +
|
||||||
", pcomp=" + toString(c) +
|
", pcomp=" + toString(c) +
|
||||||
", prect=" + StringUtil.toString(prect) +
|
", prect=" + StringUtil.toString(prect) + "].");
|
||||||
"].");
|
|
||||||
}
|
}
|
||||||
prect.add(drect);
|
prect.add(drect);
|
||||||
|
|
||||||
@@ -325,26 +303,24 @@ public class ActiveRepaintManager extends RepaintManager
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// now paint each of the dirty components, by setting the clipping
|
// now paint each of the dirty components, by setting the clipping rectangle appropriately
|
||||||
// rectangle appropriately and calling paint() on the associated
|
// and calling paint() on the associated root component
|
||||||
// root component
|
|
||||||
iter = _spare.entrySet().iterator();
|
iter = _spare.entrySet().iterator();
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
Entry entry = (Entry)iter.next();
|
Entry entry = (Entry)iter.next();
|
||||||
JComponent comp = (JComponent)entry.getKey();
|
JComponent comp = (JComponent)entry.getKey();
|
||||||
Rectangle drect = (Rectangle)entry.getValue();
|
Rectangle drect = (Rectangle)entry.getValue();
|
||||||
|
|
||||||
// get the root component, adjust the clipping (dirty)
|
// get the root component, adjust the clipping (dirty) rectangle and obtain the bounds
|
||||||
// rectangle and obtain the bounds of the client in absolute
|
// of the client in absolute coordinates
|
||||||
// coordinates
|
|
||||||
Component root = null, ocomp = null;
|
Component root = null, ocomp = null;
|
||||||
|
|
||||||
// start with the components bounds which we'll switch to the
|
// start with the components bounds which we'll switch to the opaque parent component's
|
||||||
// opaque parent component's bounds if and when we find one
|
// bounds if and when we find one
|
||||||
_cbounds.setBounds(0, 0, comp.getWidth(), comp.getHeight());
|
_cbounds.setBounds(0, 0, comp.getWidth(), comp.getHeight());
|
||||||
|
|
||||||
// climb up the parent hierarchy, looking for the first opaque
|
// climb up the parent hierarchy, looking for the first opaque parent as well as the
|
||||||
// parent as well as the root component
|
// root component
|
||||||
for (Component c = comp; c != null; c = c.getParent()) {
|
for (Component c = comp; c != null; c = c.getParent()) {
|
||||||
if (!c.isVisible() || !c.isDisplayable()) {
|
if (!c.isVisible() || !c.isDisplayable()) {
|
||||||
break;
|
break;
|
||||||
@@ -354,16 +330,14 @@ public class ActiveRepaintManager extends RepaintManager
|
|||||||
// make a note of the first opaque parent we find
|
// make a note of the first opaque parent we find
|
||||||
if (ocomp == null && ((JComponent)c).isOpaque()) {
|
if (ocomp == null && ((JComponent)c).isOpaque()) {
|
||||||
ocomp = c;
|
ocomp = c;
|
||||||
// we need to obtain the opaque parent's coordinates
|
// we need to obtain the opaque parent's coordinates in the root coordinate
|
||||||
// in the root coordinate system for when we repaint
|
// system for when we repaint
|
||||||
_cbounds.setBounds(
|
_cbounds.setBounds(0, 0, ocomp.getWidth(), ocomp.getHeight());
|
||||||
0, 0, ocomp.getWidth(), ocomp.getHeight());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// oh god the hackery. apparently the fscking
|
// oh god the hackery. apparently the fscking JEditorPane wraps a heavy weight
|
||||||
// JEditorPane wraps a heavy weight component around
|
// component around every swing component it uses when doing forms
|
||||||
// every swing component it uses when doing forms
|
|
||||||
Component tp = c.getParent();
|
Component tp = c.getParent();
|
||||||
if (!(tp instanceof JEditorPane)) {
|
if (!(tp instanceof JEditorPane)) {
|
||||||
root = c;
|
root = c;
|
||||||
@@ -371,8 +345,7 @@ public class ActiveRepaintManager extends RepaintManager
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// translate the coordinates into this component's
|
// translate the coordinates into this component's coordinate system
|
||||||
// coordinate system
|
|
||||||
drect.x += c.getX();
|
drect.x += c.getX();
|
||||||
drect.y += c.getY();
|
drect.y += c.getY();
|
||||||
_cbounds.x += c.getX();
|
_cbounds.x += c.getX();
|
||||||
@@ -383,19 +356,17 @@ public class ActiveRepaintManager extends RepaintManager
|
|||||||
c.getX(), c.getY(), c.getWidth(), c.getHeight(), drect);
|
c.getX(), c.getY(), c.getWidth(), c.getHeight(), drect);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we found no opaque parent, just paint the component
|
// if we found no opaque parent, just paint the component itself (this seems to happen
|
||||||
// itself (this seems to happen with the top-level layered
|
// with the top-level layered pane)
|
||||||
// pane)
|
|
||||||
if (ocomp == null) {
|
if (ocomp == null) {
|
||||||
ocomp = comp;
|
ocomp = comp;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if this component is rooted in our frame, repaint it into
|
// if this component is rooted in our frame, repaint it into the supplied graphics
|
||||||
// the supplied graphics instance
|
// instance
|
||||||
if (root == _root) {
|
if (root == _root) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.info("Repainting [comp=" + toString(comp) +
|
Log.info("Repainting [comp=" + toString(comp) + StringUtil.toString(_cbounds) +
|
||||||
StringUtil.toString(_cbounds) +
|
|
||||||
", ocomp=" + toString(ocomp) +
|
", ocomp=" + toString(ocomp) +
|
||||||
", drect=" + StringUtil.toString(drect) + "].");
|
", drect=" + StringUtil.toString(drect) + "].");
|
||||||
}
|
}
|
||||||
@@ -403,36 +374,30 @@ public class ActiveRepaintManager extends RepaintManager
|
|||||||
g.setClip(drect);
|
g.setClip(drect);
|
||||||
g.translate(_cbounds.x, _cbounds.y);
|
g.translate(_cbounds.x, _cbounds.y);
|
||||||
try {
|
try {
|
||||||
// some components are ill-behaved and may throw an
|
// some components are ill-behaved and may throw an exception while painting
|
||||||
// exception while painting themselves, and so we
|
// themselves, and so we needs must deal with these fellows gracefully
|
||||||
// needs must deal with these fellows gracefully
|
|
||||||
ocomp.paint(g);
|
ocomp.paint(g);
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.warning("Exception while painting component " +
|
Log.warning("Exception while painting component [comp=" + ocomp + "].");
|
||||||
"[comp=" + ocomp + ", e=" + e + "].");
|
|
||||||
Log.logStackTrace(e);
|
Log.logStackTrace(e);
|
||||||
}
|
}
|
||||||
g.translate(-_cbounds.x, -_cbounds.y);
|
g.translate(-_cbounds.x, -_cbounds.y);
|
||||||
|
|
||||||
// we also need to repaint any components in this layer
|
// we also need to repaint any components in this layer that are above our freshly
|
||||||
// that are above our freshly repainted component
|
// repainted component
|
||||||
fmgr.renderLayers((Graphics2D)g, ocomp, _cbounds, _clipped);
|
fmgr.renderLayers((Graphics2D)g, ocomp, _cbounds, _clipped);
|
||||||
|
|
||||||
} else if (root != null) {
|
} else if (root != null) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.info("Repainting old-school " +
|
Log.info("Repainting old-school [comp=" + toString(comp) +
|
||||||
"[comp=" + toString(comp) +
|
", ocomp=" + toString(ocomp) + ", root=" + toString(root) +
|
||||||
", ocomp=" + toString(ocomp) +
|
", bounds=" + StringUtil.toString(_cbounds) + "].");
|
||||||
", root=" + toString(root) +
|
|
||||||
", bounds=" + StringUtil.toString(_cbounds) +
|
|
||||||
"].");
|
|
||||||
dumpHierarchy(comp);
|
dumpHierarchy(comp);
|
||||||
}
|
}
|
||||||
|
|
||||||
// otherwise, repaint with standard swing double buffers
|
// otherwise, repaint with standard swing double buffers
|
||||||
Image obuf = getOffscreenBuffer(
|
Image obuf = getOffscreenBuffer(ocomp, _cbounds.width, _cbounds.height);
|
||||||
ocomp, _cbounds.width, _cbounds.height);
|
|
||||||
Graphics og = null, cg = null;
|
Graphics og = null, cg = null;
|
||||||
try {
|
try {
|
||||||
og = obuf.getGraphics();
|
og = obuf.getGraphics();
|
||||||
@@ -462,8 +427,7 @@ public class ActiveRepaintManager extends RepaintManager
|
|||||||
*/
|
*/
|
||||||
protected static String toString (Component comp)
|
protected static String toString (Component comp)
|
||||||
{
|
{
|
||||||
return comp.getClass().getName() +
|
return comp.getClass().getName() + StringUtil.toString(comp.getBounds());
|
||||||
StringUtil.toString(comp.getBounds());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -486,8 +450,7 @@ public class ActiveRepaintManager extends RepaintManager
|
|||||||
/** A mapping of invalid rectangles for each widget that is dirty. */
|
/** A mapping of invalid rectangles for each widget that is dirty. */
|
||||||
protected HashMap _dirty = new HashMap();
|
protected HashMap _dirty = new HashMap();
|
||||||
|
|
||||||
/** A spare hashmap that we swap in while repainting dirty components
|
/** A spare hashmap that we swap in while repainting dirty components in the old hashmap. */
|
||||||
* in the old hashmap. */
|
|
||||||
protected HashMap _spare = new HashMap();
|
protected HashMap _spare = new HashMap();
|
||||||
|
|
||||||
/** Used to compute dirty components' bounds. */
|
/** Used to compute dirty components' bounds. */
|
||||||
@@ -496,7 +459,6 @@ public class ActiveRepaintManager extends RepaintManager
|
|||||||
/** Used when rendering "layered" components. */
|
/** Used when rendering "layered" components. */
|
||||||
protected boolean[] _clipped = new boolean[] { true };
|
protected boolean[] _clipped = new boolean[] { true };
|
||||||
|
|
||||||
/** We debug so much that we have to make it easy to enable and
|
/** We debug so much that we have to make it easy to enable and disable debug logging. Yay! */
|
||||||
* disable debug logging. Yay! */
|
|
||||||
protected static final boolean DEBUG = false;
|
protected static final boolean DEBUG = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -221,7 +221,6 @@ public abstract class FrameManager
|
|||||||
{
|
{
|
||||||
if (_overlay == null) {
|
if (_overlay == null) {
|
||||||
_overlay = new MediaOverlay(this);
|
_overlay = new MediaOverlay(this);
|
||||||
registerFrameParticipant(_overlay);
|
|
||||||
}
|
}
|
||||||
return _overlay;
|
return _overlay;
|
||||||
}
|
}
|
||||||
@@ -232,7 +231,6 @@ public abstract class FrameManager
|
|||||||
public void clearMediaOverlay ()
|
public void clearMediaOverlay ()
|
||||||
{
|
{
|
||||||
if (_overlay != null) {
|
if (_overlay != null) {
|
||||||
removeFrameParticipant(_overlay);
|
|
||||||
_overlay = null;
|
_overlay = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -330,11 +328,11 @@ public abstract class FrameManager
|
|||||||
_timer = timer;
|
_timer = timer;
|
||||||
|
|
||||||
// set up our custom repaint manager
|
// set up our custom repaint manager
|
||||||
_remgr = new ActiveRepaintManager(_window);
|
_repainter = new ActiveRepaintManager(_window);
|
||||||
RepaintManager.setCurrentManager(_remgr);
|
RepaintManager.setCurrentManager(_repainter);
|
||||||
|
|
||||||
// turn off double buffering for the whole business because we handle repaints
|
// turn off double buffering for the whole business because we handle repaints
|
||||||
_remgr.setDoubleBufferingEnabled(false);
|
_repainter.setDoubleBufferingEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -377,7 +375,7 @@ public abstract class FrameManager
|
|||||||
|
|
||||||
// validate any invalid components
|
// validate any invalid components
|
||||||
try {
|
try {
|
||||||
_remgr.validateComponents();
|
_repainter.validateComponents();
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
Log.warning("Failure validating components.");
|
Log.warning("Failure validating components.");
|
||||||
Log.logStackTrace(t);
|
Log.logStackTrace(t);
|
||||||
@@ -412,6 +410,11 @@ public abstract class FrameManager
|
|||||||
Log.logStackTrace(t);
|
Log.logStackTrace(t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if we have an overlay, tick that too
|
||||||
|
if (_overlay != null) {
|
||||||
|
_overlay.tick(tickStamp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -494,8 +497,19 @@ public abstract class FrameManager
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if we have a media overlay, give that a chance to propagate dirty regions to the active
|
||||||
|
// repaint manager for areas it dirtied during this tick
|
||||||
|
if (_overlay != null) {
|
||||||
|
_overlay.propagateDirtyRegions(_repainter, _root.getRootPane());
|
||||||
|
}
|
||||||
|
|
||||||
// repaint any widgets that have declared they need to be repainted since the last tick
|
// repaint any widgets that have declared they need to be repainted since the last tick
|
||||||
boolean pcomp = _remgr.paintComponents(gfx, this);
|
boolean pcomp = _repainter.paintComponents(gfx, this);
|
||||||
|
|
||||||
|
// if we have a media overlay, give it a chance to paint on top of everything
|
||||||
|
if (_overlay != null) {
|
||||||
|
pcomp |= _overlay.paint(gfx);
|
||||||
|
}
|
||||||
|
|
||||||
// let the caller know if anybody painted anything
|
// let the caller know if anybody painted anything
|
||||||
return ((painted > 0) || pcomp);
|
return ((painted > 0) || pcomp);
|
||||||
@@ -676,7 +690,7 @@ public abstract class FrameManager
|
|||||||
protected MediaTimer _timer;
|
protected MediaTimer _timer;
|
||||||
|
|
||||||
/** Our custom repaint manager. */
|
/** Our custom repaint manager. */
|
||||||
protected ActiveRepaintManager _remgr;
|
protected ActiveRepaintManager _repainter;
|
||||||
|
|
||||||
/** If active, an overlay that will be rendering sprites and animations on top of the frame. */
|
/** If active, an overlay that will be rendering sprites and animations on top of the frame. */
|
||||||
protected MediaOverlay _overlay;
|
protected MediaOverlay _overlay;
|
||||||
|
|||||||
@@ -23,8 +23,9 @@ package com.threerings.media;
|
|||||||
|
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
|
import java.awt.Rectangle;
|
||||||
|
import javax.swing.JRootPane;
|
||||||
|
|
||||||
import com.threerings.media.FrameParticipant;
|
|
||||||
import com.threerings.media.animation.AnimationManager;
|
import com.threerings.media.animation.AnimationManager;
|
||||||
import com.threerings.media.sprite.SpriteManager;
|
import com.threerings.media.sprite.SpriteManager;
|
||||||
|
|
||||||
@@ -35,7 +36,7 @@ import com.threerings.media.sprite.SpriteManager;
|
|||||||
* it has left dirty.
|
* it has left dirty.
|
||||||
*/
|
*/
|
||||||
public class MediaOverlay
|
public class MediaOverlay
|
||||||
implements MediaHost, FrameParticipant
|
implements MediaHost
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Returns a reference to the animation manager used by this media panel.
|
* Returns a reference to the animation manager used by this media panel.
|
||||||
@@ -53,13 +54,51 @@ public class MediaOverlay
|
|||||||
return _metamgr.getSpriteManager();
|
return _metamgr.getSpriteManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by the {@link FrameManager} to propagate our dirty regions to the active repaint
|
||||||
|
* manager so that it can repaint the underlying components just prior to our painting our
|
||||||
|
* media. This will be followe by a call to {@link paint} after the components have been
|
||||||
|
* repainted.
|
||||||
|
*/
|
||||||
|
public void propagateDirtyRegions (ActiveRepaintManager repmgr, JRootPane root)
|
||||||
|
{
|
||||||
|
// this will clear out our region manager, so we need to keep these around for our
|
||||||
|
// subsequent call to paint
|
||||||
|
_dirty = _metamgr.getRegionManager().getDirtyRegions();
|
||||||
|
for (int ii = 0; ii < _dirty.length; ii++) {
|
||||||
|
Rectangle dirty = _dirty[ii];
|
||||||
|
repmgr.addDirtyRegion(root, dirty.x, dirty.y, dirty.width, dirty.height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by the {@link FrameManager} after everything is done painting, allowing us to paint
|
||||||
|
* gloriously overtop of everything in the frame.
|
||||||
|
*
|
||||||
|
* @return true if we painted something, false otherwise.
|
||||||
|
*/
|
||||||
|
public boolean paint (Graphics2D gfx)
|
||||||
|
{
|
||||||
|
if (_metamgr.needsPaint()) {
|
||||||
|
for (int ii = 0; ii < _dirty.length; ii++) {
|
||||||
|
gfx.setClip(_dirty[ii]);
|
||||||
|
_metamgr.paintMedia(gfx, MediaConstants.BACK, _dirty[ii]);
|
||||||
|
_metamgr.paintMedia(gfx, MediaConstants.FRONT, _dirty[ii]);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// from interface MediaHost
|
// from interface MediaHost
|
||||||
public Graphics2D createGraphics ()
|
public Graphics2D createGraphics ()
|
||||||
{
|
{
|
||||||
return _metamgr.getFrameManager().createGraphics();
|
return _metamgr.getFrameManager().createGraphics();
|
||||||
}
|
}
|
||||||
|
|
||||||
// from interface FrameParticipant
|
/**
|
||||||
|
* Called by the frame manager on every tick.
|
||||||
|
*/
|
||||||
public void tick (long tickStamp)
|
public void tick (long tickStamp)
|
||||||
{
|
{
|
||||||
if (!_metamgr.isPaused()) {
|
if (!_metamgr.isPaused()) {
|
||||||
@@ -68,18 +107,6 @@ public class MediaOverlay
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// from interface FrameParticipant
|
|
||||||
public boolean needsPaint ()
|
|
||||||
{
|
|
||||||
return _metamgr.needsPaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
// from interface FrameParticipant
|
|
||||||
public Component getComponent ()
|
|
||||||
{
|
|
||||||
return null; // TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a media overlay. Only the {@link FrameManager} will construct an instance.
|
* Creates a media overlay. Only the {@link FrameManager} will construct an instance.
|
||||||
*/
|
*/
|
||||||
@@ -94,4 +121,7 @@ public class MediaOverlay
|
|||||||
|
|
||||||
/** Handles the heavy lifting involving media. */
|
/** Handles the heavy lifting involving media. */
|
||||||
protected MetaMediaManager _metamgr;
|
protected MetaMediaManager _metamgr;
|
||||||
|
|
||||||
|
/** A temporary list of dirty rectangles maintained during the painting process. */
|
||||||
|
protected Rectangle[] _dirty;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -127,6 +127,14 @@ public class MediaPanel extends JComponent
|
|||||||
return _metamgr.getSpriteManager();
|
return _metamgr.getSpriteManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a reference to the region manager used by this media panel.
|
||||||
|
*/
|
||||||
|
public RegionManager getRegionManager ()
|
||||||
|
{
|
||||||
|
return _metamgr.getRegionManager();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pauses the sprites and animations that are currently active on this media panel. Also stops
|
* Pauses the sprites and animations that are currently active on this media panel. Also stops
|
||||||
* listening to the frame tick while paused.
|
* listening to the frame tick while paused.
|
||||||
|
|||||||
@@ -29,9 +29,8 @@ import java.util.ArrayList;
|
|||||||
import com.samskivert.util.StringUtil;
|
import com.samskivert.util.StringUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages regions (rectangles) that are invalidated in the process of
|
* Manages regions (rectangles) that are invalidated in the process of ticking animations and
|
||||||
* ticking animations and sprites and generally doing other display
|
* sprites and generally doing other display related business.
|
||||||
* related business.
|
|
||||||
*/
|
*/
|
||||||
public class RegionManager
|
public class RegionManager
|
||||||
{
|
{
|
||||||
@@ -46,9 +45,8 @@ public class RegionManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invalidates the specified region (the supplied rectangle will be
|
* Invalidates the specified region (the supplied rectangle will be cloned as the region
|
||||||
* cloned as the region manager fiddles with the rectangles it uses
|
* manager fiddles with the rectangles it uses internally).
|
||||||
* internally).
|
|
||||||
*/
|
*/
|
||||||
public void invalidateRegion (Rectangle rect)
|
public void invalidateRegion (Rectangle rect)
|
||||||
{
|
{
|
||||||
@@ -58,17 +56,15 @@ public class RegionManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds the supplied rectangle to the dirty regions. Control of the
|
* Adds the supplied rectangle to the dirty regions. Control of the rectangle is given to the
|
||||||
* rectangle is given to the region manager as it may choose to bend,
|
* region manager as it may choose to bend, fold or mutilate it later. If you don't want the
|
||||||
* fold or mutilate it later. If you don't want the region manager
|
* region manager messing with your rectangle, use {@link #invalidateRegion}.
|
||||||
* messing with your rectangle, use {@link #invalidateRegion}.
|
|
||||||
*/
|
*/
|
||||||
public void addDirtyRegion (Rectangle rect)
|
public void addDirtyRegion (Rectangle rect)
|
||||||
{
|
{
|
||||||
// make sure we're on an AWT thread
|
// make sure we're on an AWT thread
|
||||||
if (!EventQueue.isDispatchThread()) {
|
if (!EventQueue.isDispatchThread()) {
|
||||||
Log.warning("Oi! Region dirtied on non-AWT thread " +
|
Log.warning("Oi! Region dirtied on non-AWT thread [rect=" + rect + "].");
|
||||||
"[rect=" + rect + "].");
|
|
||||||
Thread.dumpStack();
|
Thread.dumpStack();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,8 +77,7 @@ public class RegionManager
|
|||||||
|
|
||||||
// more sanity checking
|
// more sanity checking
|
||||||
long x = rect.x, y = rect.y;
|
long x = rect.x, y = rect.y;
|
||||||
if ((Math.abs(x) > Integer.MAX_VALUE/2) ||
|
if ((Math.abs(x) > Integer.MAX_VALUE/2) || (Math.abs(y) > Integer.MAX_VALUE/2)) {
|
||||||
(Math.abs(y) > Integer.MAX_VALUE/2)) {
|
|
||||||
Log.warning("Requested to dirty questionable region " +
|
Log.warning("Requested to dirty questionable region " +
|
||||||
"[rect=" + StringUtil.toString(rect) + "].");
|
"[rect=" + StringUtil.toString(rect) + "].");
|
||||||
if (Log.getLevel() == Log.log.DEBUG) {
|
if (Log.getLevel() == Log.log.DEBUG) {
|
||||||
@@ -107,8 +102,7 @@ public class RegionManager
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
} else if (width == 0 || height == 0) {
|
} else if (width == 0 || height == 0) {
|
||||||
// no need to complain about zero sized rectangles, just
|
// no need to complain about zero sized rectangles, just ignore them
|
||||||
// ignore them
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@@ -117,8 +111,8 @@ public class RegionManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if dirty regions have been accumulated since the last
|
* Returns true if dirty regions have been accumulated since the last call to {@link
|
||||||
* call to {@link #getDirtyRegions}.
|
* #getDirtyRegions}.
|
||||||
*/
|
*/
|
||||||
public boolean haveDirtyRegions ()
|
public boolean haveDirtyRegions ()
|
||||||
{
|
{
|
||||||
@@ -126,10 +120,9 @@ public class RegionManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Merges all outstanding dirty regions into a single list of
|
* Merges all outstanding dirty regions into a single list of rectangles and returns that to
|
||||||
* rectangles and returns that to the caller. Interally, the list of
|
* the caller. Interally, the list of accumulated dirty regions is cleared out and prepared for
|
||||||
* accumulated dirty regions is cleared out and prepared for the next
|
* the next frame.
|
||||||
* frame.
|
|
||||||
*/
|
*/
|
||||||
public Rectangle[] getDirtyRegions ()
|
public Rectangle[] getDirtyRegions ()
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user