2002/08/16 23:37:17
[org.ibex.core.git] / src / org / xwt / Surface.java
index 58339c8..e59dfc6 100644 (file)
@@ -48,6 +48,9 @@ public abstract class Surface {
     /** true iff button 3 is depressed, in MessageQueue-time */
     public static boolean button3 = false;
 
+    /** true iff all surfaces created from now on should be scarred */
+    public static boolean scarAllSurfacesFromNowOn = false;
+
 
     // Public Members and State Variables /////////////////////////////////////////////////////////
 
@@ -92,7 +95,12 @@ public abstract class Surface {
     /** the y-position of the mouse the last time a Press message was enqueued */
     int last_press_y = Integer.MAX_VALUE;
 
+    /** the last button to recieve a Click message; used for simulating DoubleClick's */
+    static int lastClickButton = 0;
 
+    /** the last time a Click message was processed; used for simulating DoubleClick's */
+    static long lastClickTime = 0;
+    
     
     // Methods to be overridden by subclasses ///////////////////////////////////////////////////////
 
@@ -132,6 +140,9 @@ public abstract class Surface {
     /** Destroy the surface */
     public abstract void _dispose();
 
+    /** Notifies the surface that limits have been imposed on the surface's size */
+    public void setLimits(int min_width, int min_height, int max_width, int max_height) { }
+
 
     // Helper methods for subclasses ////////////////////////////////////////////////////////////
 
@@ -150,7 +161,7 @@ public abstract class Surface {
             MessageQueue.add(new Message() { public void perform() {
                 Surface.this.boxContainingMouse = who;
                 Platform.clipboardReadEnabled = true;
-                root.put("Press1", null, Boolean.TRUE);
+                root.put("Press3", null, Boolean.TRUE);
                 Platform.clipboardReadEnabled = false;
             }});
         }
@@ -174,6 +185,12 @@ public abstract class Surface {
         if (button == 1) new SimpleMessage("Click1", Boolean.TRUE, root.whoIs(mousex, mousey));
         else if (button == 2) new SimpleMessage("Click2", Boolean.TRUE, root.whoIs(mousex, mousey));
         else if (button == 3) new SimpleMessage("Click3", Boolean.TRUE, root.whoIs(mousex, mousey));
+        if (Platform.needsAutoDoubleClick()) {
+            long now = System.currentTimeMillis();
+            if (lastClickButton == button && now - lastClickTime < 350) DoubleClick(button);
+            lastClickButton = button;
+            lastClickTime = now;
+        }
     }
 
     protected final void DoubleClick(int button) {
@@ -185,16 +202,16 @@ public abstract class Surface {
     /** sends a KeyPressed message; subclasses should not add the C- or A- prefixes, nor should they capitalize alphabet characters */
     protected final void KeyPressed(String key) {
         if (key == null) return;
-        
-        if (key.equals("alt")) alt = true;
+
+        if (key.toLowerCase().endsWith("shift")) shift = true;
+        else if (shift) key = key.toUpperCase();
+
+        if (key.toLowerCase().equals("alt")) alt = true;
         else if (alt) key = "A-" + key;
 
-        if (key.endsWith("control")) control = true;
+        if (key.toLowerCase().endsWith("control")) control = true;
         else if (control) key = "C-" + key;
 
-        if (key.endsWith("shift")) shift = true;
-        else if (shift) key = key.toUpperCase();
-
         final String fkey = key;
         MessageQueue.add(new KMessage(key));
     }
@@ -205,8 +222,12 @@ public abstract class Surface {
         public KMessage(String k) { key = k; }
         public void perform() {
             if (key.equals("C-v") || key.equals("A-v")) Platform.clipboardReadEnabled = true;
-            for(int i=0; i<keywatchers.size(); i++)
-                ((Box)keywatchers.elementAt(i)).put("KeyPressed", null, key);
+            outer: for(int i=0; i<keywatchers.size(); i++) {
+                Box b = (Box)keywatchers.elementAt(i);
+                for(Box cur = b; cur != null; cur = cur.getParent())
+                    if (cur.invisible) continue outer;
+                b.put("KeyPressed", null, key);
+            }
             Platform.clipboardReadEnabled = false;
         }
     }
@@ -214,12 +235,16 @@ public abstract class Surface {
     /** sends a KeyReleased message; subclasses should not add the C- or A- prefixes, nor should they capitalize alphabet characters */
     protected final void KeyReleased(final String key) {
         if (key == null) return;
-        if (key.equals("alt")) alt = false;
-        else if (key.equals("control")) control = false;
-        else if (key.equals("shift")) shift = false;
+        if (key.toLowerCase().equals("alt")) alt = false;
+        else if (key.toLowerCase().equals("control")) control = false;
+        else if (key.toLowerCase().equals("shift")) shift = false;
         MessageQueue.add(new Message() { public void perform() {
-            for(int i=0; i<keywatchers.size(); i++)
-                ((Box)keywatchers.elementAt(i)).put("KeyReleased", null, key);
+            outer: for(int i=0; i<keywatchers.size(); i++) {
+                Box b = (Box)keywatchers.elementAt(i);
+                for(Box cur = b; cur != null; cur = cur.getParent())
+                    if (cur.invisible) continue outer;
+                b.put("KeyReleased", null, key);
+            }
         }});
     }
 
@@ -287,7 +312,7 @@ public abstract class Surface {
         long lastResizeTime = (((long)lastResizeTimeTop) << 32) | (long)lastResizeTimeBottom;
         if (Platform.supressDirtyOnResize() && System.currentTimeMillis() - lastResizeTime < 100 && (w >= width - 1 || h >= height - 1)) return;
         screenDirtyRegions.dirty(x, y, w, h);
-        blitDirtyScreenRegions();
+        Refresh();
     }
 
 
@@ -305,12 +330,6 @@ public abstract class Surface {
     /** A list of all the Boxes on this Surface that should be notified of keyboard events */
     Vec keywatchers = new Vec();
 
-    /**
-     *  this is incremented every time we render; it acts as a sort of 'timestamp' to let Boxes to know if they have
-     *  been dirtied since the last rendering began (and hence should not propagate up dirty() requests from their children)
-     */
-    volatile int dirtiedTimeStamp = 0;
-
     /** When set to true, render() should abort as soon as possible and restart the rendering process */
     volatile boolean abort = false;
 
@@ -320,6 +339,8 @@ public abstract class Surface {
     /** a striped 100x100 double buffer */
     private DoubleBuffer showRenderBuf2 = null;
 
+    /** true iff this window should be scarred */
+    private boolean scarred = true;
 
 
     // Other Methods ///////////////////////////////////////////////////////////////////////////////
@@ -340,9 +361,13 @@ public abstract class Surface {
 
     /** wrapper for setSize() which makes sure to dirty the place where the scar used to be */
     void _setSize(int width, int height) {
-        dirty(hscar,
-              root.size(1) - vscar - scarPicture.getHeight(),
-              scarPicture.getWidth(), scarPicture.getHeight());
+        if (scarred) {
+            width = Math.max(width, scarPicture.getWidth());
+            height = Math.max(height, scarPicture.getHeight());
+            dirty(hscar,
+                  root.size(1) - vscar - scarPicture.getHeight(),
+                  scarPicture.getWidth(), scarPicture.getHeight());
+        }
         setSize(width, height);
         this.width = width;
         this.height = height;
@@ -372,6 +397,8 @@ public abstract class Surface {
     }
 
     public Surface(Box root) {
+        this.scarred = scarAllSurfacesFromNowOn;
+        scarAllSurfacesFromNowOn = true;
         this.root = root;
         if (root.surface != null && root.surface.root == root) root.surface.dispose();
         root.remove();
@@ -394,15 +421,13 @@ public abstract class Surface {
     /** runs the prerender() and render() pipelines in the root Box to regenerate the backbuffer, then blits it to the screen */
     public synchronized void render() {
 
-        if (++dirtiedTimeStamp == Integer.MAX_VALUE - 1) dirtiedTimeStamp = 0;
-
         // if the window size changed as a result of a user action, we have to update the root box's size
         if (root.size(0) != width || root.size(1) != height) {
 
             // since the scar will be moving, dirty the place it used to be
-            dirty(hscar,
-                  root.size(1) - vscar - scarPicture.getHeight(),
-                  scarPicture.getWidth(), scarPicture.getHeight());
+            if (scarred) dirty(hscar,
+                               root.size(1) - vscar - scarPicture.getHeight(),
+                               scarPicture.getWidth(), scarPicture.getHeight());
 
             // sort of ugly; we can't use set() here because it will cause an infinite mutual recursion
             root._size_0 = (short)width;
@@ -449,7 +474,7 @@ public abstract class Surface {
             root.render(x, y, w, h, backbuffer);
             
             // if any area under the scar was repainted, rescar that area
-            if (x < hscar + scarPicture.getWidth() &&
+            if (scarred && x < hscar + scarPicture.getWidth() &&
                 y + h > height - scarPicture.getHeight() - vscar) {
                 int _x1 = Math.max(x, hscar);
                 int _x2 = Math.min(x + w, hscar + scarPicture.getWidth());
@@ -548,11 +573,11 @@ public abstract class Surface {
     }
 
     // FEATURE: reinstate recycler
-    private class SimpleMessage implements Message {
+    public class SimpleMessage implements Message {
         
         private Box boxContainingMouse;
         private Object value;
-        private String name;
+        public String name;
         
         SimpleMessage(String name, Object value, Box boxContainingMouse) {
             this.boxContainingMouse = boxContainingMouse;