// FIXME update these
// box properties can not be trapped
static final String[] props = new String[] {
- "fill", "stroke", "image", "tile", "fixedaspect", "text", "path", "font",
"shrink", "hshrink", "vshrink", "x", "y", "width", "height", "cols", "rows",
- "colspan", "rowspan", "align", "visible", "absolute", "globalx", "globaly",
- "minwidth", "maxwidth", "minheight", "maxheight",
- "numchildren", "redirect", "cursor", "mousex", "mousey", "xwt", "static",
- "mouseinside", "root", "thisbox", "indexof"
+ "colspan", "rowspan", "align", "visible", "packed", "globalx", "globaly",
+ "minwidth", "maxwidth", "minheight", "maxheight", "indexof", "thisbox", "clip",
+ "numchildren", "redirect", "cursor", "mouse", "surface"
};
// FIXME update these
case "aspect": return N(aspect);
case "x": return (parent == null || !test(VISIBLE)) ? N(0) : N(x);
case "y": return (parent == null || !test(VISIBLE)) ? N(0) : N(y);
- case "width": return N(width);
- case "height": return N(height);
case "cols": return test(FIXED) == COLS ? N(cols) : N(0);
case "rows": return test(FIXED) == ROWS ? N(rows) : N(0);
case "colspan": return N(colspan);
case "rowspan": return N(rowspan);
+ case "width": return N(width);
+ case "height": return N(height);
+ case "minwidth": return N(minwidth);
+ case "maxwidth": return N(maxwidth);
+ case "minheight": return N(minheight);
+ case "maxheight": return N(maxheight);
case "clip": return B(test(CLIP));
case "visible": return B(test(VISIBLE) && (parent == null || (parent.get("visible") == T)));
case "packed": return B(test(PACKED));
throw new JSExn("you cannot read from the box.mouse property in background thread context");
return new Mouse();
case "numchildren": return redirect == null ? N(0) : redirect == this ? N(treeSize()) : redirect.get("numchildren");
- case "minwidth": return N(minwidth);
- case "maxwidth": return N(maxwidth);
- case "minheight": return N(minheight);
- case "maxheight": return N(maxheight);
case "redirect": return redirect == null ? null : redirect == this ? T : redirect.get("redirect");
case "Minimized": if (parent == null && getSurface() != null) return B(getSurface().minimized);
default: return super.get(name);
case "Minimized": if (parent == null && getSurface() != null) getSurface().minimized = toBoolean(value); // FEATURE
case "Maximized": if (parent == null && getSurface() != null) getSurface().maximized = toBoolean(value); // FEATURE
case "Close": if (parent == null && getSurface() != null) getSurface().dispose(true);
- case "toback": if (parent == null && getSurface() != null && toBoolean(value)) { getSurface().toBack(); }
- case "tofront": if (parent == null && getSurface() != null && toBoolean(value)) { getSurface().toFront(); }
case "redirect": if (redirect == this) redirect = (Box)value; else Log.info(this, "redirect can only be set once");
case "font": font = value == null ? null : Font.getFont((Stream)value, font == null ? 10 : font.pointsize); MARK_RESIZE; dirty();
case "fontsize": font = Font.getFont(font == null ? null : font.res, toInt(value)); MARK_RESIZE; dirty();
public static Task current() { return current; }
/** synchronizd so that we can safely call it from an event-delivery thread, in-context */
- public static synchronized void renderAll() {
- for(int i=0; i<Surface.allSurfaces.size(); i++) {
- Surface s = ((Surface)Surface.allSurfaces.elementAt(i));
- do { s.render(); } while(s.abort);
+ private static volatile boolean rendering = false;
+ private static volatile boolean again = false;
+ public static void renderAll() {
+ if (rendering) { again = true; return; }
+ synchronized(Scheduler.class) {
+ try {
+ rendering = true;
+ do {
+ again = false;
+ for(int i=0; i<Surface.allSurfaces.size(); i++) {
+ Surface s = ((Surface)Surface.allSurfaces.elementAt(i));
+ do { s.render(); } while(s.abort);
+ }
+ } while(again);
+ } finally {
+ rendering = false;
+ }
}
}
volatile boolean abort = false;
volatile int pendingWidth = -1;
volatile int pendingHeight = -1;
+ volatile int actualWidth = -1;
+ volatile int actualHeight = -1;
public static boolean alt = false; ///< true iff the alt button is pressed down, in real time
public static boolean control = false; ///< true iff the control button is pressed down, in real time
public abstract void _dispose(); ///< Destroy the surface
public void setLimits(int min_width, int min_height, int max_width, int max_height) { /* FIXME */ }
+ protected void setSize(int w, int h) {
+ if (w == actualWidth && h == actualHeight) return;
+ actualWidth = w;
+ actualHeight = h;
+ _setSize(w, h);
+ }
// Helper methods for subclasses ////////////////////////////////////////////////////////////
/** subclasses should invoke this method when the user resizes the window */
protected final void SizeChange(final int width, final int height) {
- pendingWidth = width;
- pendingHeight = height;
- Refresh();
- Scheduler.add(new Scheduler.Task() { public void perform() { }});
+ if (pendingWidth == width && pendingHeight == height) return;
+ actualWidth = pendingWidth = width;
+ actualHeight = pendingHeight = height;
+ abort = true;
+ Scheduler.renderAll();
}
// FEATURE: can we avoid creating objects here?
protected final void Minimized(boolean b) { minimized = b; new SimpleMessage("Minimized", b ? T : F, root); }
protected final void Maximized(boolean b) { maximized = b; new SimpleMessage("Maximized", b ? T : F, root); }
protected final void Focused(boolean b) { new SimpleMessage("Focused", b ? T : F, root); }
- public void Refresh() { abort = true; }
+ public void Refresh() { Scheduler.add(new Scheduler.Task() { public void perform() { } }); }
public final void setMaximized(boolean b) { if (b != maximized) _setMaximized(maximized = b); }
public final void setMinimized(boolean b) { if (b != minimized) _setMinimized(minimized = b); }
/** runs the prerender() and render() pipelines in the root Box to regenerate the backbuffer, then blits it to the screen */
public synchronized void render() {
+
// make sure the root is properly sized
do {
abort = false;
root.repack();
if (pendingWidth != -1) root.setMaxWidth(JS.N(pendingWidth));
if (pendingHeight != -1) root.setMaxHeight(JS.N(pendingHeight));
- // dirty the place where the scar used to be in case the root window size was programmatically changed
- if (root.maxwidth != root.width || root.maxheight != root.height)
- root.dirty(0, root.height - Main.scarImage.height, Main.scarImage.width, Main.scarImage.height);
+ if (root.maxwidth != root.width || root.maxheight != root.height) {
+ // dirty the place where the scar used to be and where it is now
+ dirty(0, root.height - Main.scarImage.height, Main.scarImage.width, Main.scarImage.height);
+ dirty(0, root.maxheight - Main.scarImage.height, Main.scarImage.width, Main.scarImage.height);
+ }
root.resize(root.x, root.y, root.maxwidth, root.maxheight);
root.resize_children();
- _setSize(root.width, root.height);
+ setSize(root.width, root.height);
String oldcursor = cursor;
cursor = "default";
root.putAndTriggerTrapsAndCatchExceptions("_Move", JS.T);
if (w <= 0 || h <= 0) continue;
root.render(0, 0, x, y, x + w, y + h, this, identity);
- drawPicture(Main.scarImage, 0, root.height - Main.scarImage.height, x, y, w, h);
+ drawPicture(Main.scarImage, 0, root.height - Main.scarImage.height, x, y, x+w, y+h);
if (abort) {
// Static data/methods ///////////////////////////////////////////////////////////////////
+ // FIXME need to provide the XWT object too
public static Template getTemplate(Stream r) throws JSExn {
try {
r = r.addExtension(".xwt");
componentResized(window.getWidth() - insets.left - insets.right, window.getHeight() - insets.top - insets.bottom);
}
- public void componentResized(int newwidth, int newheight) {
- int oldwidth = root.width;
- int oldheight = root.height;
- SizeChange(newwidth, newheight);
- }
+ public void componentResized(int newwidth, int newheight) { SizeChange(newwidth, newheight); }
public void keyTyped(KeyEvent k) { }
public void keyPressed(KeyEvent k) { KeyPressed(translateKey(k)); }