Bug fixes
[nikiroo-utils.git] / src / jexer / TApplication.java
index f4cf2d5cb7a54a800c421e21b854b8552247725a..971f6f8fa572ff243645975966243dc9ff25f598 100644 (file)
@@ -31,6 +31,8 @@ package jexer;
 import java.io.InputStream;
 import java.io.IOException;
 import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.io.Reader;
 import java.io.UnsupportedEncodingException;
 import java.util.Collections;
 import java.util.Date;
@@ -544,6 +546,40 @@ public class TApplication implements Runnable {
         TApplicationImpl();
     }
 
+    /**
+     * Public constructor.  The backend type will be BackendType.ECMA48.
+     *
+     * @param input the InputStream underlying 'reader'.  Its available()
+     * method is used to determine if reader.read() will block or not.
+     * @param reader a Reader connected to the remote user.
+     * @param writer a PrintWriter connected to the remote user.
+     * @param setRawMode if true, set System.in into raw mode with stty.
+     * This should in general not be used.  It is here solely for Demo3,
+     * which uses System.in.
+     * @throws IllegalArgumentException if input, reader, or writer are null.
+     */
+    public TApplication(final InputStream input, final Reader reader,
+        final PrintWriter writer, final boolean setRawMode) {
+
+        backend = new ECMA48Backend(this, input, reader, writer, setRawMode);
+        TApplicationImpl();
+    }
+
+    /**
+     * Public constructor.  The backend type will be BackendType.ECMA48.
+     *
+     * @param input the InputStream underlying 'reader'.  Its available()
+     * method is used to determine if reader.read() will block or not.
+     * @param reader a Reader connected to the remote user.
+     * @param writer a PrintWriter connected to the remote user.
+     * @throws IllegalArgumentException if input, reader, or writer are null.
+     */
+    public TApplication(final InputStream input, final Reader reader,
+        final PrintWriter writer) {
+
+        this(input, reader, writer, false);
+    }
+
     /**
      * Public constructor.  This hook enables use with new non-Jexer
      * backends.
@@ -582,12 +618,13 @@ public class TApplication implements Runnable {
      * @param y row position
      */
     private void invertCell(final int x, final int y) {
-        synchronized (getScreen()) {
-            CellAttributes attr = getScreen().getAttrXY(x, y);
-            attr.setForeColor(attr.getForeColor().invert());
-            attr.setBackColor(attr.getBackColor().invert());
-            getScreen().putAttrXY(x, y, attr, false);
+        if (debugThreads) {
+            System.err.printf("invertCell() %d %d\n", x, y);
         }
+        CellAttributes attr = getScreen().getAttrXY(x, y);
+        attr.setForeColor(attr.getForeColor().invert());
+        attr.setBackColor(attr.getBackColor().invert());
+        getScreen().putAttrXY(x, y, attr, false);
     }
 
     /**
@@ -599,18 +636,23 @@ public class TApplication implements Runnable {
         }
 
         if (!repaint) {
-            if ((oldMouseX != mouseX) || (oldMouseY != mouseY)) {
-                // The only thing that has happened is the mouse moved.
-                // Clear the old position and draw the new position.
-                invertCell(oldMouseX, oldMouseY);
-                invertCell(mouseX, mouseY);
-                oldMouseX = mouseX;
-                oldMouseY = mouseY;
+            if (debugThreads) {
+                System.err.printf("drawAll() !repaint\n");
             }
-            if (getScreen().isDirty()) {
-                backend.flushScreen();
+            synchronized (getScreen()) {
+                if ((oldMouseX != mouseX) || (oldMouseY != mouseY)) {
+                    // The only thing that has happened is the mouse moved.
+                    // Clear the old position and draw the new position.
+                    invertCell(oldMouseX, oldMouseY);
+                    invertCell(mouseX, mouseY);
+                    oldMouseX = mouseX;
+                    oldMouseY = mouseY;
+                }
+                if (getScreen().isDirty()) {
+                    backend.flushScreen();
+                }
+                return;
             }
-            return;
         }
 
         if (debugThreads) {
@@ -676,6 +718,8 @@ public class TApplication implements Runnable {
 
         // Draw the mouse pointer
         invertCell(mouseX, mouseY);
+        oldMouseX = mouseX;
+        oldMouseY = mouseY;
 
         // Place the cursor if it is visible
         TWidget activeWidget = null;
@@ -694,7 +738,9 @@ public class TApplication implements Runnable {
         }
 
         // Flush the screen contents
-        backend.flushScreen();
+        if (getScreen().isDirty()) {
+            backend.flushScreen();
+        }
 
         repaint = false;
     }
@@ -726,6 +772,9 @@ public class TApplication implements Runnable {
                 // wait until either the backend or the consumer threads have
                 // something to do.
                 try {
+                    if (debugThreads) {
+                        System.err.println("sleep " + timeout + " millis");
+                    }
                     synchronized (this) {
                         this.wait(timeout);
                     }
@@ -916,20 +965,35 @@ public class TApplication implements Runnable {
         if (event instanceof TKeypressEvent) {
             TKeypressEvent keypress = (TKeypressEvent) event;
 
-            // See if this key matches an accelerator, and if so dispatch the
-            // menu event.
-            TKeypress keypressLowercase = keypress.getKey().toLowerCase();
-            TMenuItem item = null;
-            synchronized (accelerators) {
-                item = accelerators.get(keypressLowercase);
+            // See if this key matches an accelerator, and is not being
+            // shortcutted by the active window, and if so dispatch the menu
+            // event.
+            boolean windowWillShortcut = false;
+            for (TWindow window: windows) {
+                if (window.isActive()) {
+                    if (window.isShortcutKeypress(keypress.getKey())) {
+                        // We do not process this key, it will be passed to
+                        // the window instead.
+                        windowWillShortcut = true;
+                    }
+                }
             }
-            if (item != null) {
-                if (item.isEnabled()) {
-                    // Let the menu item dispatch
-                    item.dispatch();
-                    return;
+
+            if (!windowWillShortcut) {
+                TKeypress keypressLowercase = keypress.getKey().toLowerCase();
+                TMenuItem item = null;
+                synchronized (accelerators) {
+                    item = accelerators.get(keypressLowercase);
+                }
+                if (item != null) {
+                    if (item.isEnabled()) {
+                        // Let the menu item dispatch
+                        item.dispatch();
+                        return;
+                    }
                 }
             }
+
             // Handle the keypress
             if (onKeypress(keypress)) {
                 return;
@@ -1610,7 +1674,7 @@ public class TApplication implements Runnable {
      *
      * @param event new event to add to the queue
      */
-    public final void addMenuEvent(final TInputEvent event) {
+    public final void postMenuEvent(final TInputEvent event) {
         synchronized (fillEventQueue) {
             fillEventQueue.add(event);
         }
@@ -1696,11 +1760,8 @@ public class TApplication implements Runnable {
         if (activeMenu != null) {
             return;
         }
-
-        synchronized (windows) {
-            for (TWindow window: windows) {
-                closeWindow(window);
-            }
+        while (windows.size() > 0) {
+            closeWindow(windows.get(0));
         }
     }