Use internal SNAPSHOT couplings again
[trakem2.git] / TrakEM2_ / src / main / java / ini / trakem2 / display / AbstractRepaintThread.java
bloba1c7928d407d496ed0c294a910cb96e0459a72b5
1 /**
3 TrakEM2 plugin for ImageJ(C).
4 Copyright (C) 2007-2009 Albert Cardona and Rodney Douglas.
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation (http://www.gnu.org/licenses/gpl.txt )
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 You may contact Albert Cardona at acardona at ini.phys.ethz.ch
20 Institute of Neuroinformatics, University of Zurich / ETH, Switzerland.
21 **/
23 package ini.trakem2.display;
25 import ini.trakem2.utils.CachingThread;
27 import java.awt.Component;
28 import java.awt.Rectangle;
29 import java.util.LinkedList;
31 public abstract class AbstractRepaintThread extends CachingThread {
33 final protected AbstractOffscreenThread off;
34 private final java.util.List<PaintEvent> events = new LinkedList<PaintEvent>();
35 private final Component target;
37 public AbstractRepaintThread(final Component target, final String name, final AbstractOffscreenThread off) {
38 super(name);
39 this.target = target;
40 this.off = off;
41 setPriority(Thread.NORM_PRIORITY + 1);
42 try { setDaemon(true); } catch (Exception e) { e.printStackTrace(); }
43 start();
46 private class PaintEvent {
47 final Rectangle clipRect;
48 final boolean update_graphics;
49 PaintEvent(final Rectangle clipRect, final boolean update_graphics) {
50 this.clipRect = clipRect;
51 this.update_graphics = update_graphics; // java is sooo verbose... this class is just a tuple!
55 /** Queue a new request for painting, updating offscreen graphics. */
56 public final void paint(final Rectangle clipRect) {
57 paint(clipRect, true);
60 /** Queue a new request for painting. */
61 public void paint(final Rectangle clipRect, final boolean update_graphics) {
62 //Utils.log2("update_graphics: " + update_graphics);
63 //Utils.printCaller(this, 5);
64 // queue the event and signal a repaint request
65 synchronized (events) {
66 events.add(new PaintEvent(clipRect, update_graphics));
67 events.notifyAll();
71 /** Will gracefully kill this thread by breaking its infinite wait-for-event loop, and also call cancel on all registered offscreen threads. */
72 public void quit() {
73 interrupt();
74 // notify and finish
75 synchronized (events) {
76 events.notifyAll();
79 off.quit();
82 public void run() {
83 while (!isInterrupted()) {
84 try {
85 // wait until anyone issues a repaint event
86 synchronized (events) {
87 while (0 == events.size()) {
88 if (isInterrupted()) return;
89 try { events.wait(); } catch (InterruptedException ie) {}
93 if (isInterrupted()) {
94 return;
97 // wait a bit to catch fast subsequent events
98 // 10 miliseconds
99 try { Thread.sleep(10); } catch (InterruptedException ie) {}
101 // obtain all events up to now and clear the event queue
102 final PaintEvent[] pe;
103 synchronized (events) {
104 pe = new PaintEvent[events.size()];
105 events.toArray(pe);
106 events.clear();
108 if (0 == pe.length) {
109 continue;
112 // obtain repaint parameters from merged events
113 Rectangle clipRect = pe[0].clipRect;
114 boolean update_graphics = pe[0].update_graphics;
115 for (int i=1; i<pe.length; i++) {
116 if (null != clipRect) {
117 if (null == pe[i].clipRect) clipRect = null; // all
118 else clipRect.add(pe[i].clipRect);
119 } // else 'null' clipRect means repaint the entire canvas
120 if (!update_graphics) update_graphics = pe[i].update_graphics;
121 else if (null == clipRect) break;
124 // issue an offscreen thread if necessary
125 if (update_graphics) {
126 handleUpdateGraphics(target, clipRect);
129 // repaint
131 if (null == clipRect) target.repaint(0, 0, 0, target.getWidth(), target.getHeight()); // using super.repaint() causes infinite thread loops in the IBM-1.4.2-ppc
132 else target.repaint(0, clipRect.x, clipRect.y, clipRect.width, clipRect.height);
135 // Crazy idea: paint NOW
136 final java.awt.Graphics g = target.getGraphics();
137 if (null != g) {
138 // Ensure full clip rect
139 g.setClip(0, 0, target.getWidth(), target.getHeight());
140 target.paint(g);
141 g.dispose();
143 } catch (Throwable t) {
144 t.printStackTrace();
149 /** Child classes need to extend this method for handling the need of recreating offscreen images. */
150 abstract protected void handleUpdateGraphics(Component target, Rectangle clipRect);
152 /** Waits until the offscreen thread is finished with the current cycle. */
153 public void waitForOffs() {
154 off.waitOnRepaintCycle();