Moved SwingActiveRender utility to it's own module
This commit is contained in:
parent
fd68a23974
commit
9ebc3499ea
@ -1,116 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2015 dorkbox, llc
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package dorkbox.util.swing;
|
|
||||||
|
|
||||||
import java.awt.Component;
|
|
||||||
import java.awt.Graphics;
|
|
||||||
import java.awt.Toolkit;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.swing.JComponent;
|
|
||||||
|
|
||||||
import dorkbox.util.ActionHandlerLong;
|
|
||||||
import dorkbox.util.Property;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loop that controls the active rendering process
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
class ActiveRenderLoop implements Runnable {
|
|
||||||
|
|
||||||
@Property
|
|
||||||
/**
|
|
||||||
* How many frames per second we want the Swing ActiveRender thread to run at
|
|
||||||
*
|
|
||||||
* NOTE: The ActiveRenderLoop replaces the Swing EDT (only for specified JFrames) in order to enable smoother animations. It is also
|
|
||||||
* important to REMEMBER -- if you add a component to an actively managed JFrame, YOU MUST make sure to call
|
|
||||||
* {@link JComponent#setIgnoreRepaint(boolean)} otherwise this component will "fight" on the EDT for updates. You can completely
|
|
||||||
* disable the EDT by calling {@link NullRepaintManager#install()}
|
|
||||||
*/
|
|
||||||
public static int TARGET_FPS = 30;
|
|
||||||
|
|
||||||
@SuppressWarnings("WhileLoopReplaceableByForEach")
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
void run() {
|
|
||||||
long lastTime = System.nanoTime();
|
|
||||||
|
|
||||||
// 30 FPS is usually just fine. This isn't a game where we need 60+ FPS. We permit this to be changed though, just in case it is.
|
|
||||||
final long OPTIMAL_TIME = 1000000000 / TARGET_FPS;
|
|
||||||
Graphics graphics = null;
|
|
||||||
|
|
||||||
while (SwingActiveRender.hasActiveRenders) {
|
|
||||||
long now = System.nanoTime();
|
|
||||||
long updateDeltaNanos = now - lastTime;
|
|
||||||
lastTime = now;
|
|
||||||
|
|
||||||
// not synchronized, because we don't care. The worst case, is one frame of animation behind.
|
|
||||||
for (int i = 0; i < SwingActiveRender.activeRenderEvents.size(); i++) {
|
|
||||||
ActionHandlerLong actionHandlerLong = SwingActiveRender.activeRenderEvents.get(i);
|
|
||||||
|
|
||||||
//noinspection unchecked
|
|
||||||
actionHandlerLong.handle(updateDeltaNanos);
|
|
||||||
}
|
|
||||||
|
|
||||||
// this needs to be synchronized because we don't want to our canvas removed WHILE we are rendering it.
|
|
||||||
synchronized (SwingActiveRender.activeRenders) {
|
|
||||||
final List<Component> activeRenders = SwingActiveRender.activeRenders;
|
|
||||||
|
|
||||||
for (Component component : activeRenders) {
|
|
||||||
if (!component.isDisplayable()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// maybe the frame was closed, so we must be in a try/catch issue #11
|
|
||||||
try {
|
|
||||||
graphics = component.getGraphics();
|
|
||||||
component.paint(graphics);
|
|
||||||
} catch (Exception e) {
|
|
||||||
// the canvas can be closed as well. can get a "java.lang.IllegalStateException: Component must have a valid peer" if
|
|
||||||
// it's already be closed during the getDrawGraphics call.
|
|
||||||
e.printStackTrace();
|
|
||||||
} finally {
|
|
||||||
if (graphics != null) {
|
|
||||||
graphics.dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sync the display on some systems (on Linux, this fixes event queue problems)
|
|
||||||
Toolkit.getDefaultToolkit()
|
|
||||||
.sync();
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Converted to int before the division, because IDIV is
|
|
||||||
// 1 order magnitude faster than LDIV (and int's work for us anyways)
|
|
||||||
// see: http://www.cs.nuim.ie/~jpower/Research/Papers/2008/lambert-qapl08.pdf
|
|
||||||
// Also, down-casting (long -> int) is not expensive w.r.t IDIV/LDIV
|
|
||||||
//noinspection NumericCastThatLosesPrecision
|
|
||||||
final int l = (int) (lastTime - System.nanoTime() + OPTIMAL_TIME);
|
|
||||||
final int millis = l / 1000000;
|
|
||||||
if (millis > 1) {
|
|
||||||
Thread.sleep(millis);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// try to keep the CPU from getting slammed. We couldn't match our target FPS, so loop again
|
|
||||||
Thread.yield();
|
|
||||||
}
|
|
||||||
} catch (InterruptedException ignored) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,109 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2017 dorkbox, llc
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package dorkbox.util.swing;
|
|
||||||
|
|
||||||
import java.awt.Component;
|
|
||||||
import java.awt.Dimension;
|
|
||||||
import java.awt.Graphics;
|
|
||||||
|
|
||||||
import javax.accessibility.Accessible;
|
|
||||||
import javax.swing.JComponent;
|
|
||||||
import javax.swing.UIManager;
|
|
||||||
import javax.swing.plaf.ComponentUI;
|
|
||||||
import javax.swing.plaf.MenuItemUI;
|
|
||||||
|
|
||||||
public
|
|
||||||
class DefaultMenuItemUI extends MenuItemUI {
|
|
||||||
private final ComponentUI ui;
|
|
||||||
|
|
||||||
public
|
|
||||||
DefaultMenuItemUI(final JComponent jComponent) {
|
|
||||||
this.ui = UIManager.getDefaults()
|
|
||||||
.getUI(jComponent);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
void installUI(final JComponent c) {
|
|
||||||
ui.installUI(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
void uninstallUI(final JComponent c) {
|
|
||||||
ui.uninstallUI(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
void paint(final Graphics g, final JComponent c) {
|
|
||||||
ui.paint(g, c);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
void update(final Graphics g, final JComponent c) {
|
|
||||||
ui.update(g, c);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
Dimension getPreferredSize(final JComponent c) {
|
|
||||||
return ui.getPreferredSize(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
Dimension getMinimumSize(final JComponent c) {
|
|
||||||
return ui.getMinimumSize(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
Dimension getMaximumSize(final JComponent c) {
|
|
||||||
return ui.getMaximumSize(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
boolean contains(final JComponent c, final int x, final int y) {
|
|
||||||
return ui.contains(c, x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
int getBaseline(final JComponent c, final int width, final int height) {
|
|
||||||
return ui.getBaseline(c, width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
Component.BaselineResizeBehavior getBaselineResizeBehavior(final JComponent c) {
|
|
||||||
return ui.getBaselineResizeBehavior(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
int getAccessibleChildrenCount(final JComponent c) {
|
|
||||||
return ui.getAccessibleChildrenCount(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
Accessible getAccessibleChild(final JComponent c, final int i) {
|
|
||||||
return ui.getAccessibleChild(c, i);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,109 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2017 dorkbox, llc
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package dorkbox.util.swing;
|
|
||||||
|
|
||||||
import java.awt.Component;
|
|
||||||
import java.awt.Dimension;
|
|
||||||
import java.awt.Graphics;
|
|
||||||
|
|
||||||
import javax.accessibility.Accessible;
|
|
||||||
import javax.swing.JComponent;
|
|
||||||
import javax.swing.UIManager;
|
|
||||||
import javax.swing.plaf.ComponentUI;
|
|
||||||
import javax.swing.plaf.PopupMenuUI;
|
|
||||||
|
|
||||||
public
|
|
||||||
class DefaultPopupMenuUI extends PopupMenuUI {
|
|
||||||
private final ComponentUI ui;
|
|
||||||
|
|
||||||
public
|
|
||||||
DefaultPopupMenuUI(final JComponent jComponent) {
|
|
||||||
this.ui = UIManager.getDefaults()
|
|
||||||
.getUI(jComponent);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
void installUI(final JComponent c) {
|
|
||||||
ui.installUI(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
void uninstallUI(final JComponent c) {
|
|
||||||
ui.uninstallUI(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
void paint(final Graphics g, final JComponent c) {
|
|
||||||
ui.paint(g, c);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
void update(final Graphics g, final JComponent c) {
|
|
||||||
ui.update(g, c);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
Dimension getPreferredSize(final JComponent c) {
|
|
||||||
return ui.getPreferredSize(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
Dimension getMinimumSize(final JComponent c) {
|
|
||||||
return ui.getMinimumSize(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
Dimension getMaximumSize(final JComponent c) {
|
|
||||||
return ui.getMaximumSize(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
boolean contains(final JComponent c, final int x, final int y) {
|
|
||||||
return ui.contains(c, x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
int getBaseline(final JComponent c, final int width, final int height) {
|
|
||||||
return ui.getBaseline(c, width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
Component.BaselineResizeBehavior getBaselineResizeBehavior(final JComponent c) {
|
|
||||||
return ui.getBaselineResizeBehavior(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
int getAccessibleChildrenCount(final JComponent c) {
|
|
||||||
return ui.getAccessibleChildrenCount(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
Accessible getAccessibleChild(final JComponent c, final int i) {
|
|
||||||
return ui.getAccessibleChild(c, i);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,109 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2017 dorkbox, llc
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package dorkbox.util.swing;
|
|
||||||
|
|
||||||
import java.awt.Component;
|
|
||||||
import java.awt.Dimension;
|
|
||||||
import java.awt.Graphics;
|
|
||||||
|
|
||||||
import javax.accessibility.Accessible;
|
|
||||||
import javax.swing.JComponent;
|
|
||||||
import javax.swing.UIManager;
|
|
||||||
import javax.swing.plaf.ComponentUI;
|
|
||||||
import javax.swing.plaf.SeparatorUI;
|
|
||||||
|
|
||||||
public
|
|
||||||
class DefaultSeparatorUI extends SeparatorUI {
|
|
||||||
private final ComponentUI ui;
|
|
||||||
|
|
||||||
public
|
|
||||||
DefaultSeparatorUI(final JComponent jComponent) {
|
|
||||||
this.ui = UIManager.getDefaults()
|
|
||||||
.getUI(jComponent);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
void installUI(final JComponent c) {
|
|
||||||
ui.installUI(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
void uninstallUI(final JComponent c) {
|
|
||||||
ui.uninstallUI(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
void paint(final Graphics g, final JComponent c) {
|
|
||||||
ui.paint(g, c);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
void update(final Graphics g, final JComponent c) {
|
|
||||||
ui.update(g, c);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
Dimension getPreferredSize(final JComponent c) {
|
|
||||||
return ui.getPreferredSize(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
Dimension getMinimumSize(final JComponent c) {
|
|
||||||
return ui.getMinimumSize(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
Dimension getMaximumSize(final JComponent c) {
|
|
||||||
return ui.getMaximumSize(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
boolean contains(final JComponent c, final int x, final int y) {
|
|
||||||
return ui.contains(c, x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
int getBaseline(final JComponent c, final int width, final int height) {
|
|
||||||
return ui.getBaseline(c, width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
Component.BaselineResizeBehavior getBaselineResizeBehavior(final JComponent c) {
|
|
||||||
return ui.getBaselineResizeBehavior(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
int getAccessibleChildrenCount(final JComponent c) {
|
|
||||||
return ui.getAccessibleChildrenCount(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
Accessible getAccessibleChild(final JComponent c, final int i) {
|
|
||||||
return ui.getAccessibleChild(c, i);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,63 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2015 dorkbox, llc
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package dorkbox.util.swing;
|
|
||||||
|
|
||||||
import javax.swing.JComponent;
|
|
||||||
import javax.swing.RepaintManager;
|
|
||||||
import javax.swing.SwingUtilities;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The NullRepaintManager is a RepaintManager that doesn't do any repainting. Useful when all of the rendering is done manually by the
|
|
||||||
* application.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
class NullRepaintManager extends RepaintManager {
|
|
||||||
/**
|
|
||||||
* Installs the NullRepaintManager onto the EDT (WARNING: This disables painting/rendering by the EDT, for the entire JVM)
|
|
||||||
*/
|
|
||||||
public static
|
|
||||||
void install() {
|
|
||||||
SwingUtilities.invokeLater(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
void run() {
|
|
||||||
RepaintManager repaintManager = new NullRepaintManager();
|
|
||||||
repaintManager.setDoubleBufferingEnabled(false);
|
|
||||||
RepaintManager.setCurrentManager(repaintManager);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
void addInvalidComponent(JComponent c) {
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
void addDirtyRegion(JComponent c, int x, int y, int w, int h) {
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
void markCompletelyDirty(JComponent c) {
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
void paintDirtyRegions() {
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,176 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2015 dorkbox, llc
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package dorkbox.util.swing;
|
|
||||||
|
|
||||||
import java.awt.Component;
|
|
||||||
import java.awt.EventQueue;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
|
||||||
|
|
||||||
import javax.swing.SwingUtilities;
|
|
||||||
|
|
||||||
import dorkbox.util.ActionHandlerLong;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Contains all of the appropriate logic to setup and render via "Active" rendering (instead of "Passive" rendering).
|
|
||||||
*
|
|
||||||
* This permits us to render components OFF of the EDT - even though there are other frames/components that are ON the EDT.
|
|
||||||
* <br>
|
|
||||||
* Because we still want to react to mouse events, etc on the EDT, we do not completely remove the EDT -- we merely allow us
|
|
||||||
* to "synchronize" the EDT object to our thread. It's a little bit hacky, but it works beautifully, and permits MUCH nicer animations.
|
|
||||||
* <br>
|
|
||||||
*/
|
|
||||||
public final
|
|
||||||
class SwingActiveRender {
|
|
||||||
private static Thread activeRenderThread = null;
|
|
||||||
|
|
||||||
static final List<Component> activeRenders = new ArrayList<Component>();
|
|
||||||
static final List<ActionHandlerLong> activeRenderEvents = new CopyOnWriteArrayList<ActionHandlerLong>();
|
|
||||||
|
|
||||||
// volatile, so that access triggers thread synchrony, since 1.6. See the Java Language Spec, Chapter 17
|
|
||||||
static volatile boolean hasActiveRenders = false;
|
|
||||||
|
|
||||||
private static final Runnable renderLoop = new ActiveRenderLoop();
|
|
||||||
|
|
||||||
private
|
|
||||||
SwingActiveRender() {
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enables the component to to added to an "Active Render" thread, at a target "Frames-per-second". This is to support smooth, swing-based
|
|
||||||
* animations.
|
|
||||||
* <p>
|
|
||||||
* This works by removing this object from EDT updates and manually calls paint on the component, updating it on our own thread, but
|
|
||||||
* still remaining synchronized with the EDT.
|
|
||||||
*
|
|
||||||
* @param component the component to add to the ActiveRender thread.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("Duplicates")
|
|
||||||
public static
|
|
||||||
void addActiveRender(final Component component) {
|
|
||||||
// this should be on the EDT
|
|
||||||
if (!EventQueue.isDispatchThread()) {
|
|
||||||
SwingUtilities.invokeLater(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
void run() {
|
|
||||||
addActiveRender(component);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
component.setIgnoreRepaint(true);
|
|
||||||
|
|
||||||
synchronized (activeRenders) {
|
|
||||||
if (!hasActiveRenders) {
|
|
||||||
setupActiveRenderThread();
|
|
||||||
}
|
|
||||||
|
|
||||||
hasActiveRenders = true;
|
|
||||||
activeRenders.add(component);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes a component from the ActiveRender queue. This should happen when the component is closed.
|
|
||||||
*
|
|
||||||
* @param component the component to remove
|
|
||||||
*/
|
|
||||||
public static
|
|
||||||
void removeActiveRender(final Component component) {
|
|
||||||
// this should be on the EDT
|
|
||||||
if (!EventQueue.isDispatchThread()) {
|
|
||||||
SwingUtilities.invokeLater(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
void run() {
|
|
||||||
removeActiveRender(component);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
synchronized (activeRenders) {
|
|
||||||
activeRenders.remove(component);
|
|
||||||
|
|
||||||
final boolean hadActiveRenders = !activeRenders.isEmpty();
|
|
||||||
hasActiveRenders = hadActiveRenders;
|
|
||||||
|
|
||||||
if (!hadActiveRenders) {
|
|
||||||
activeRenderThread = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
component.setIgnoreRepaint(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specifies an ActionHandler to be called when the ActiveRender thread starts to render at each tick.
|
|
||||||
*
|
|
||||||
* @param handler the handler to add
|
|
||||||
*/
|
|
||||||
public static
|
|
||||||
void addActiveRenderFrameStart(final ActionHandlerLong handler) {
|
|
||||||
synchronized (activeRenders) {
|
|
||||||
activeRenderEvents.add(handler);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Potentially SLOW calculation, as it compares each entry in a queue for equality
|
|
||||||
*
|
|
||||||
* @param handler this is the handler to check
|
|
||||||
*
|
|
||||||
* @return true if this handler already exists in the active render, on-frame-start queue
|
|
||||||
*/
|
|
||||||
public static
|
|
||||||
boolean containsActiveRenderFrameStart(final ActionHandlerLong handler) {
|
|
||||||
synchronized (activeRenders) {
|
|
||||||
return activeRenderEvents.contains(handler);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes the handler from the on-frame-start queue
|
|
||||||
*
|
|
||||||
* @param handler the handler to remove
|
|
||||||
*/
|
|
||||||
public static
|
|
||||||
void removeActiveRenderFrameStart(final ActionHandlerLong handler) {
|
|
||||||
synchronized (activeRenders) {
|
|
||||||
activeRenderEvents.remove(handler);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates (if necessary) the active-render thread. When there are no active-render targets, this thread will exit
|
|
||||||
*/
|
|
||||||
private static
|
|
||||||
void setupActiveRenderThread() {
|
|
||||||
if (activeRenderThread != null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
SynchronizedEventQueue.install();
|
|
||||||
|
|
||||||
activeRenderThread = new Thread(renderLoop, "AWT-ActiveRender");
|
|
||||||
activeRenderThread.setDaemon(true);
|
|
||||||
activeRenderThread.start();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,57 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2015 dorkbox, llc
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package dorkbox.util.swing;
|
|
||||||
|
|
||||||
import java.awt.AWTEvent;
|
|
||||||
import java.awt.EventQueue;
|
|
||||||
import java.awt.Toolkit;
|
|
||||||
|
|
||||||
public final
|
|
||||||
class SynchronizedEventQueue extends EventQueue {
|
|
||||||
public static final Object MUTEX = new Object();
|
|
||||||
|
|
||||||
private static final SynchronizedEventQueue instance = new SynchronizedEventQueue();
|
|
||||||
private static volatile boolean alreadyInUse = false;
|
|
||||||
|
|
||||||
public static synchronized
|
|
||||||
void install() {
|
|
||||||
if (!alreadyInUse) {
|
|
||||||
// set up the synchronized event queue
|
|
||||||
EventQueue eventQueue = Toolkit.getDefaultToolkit()
|
|
||||||
.getSystemEventQueue();
|
|
||||||
eventQueue.push(instance);
|
|
||||||
alreadyInUse = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enforce singleton property.
|
|
||||||
*/
|
|
||||||
private
|
|
||||||
SynchronizedEventQueue() {
|
|
||||||
}
|
|
||||||
|
|
||||||
protected
|
|
||||||
void dispatchEvent(AWTEvent aEvent) {
|
|
||||||
synchronized (MUTEX) {
|
|
||||||
try {
|
|
||||||
super.dispatchEvent(aEvent);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user