From 7090277d99a43a68c3c6ea7f058e488082aa3e7d Mon Sep 17 00:00:00 2001 From: Michael Bayne Date: Wed, 7 Jun 2006 21:54:12 +0000 Subject: [PATCH] Revamped the frame manager to support operating on non-JFrames where our Window and our RootPaneContainer might be different things (the Window would naturally contain the RootPaneContainer but wouldn't necessarily be the same component). git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@4181 542714f4-19e9-0310-aa3c-eee0fc999fb1 --- ...Manager.java => ActiveRepaintManager.java} | 21 ++-- .../threerings/media/BackFrameManager.java | 16 +-- .../threerings/media/FlipFrameManager.java | 12 +- .../com/threerings/media/FrameManager.java | 106 +++++++++--------- .../stage/tools/editor/EditorApp.java | 2 +- .../stage/tools/viewer/ViewerApp.java | 2 +- .../com/threerings/util/KeyDispatcher.java | 55 +++++---- .../com/threerings/media/util/PathViz.java | 4 +- .../miso/client/ScrollingTestApp.java | 2 +- .../com/threerings/miso/viewer/ViewerApp.java | 2 +- 10 files changed, 108 insertions(+), 114 deletions(-) rename src/java/com/threerings/media/{FrameRepaintManager.java => ActiveRepaintManager.java} (97%) diff --git a/src/java/com/threerings/media/FrameRepaintManager.java b/src/java/com/threerings/media/ActiveRepaintManager.java similarity index 97% rename from src/java/com/threerings/media/FrameRepaintManager.java rename to src/java/com/threerings/media/ActiveRepaintManager.java index aa981ff2f..9ee0703f2 100644 --- a/src/java/com/threerings/media/FrameRepaintManager.java +++ b/src/java/com/threerings/media/ActiveRepaintManager.java @@ -24,7 +24,6 @@ package com.threerings.media; import java.applet.Applet; import java.awt.Component; -import java.awt.Frame; import java.awt.Graphics2D; import java.awt.Graphics; import java.awt.Image; @@ -53,17 +52,17 @@ import com.samskivert.util.StringUtil; * * @see FrameManager */ -public class FrameRepaintManager extends RepaintManager +public class ActiveRepaintManager extends RepaintManager { /** - * Components that are rooted in this frame will be rendered into the - * offscreen buffer managed by the frame manager. Other components - * will be rendered into separate offscreen buffers and repainted in - * the normal Swing manner. + * Components that are rooted in this component (which must be a {@link + * Window} or an {@link Applet}) will be rendered into the offscreen buffer + * managed by the frame manager. Other components will be rendered into + * separate offscreen buffers and repainted in the normal Swing manner. */ - public FrameRepaintManager (Frame frame) + public ActiveRepaintManager (Component root) { - _rootFrame = frame; + _root = root; } // documentation inherited @@ -393,7 +392,7 @@ public class FrameRepaintManager extends RepaintManager // if this component is rooted in our frame, repaint it into // the supplied graphics instance - if (root == _rootFrame) { + if (root == _root) { if (DEBUG) { Log.info("Repainting [comp=" + toString(comp) + StringUtil.toString(_cbounds) + @@ -478,8 +477,8 @@ public class FrameRepaintManager extends RepaintManager } } - /** The managed frame. */ - protected Frame _rootFrame; + /** The root of our interface. */ + protected Component _root; /** A list of invalid components. */ protected Object[] _invalid; diff --git a/src/java/com/threerings/media/BackFrameManager.java b/src/java/com/threerings/media/BackFrameManager.java index 71efcf3b6..4d2144bca 100644 --- a/src/java/com/threerings/media/BackFrameManager.java +++ b/src/java/com/threerings/media/BackFrameManager.java @@ -1,5 +1,5 @@ // -// $Id: BackFrameManager.java,v 1.8 2004/08/27 02:12:37 mdb Exp $ +// $Id$ // // Narya library - tools for developing networked games // Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved @@ -39,11 +39,11 @@ public class BackFrameManager extends FrameManager boolean incremental = true; do { - GraphicsConfiguration gc = _frame.getGraphicsConfiguration(); + GraphicsConfiguration gc = _window.getGraphicsConfiguration(); // create our off-screen buffer if necessary - if (_backimg == null || _backimg.getWidth() != _frame.getWidth() || - _backimg.getHeight() != _frame.getHeight()) { + if (_backimg == null || _backimg.getWidth() != _window.getWidth() || + _backimg.getHeight() != _window.getHeight()) { createBackBuffer(gc); } @@ -73,8 +73,8 @@ public class BackFrameManager extends FrameManager // dirty everything if we're not incrementally rendering if (!incremental) { - _frame.getRootPane().revalidate(); - _frame.getRootPane().repaint(); + _root.getRootPane().revalidate(); + _root.getRootPane().repaint(); } if (!paint(_bgfx)) { @@ -84,7 +84,7 @@ public class BackFrameManager extends FrameManager // we cache our frame's graphics object so that we can avoid // instantiating a new one on every tick if (_fgfx == null) { - _fgfx = (Graphics2D)_frame.getGraphics(); + _fgfx = (Graphics2D)_window.getGraphics(); } _fgfx.drawImage(_backimg, 0, 0, null); @@ -120,7 +120,7 @@ public class BackFrameManager extends FrameManager } // create the offscreen buffer - int width = _frame.getWidth(), height = _frame.getHeight(); + int width = _window.getWidth(), height = _window.getHeight(); _backimg = gc.createCompatibleVolatileImage(width, height); // fill the back buffer with white diff --git a/src/java/com/threerings/media/FlipFrameManager.java b/src/java/com/threerings/media/FlipFrameManager.java index e3b32c2bf..f6d0ef5ea 100644 --- a/src/java/com/threerings/media/FlipFrameManager.java +++ b/src/java/com/threerings/media/FlipFrameManager.java @@ -1,5 +1,5 @@ // -// $Id: FlipFrameManager.java,v 1.6 2004/08/27 02:12:37 mdb Exp $ +// $Id$ // // Narya library - tools for developing networked games // Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved @@ -43,13 +43,13 @@ public class FlipFrameManager extends FrameManager new ImageCapabilities(true), new ImageCapabilities(true), BufferCapabilities.FlipContents.COPIED); try { - _frame.createBufferStrategy(2, cap); + _window.createBufferStrategy(2, cap); } catch (AWTException ae) { Log.warning("Failed creating flip bufstrat: " + ae + "."); // fall back to one without custom capabilities - _frame.createBufferStrategy(2); + _window.createBufferStrategy(2); } - _bufstrat = _frame.getBufferStrategy(); + _bufstrat = _window.getBufferStrategy(); } // start out assuming we can do an incremental render @@ -65,8 +65,8 @@ public class FlipFrameManager extends FrameManager Log.info("Doing non-incremental render; contents lost " + "[lost=" + _bufstrat.contentsLost() + ", rest=" + _bufstrat.contentsRestored() + "]."); - _frame.getRootPane().revalidate(); - _frame.getRootPane().repaint(); + _root.getRootPane().revalidate(); + _root.getRootPane().repaint(); } // request to paint our participants and components and bail diff --git a/src/java/com/threerings/media/FrameManager.java b/src/java/com/threerings/media/FrameManager.java index 0b6331112..7fa420858 100644 --- a/src/java/com/threerings/media/FrameManager.java +++ b/src/java/com/threerings/media/FrameManager.java @@ -39,9 +39,10 @@ import java.awt.event.WindowListener; import java.awt.EventQueue; -import javax.swing.JFrame; import javax.swing.JLayeredPane; import javax.swing.RepaintManager; +import javax.swing.JRootPane; +import javax.swing.RootPaneContainer; import javax.swing.event.AncestorEvent; import javax.swing.event.AncestorListener; @@ -56,35 +57,33 @@ import com.threerings.media.util.TrailingAverage; import com.threerings.util.unsafe.Unsafe; /** - * Provides a central point from which the computation for each "frame" or - * tick can be dispatched. This assumed that the application structures - * its activity around the rendering of each frame, which is a common - * architecture for games. The animation and sprite support provided by - * other classes in this package are structured for use in an application - * that uses a frame manager to tick everything once per frame. + * Provides a central point from which the computation for each "frame" or tick + * can be dispatched. This assumed that the application structures its activity + * around the rendering of each frame, which is a common architecture for + * games. The animation and sprite support provided by other classes in this + * package are structured for use in an application that uses a frame manager + * to tick everything once per frame. * - *

The frame manager goes through a simple two part procedure every - * frame: + *

The frame manager goes through a simple two part procedure every frame: * *

+ *
  • Painting the user interface hierarchy: the top-level component (the + * frame) is painted (via a call to {@link JRootPane#paint}) into a flip buffer + * (if supported, an off-screen buffer if not). Updates that were computed + * during the tick should be rendered in this call to paint. The paint call + * will propagate down to all components in the UI hierarchy, some of which may + * be {@link FrameParticipant}s and will have prepared themselves for their + * upcoming painting in the previous call to {@link + * FrameParticipant#tick}. When the call to paint completes, the flip buffer is + * flipped and the process starts all over again. * *

    The ticking and rendering takes place on the AWT thread so as to * avoid the need for complicated coordination between AWT event handler @@ -125,12 +124,13 @@ public abstract class FrameManager /** * Creates a frame manager that will use a {@link SystemMediaTimer} to - * obtain timing information, which is available on every platform, - * but returns inaccurate time stamps on many platforms. + * obtain timing information, which is available on every platform, but + * returns inaccurate time stamps on many platforms. * - * @see #newInstance(JFrame, MediaTimer) + * @see #newInstance(Window, RootPaneContainer, MediaTimer) */ - public static FrameManager newInstance (JFrame frame) + public static FrameManager newInstance ( + Window window, RootPaneContainer root) { // first try creating a PerfTimer which is the best if we're using // JDK1.4.2 @@ -142,7 +142,7 @@ public abstract class FrameManager "System.currentTimeMillis() based timer."); timer = new SystemMediaTimer(); } - return newInstance(frame, timer); + return newInstance(window, root, timer); } /** @@ -154,7 +154,8 @@ public abstract class FrameManager * * @see GraphicsDevice#setFullScreenWindow */ - public static FrameManager newInstance (JFrame frame, MediaTimer timer) + public static FrameManager newInstance ( + Window window, RootPaneContainer root, MediaTimer timer) { FrameManager fmgr; if (_useFlip.getValue()) { @@ -164,23 +165,25 @@ public abstract class FrameManager Log.info("Creating back frame manager."); fmgr = new BackFrameManager(); } - fmgr.init(frame, timer); + fmgr.init(window, root, timer); return fmgr; } /** * Initializes this frame manager and prepares it for operation. */ - protected void init (JFrame frame, MediaTimer timer) + protected void init ( + Window window, RootPaneContainer root, MediaTimer timer) { - _frame = frame; - if (frame instanceof ManagedJFrame) { - ((ManagedJFrame)_frame).init(this); + _window = window; + _root = root; + if (window instanceof ManagedJFrame) { + ((ManagedJFrame)window).init(this); } _timer = timer; // set up our custom repaint manager - _remgr = new FrameRepaintManager(_frame); + _remgr = new ActiveRepaintManager(_window); RepaintManager.setCurrentManager(_remgr); // turn off double buffering for the whole business because we @@ -199,7 +202,7 @@ public abstract class FrameManager protected void addTestListeners () { // add a test window listener - _frame.addWindowListener(new WindowListener() { + _window.addWindowListener(new WindowListener() { public void windowActivated (WindowEvent e) { Log.info("Window activated [evt=" + e + "]."); } @@ -230,7 +233,7 @@ public abstract class FrameManager }); // add a component listener - _frame.addComponentListener(new ComponentListener() { + _window.addComponentListener(new ComponentListener() { public void componentHidden (ComponentEvent e) { Log.info("Window component hidden [evt=" + e + "]."); } @@ -249,7 +252,7 @@ public abstract class FrameManager }); // add test ancestor focus listener - _frame.getRootPane().addAncestorListener( + _root.getRootPane().addAncestorListener( new AncestorListener() { public void ancestorAdded (AncestorEvent e) { Log.info("Root pane ancestor added [e=" + e + "]."); @@ -328,14 +331,6 @@ public abstract class FrameManager ListUtil.clearRef(_participants, participant); } - /** - * Returns the frame being managed. - */ - public JFrame getFrame () - { - return _frame; - } - /** * Returns a millisecond granularity time stamp using the {@link * MediaTimer} with which this frame manager was configured. @@ -419,8 +414,8 @@ public abstract class FrameManager } // if our frame is not showing (or is impossibly sized), don't try // rendering anything - if (_frame.isShowing() && - _frame.getWidth() > 0 && _frame.getHeight() > 0) { + if (_window.isShowing() && + _window.getWidth() > 0 && _window.getHeight() > 0) { // tick our participants tickParticipants(tickStamp); paint = _timer.getElapsedMicros(); @@ -488,7 +483,7 @@ public abstract class FrameManager /** * Called once per frame to invoke {@link Component#paint} on all of * our frame participants' components and all dirty components managed - * by our {@link FrameRepaintManager}. + * by our {@link ActiveRepaintManager}. */ protected abstract void paint (long tickStamp); @@ -774,14 +769,17 @@ public abstract class FrameManager protected long _lastTick; }; - /** The frame into which we do our rendering. */ - protected JFrame _frame; + /** The window into which we do our rendering. */ + protected Window _window; + + /** Provides access to our Swing bits. */ + protected RootPaneContainer _root; /** Used to obtain timing measurements. */ protected MediaTimer _timer; /** Our custom repaint manager. */ - protected FrameRepaintManager _remgr; + protected ActiveRepaintManager _remgr; /** The number of milliseconds per frame (14 by default, which gives * an fps of ~71). */ diff --git a/src/java/com/threerings/stage/tools/editor/EditorApp.java b/src/java/com/threerings/stage/tools/editor/EditorApp.java index 3481ff6ad..5f4536f3b 100644 --- a/src/java/com/threerings/stage/tools/editor/EditorApp.java +++ b/src/java/com/threerings/stage/tools/editor/EditorApp.java @@ -89,7 +89,7 @@ public class EditorApp implements Runnable _frame = createEditorFrame(); // create our frame manager - _framemgr = FrameManager.newInstance(_frame); + _framemgr = FrameManager.newInstance(_frame, _frame); // create our myriad managers, repositories, etc. _rmgr = new ResourceManager("rsrc"); diff --git a/src/java/com/threerings/stage/tools/viewer/ViewerApp.java b/src/java/com/threerings/stage/tools/viewer/ViewerApp.java index e575d7df3..e8b11e826 100644 --- a/src/java/com/threerings/stage/tools/viewer/ViewerApp.java +++ b/src/java/com/threerings/stage/tools/viewer/ViewerApp.java @@ -76,7 +76,7 @@ public class ViewerApp _mesgmgr = new MessageManager("rsrc.i18n"); _frame = new ViewerFrame(gc); - _framemgr = FrameManager.newInstance(_frame); + _framemgr = FrameManager.newInstance(_frame, _frame); StageContext ctx = new ContextImpl(); _frame.init(ctx, new CharacterManager(_imgr, _crepo)); diff --git a/src/java/com/threerings/util/KeyDispatcher.java b/src/java/com/threerings/util/KeyDispatcher.java index c667c1940..3714bc730 100644 --- a/src/java/com/threerings/util/KeyDispatcher.java +++ b/src/java/com/threerings/util/KeyDispatcher.java @@ -22,7 +22,7 @@ package com.threerings.util; import java.awt.Component; -import java.awt.Frame; +import java.awt.Window; import java.awt.KeyEventDispatcher; import java.awt.KeyboardFocusManager; @@ -61,14 +61,14 @@ public class KeyDispatcher /** * Constructs a key dispatcher. */ - public KeyDispatcher (Frame frame) + public KeyDispatcher (Window window) { // save things off - _frame = frame; + _window = window; - // listen to window events on our main frame so that we can - // release keys when the mouse leaves the frame - _frame.addWindowFocusListener(this); + // listen to window events on our main window so that we can release + // keys when the mouse leaves the window + _window.addWindowFocusListener(this); // monitor key events from the central dispatch mechanism KeyboardFocusManager.getCurrentKeyboardFocusManager(). @@ -76,19 +76,17 @@ public class KeyDispatcher } /** - * Shuts down the key dispatcher. We currently have no plans to ever - * shut this little guy down, and so we leave the following dead code - * here, commented forevermore. + * Shuts down the key dispatcher. */ -// public void shutdown () -// { -// // cease monitoring key events -// KeyboardFocusManager.getCurrentKeyboardFocusManager(). -// removeKeyEventDispatcher(this); + public void shutdown () + { + // cease monitoring key events + KeyboardFocusManager.getCurrentKeyboardFocusManager(). + removeKeyEventDispatcher(this); -// // cease observing our frame -// _frame.removeWindowFocusListener(this); -// } + // cease observing our window + _window.removeWindowFocusListener(this); + } /** * Makes the specified component the new grabber of key typed events @@ -121,7 +119,7 @@ public class KeyDispatcher // update the current chat grabbing component _curChatGrabber = _chatGrabbers.isEmpty() ? null : - (JTextComponent) _chatGrabbers.getLast(); + _chatGrabbers.getLast(); } /** @@ -149,7 +147,7 @@ public class KeyDispatcher case KeyEvent.KEY_TYPED: // dispatch to all the global listeners for (int ii = 0; ii < lsize; ii++) { - ((KeyListener) _listeners.get(ii)).keyTyped(e); + _listeners.get(ii).keyTyped(e); } // see if a chat grabber needs to grab it @@ -172,7 +170,7 @@ public class KeyDispatcher case KeyEvent.KEY_PRESSED: if (lsize > 0) { for (int ii = 0; ii < lsize; ii++) { - ((KeyListener) _listeners.get(ii)).keyPressed(e); + _listeners.get(ii).keyPressed(e); } // remember the key event.. _downKeys.put(e.getKeyCode(), e); @@ -227,15 +225,13 @@ public class KeyDispatcher // un-press any keys that were left down if (!_downKeys.isEmpty()) { long now = System.currentTimeMillis(); - for (Iterator iter = _downKeys.elements(); iter.hasNext(); ) { - KeyEvent down = (KeyEvent) iter.next(); + for (KeyEvent down : _downKeys.values()) { KeyEvent up = new KeyEvent( down.getComponent(), KeyEvent.KEY_RELEASED, now, down.getModifiers(), down.getKeyCode(), down.getKeyChar(), down.getKeyLocation()); - for (int ii = 0, nn = _listeners.size(); ii < nn; ii++) { - ((KeyListener) _listeners.get(ii)).keyReleased(up); + _listeners.get(ii).keyReleased(up); } } _downKeys.clear(); @@ -260,19 +256,20 @@ public class KeyDispatcher removeChatGrabber((JTextComponent) ae.getComponent()); } - /** The main frame for which we're observing key events. */ - protected Frame _frame; + /** The main window for which we're observing key events. */ + protected Window _window; /** The current most-recently pushed component that wants to grab * alphanumeric key presses. */ protected JTextComponent _curChatGrabber; /** The stack of grabbers. */ - protected LinkedList _chatGrabbers = new LinkedList(); + protected LinkedList _chatGrabbers = + new LinkedList(); /** Global key listeners. */ - protected ArrayList _listeners = new ArrayList(); + protected ArrayList _listeners = new ArrayList(); /** Keys that are currently held down. */ - protected HashIntMap _downKeys = new HashIntMap(); + protected HashIntMap _downKeys = new HashIntMap(); } diff --git a/tests/src/java/com/threerings/media/util/PathViz.java b/tests/src/java/com/threerings/media/util/PathViz.java index 8490bd5f3..8e667bf84 100644 --- a/tests/src/java/com/threerings/media/util/PathViz.java +++ b/tests/src/java/com/threerings/media/util/PathViz.java @@ -1,5 +1,5 @@ // -// $Id: PathViz.java,v 1.5 2004/08/27 02:21:00 mdb Exp $ +// $Id$ // // Narya library - tools for developing networked games // Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved @@ -74,7 +74,7 @@ public class PathViz extends MediaPanel public static void main (String[] args) { ManagedJFrame frame = new ManagedJFrame("Path viz"); - FrameManager fmgr = FrameManager.newInstance(frame); + FrameManager fmgr = FrameManager.newInstance(frame, frame); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setContentPane(new PathViz(fmgr)); diff --git a/tests/src/java/com/threerings/miso/client/ScrollingTestApp.java b/tests/src/java/com/threerings/miso/client/ScrollingTestApp.java index 549b82657..54ca6329f 100644 --- a/tests/src/java/com/threerings/miso/client/ScrollingTestApp.java +++ b/tests/src/java/com/threerings/miso/client/ScrollingTestApp.java @@ -88,7 +88,7 @@ public class ScrollingTestApp _frame = new ScrollingFrame(gc); // set up our frame manager - _framemgr = FrameManager.newInstance(_frame); + _framemgr = FrameManager.newInstance(_frame, _frame); // we don't need to configure anything ResourceManager rmgr = new ResourceManager("rsrc"); diff --git a/tests/src/java/com/threerings/miso/viewer/ViewerApp.java b/tests/src/java/com/threerings/miso/viewer/ViewerApp.java index 075ab5ee2..4d234ff04 100644 --- a/tests/src/java/com/threerings/miso/viewer/ViewerApp.java +++ b/tests/src/java/com/threerings/miso/viewer/ViewerApp.java @@ -81,7 +81,7 @@ public class ViewerApp // create the window _frame = new ViewerFrame(gc); - _framemgr = FrameManager.newInstance(_frame); + _framemgr = FrameManager.newInstance(_frame, _frame); // we don't need to configure anything ResourceManager rmgr = new ResourceManager("rsrc");