}
}
+ /**
+ * Check if application is still running.
+ *
+ * @return true if the application is running
+ */
+ public final boolean isRunning() {
+ if (quit == true) {
+ return false;
+ }
+ return true;
+ }
+
// ------------------------------------------------------------------------
// Screen refresh loop ----------------------------------------------------
// ------------------------------------------------------------------------
// Flush the screen contents
if ((images.size() > 0) || getScreen().isDirty()) {
+ if (debugThreads) {
+ System.err.printf("%d %s backend.flushScreen()\n",
+ System.currentTimeMillis(), Thread.currentThread());
+ }
backend.flushScreen();
}
assert (!window.isActive());
if (activeWindow != null) {
- assert (activeWindow.getZ() == 0);
+ // TODO: see if this assertion is really necessary.
+ // assert (activeWindow.getZ() == 0);
activeWindow.setActive(false);
return false;
}
+ /**
+ * Check if there is a window with overridden menu flag on top.
+ *
+ * @return true if the active window is overriding the menu
+ */
+ private boolean overrideMenuWindowActive() {
+ if (activeWindow != null) {
+ if (activeWindow.hasOverriddenMenu()) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
/**
* Close all open windows.
*/
if ((mouse.getType() == TMouseEvent.Type.MOUSE_DOWN)
&& (mouse.isMouse1())
&& (!modalWindowActive())
+ && (!overrideMenuWindowActive())
&& (mouse.getAbsoluteY() == 0)
) {
putCharXY(1 + mnemonic.getShortcutIdx(), 0,
mnemonic.getShortcut(), menuMnemonicColor);
}
-
}
}
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
+import java.util.ResourceBundle;
import javax.imageio.ImageIO;
import jexer.event.TKeypressEvent;
*/
public class TImageWindow extends TScrollableWindow {
+ /**
+ * Translated strings.
+ */
+ private static final ResourceBundle i18n = ResourceBundle.getBundle(TImageWindow.class.getName());
+
// ------------------------------------------------------------------------
// Constants --------------------------------------------------------------
// ------------------------------------------------------------------------
setBottomValue(imageField.getRows() - imageField.getHeight());
setLeftValue(0);
setRightValue(imageField.getColumns() - imageField.getWidth());
+
+ statusBar = newStatusBar(i18n.getString("statusBar"));
}
// ------------------------------------------------------------------------
--- /dev/null
+statusBar=Alt-\u2190\u2192: Rotate Left/Right Alt-\u2191\u2193: Bigger/Smaller \u2190\u2192\u2191\u2193: Pan
0, 'y', true, false, false);
public static final TKeypress kbAltZ = new TKeypress(false,
0, 'z', true, false, false);
+ public static final TKeypress kbAlt0 = new TKeypress(false,
+ 0, '0', true, false, false);
+ public static final TKeypress kbAlt1 = new TKeypress(false,
+ 0, '1', true, false, false);
+ public static final TKeypress kbAlt2 = new TKeypress(false,
+ 0, '2', true, false, false);
+ public static final TKeypress kbAlt3 = new TKeypress(false,
+ 0, '3', true, false, false);
+ public static final TKeypress kbAlt4 = new TKeypress(false,
+ 0, '4', true, false, false);
+ public static final TKeypress kbAlt5 = new TKeypress(false,
+ 0, '5', true, false, false);
+ public static final TKeypress kbAlt6 = new TKeypress(false,
+ 0, '6', true, false, false);
+ public static final TKeypress kbAlt7 = new TKeypress(false,
+ 0, '7', true, false, false);
+ public static final TKeypress kbAlt8 = new TKeypress(false,
+ 0, '8', true, false, false);
+ public static final TKeypress kbAlt9 = new TKeypress(false,
+ 0, '9', true, false, false);
public static final TKeypress kbCtrlA = new TKeypress(false,
0, 'A', false, true, false);
public static final TKeypress kbCtrlB = new TKeypress(false,
// thread.
synchronized (emulator) {
setHiddenMouse(emulator.hasHiddenMousePointer());
-
+
setCursorX(emulator.getCursorX() + 1);
setCursorY(emulator.getCursorY() + 1
+ (getHeight() - 2 - emulator.getHeight())
*/
public static final int HIDEONCLOSE = 0x40;
+ /**
+ * Menus cannot be used when this window is active (default no).
+ */
+ public static final int OVERRIDEMENU = 0x80;
+
// ------------------------------------------------------------------------
// Variables --------------------------------------------------------------
// ------------------------------------------------------------------------
return false;
}
+ /**
+ * Returns true if this window does not want menus to work while it is
+ * visible.
+ *
+ * @return true if this window does not want menus to work while it is
+ * visible
+ */
+ public final boolean hasOverriddenMenu() {
+ if ((flags & OVERRIDEMENU) != 0) {
+ return true;
+ }
+ return false;
+ }
+
/**
* Retrieve the background color.
*
int red, green, blue;
if (imageX < image.getWidth() - 1) {
int pXpY = ditheredImage.getRGB(imageX + 1, imageY);
- red = (int) ((pXpY >>> 16) & 0xFF) + (7 * redError);
- green = (int) ((pXpY >>> 8) & 0xFF) + (7 * greenError);
- blue = (int) ( pXpY & 0xFF) + (7 * blueError);
+ red = ((pXpY >>> 16) & 0xFF) + (7 * redError);
+ green = ((pXpY >>> 8) & 0xFF) + (7 * greenError);
+ blue = ( pXpY & 0xFF) + (7 * blueError);
red = clamp(red);
green = clamp(green);
blue = clamp(blue);
if (imageY < image.getHeight() - 1) {
int pXpYp = ditheredImage.getRGB(imageX + 1,
imageY + 1);
- red = (int) ((pXpYp >>> 16) & 0xFF) + redError;
- green = (int) ((pXpYp >>> 8) & 0xFF) + greenError;
- blue = (int) ( pXpYp & 0xFF) + blueError;
+ red = ((pXpYp >>> 16) & 0xFF) + redError;
+ green = ((pXpYp >>> 8) & 0xFF) + greenError;
+ blue = ( pXpYp & 0xFF) + blueError;
red = clamp(red);
green = clamp(green);
blue = clamp(blue);
int pXYp = ditheredImage.getRGB(imageX,
imageY + 1);
- red = (int) ((pXmYp >>> 16) & 0xFF) + (3 * redError);
- green = (int) ((pXmYp >>> 8) & 0xFF) + (3 * greenError);
- blue = (int) ( pXmYp & 0xFF) + (3 * blueError);
+ red = ((pXmYp >>> 16) & 0xFF) + (3 * redError);
+ green = ((pXmYp >>> 8) & 0xFF) + (3 * greenError);
+ blue = ( pXmYp & 0xFF) + (3 * blueError);
red = clamp(red);
green = clamp(green);
blue = clamp(blue);
pXmYp |= ((green & 0xFF) << 8) | (blue & 0xFF);
ditheredImage.setRGB(imageX - 1, imageY + 1, pXmYp);
- red = (int) ((pXYp >>> 16) & 0xFF) + (5 * redError);
- green = (int) ((pXYp >>> 8) & 0xFF) + (5 * greenError);
- blue = (int) ( pXYp & 0xFF) + (5 * blueError);
+ red = ((pXYp >>> 16) & 0xFF) + (5 * redError);
+ green = ((pXYp >>> 8) & 0xFF) + (5 * greenError);
+ blue = ( pXYp & 0xFF) + (5 * blueError);
red = clamp(red);
green = clamp(green);
blue = clamp(blue);
flush();
}
+ /**
+ * Resize the physical screen to match the logical screen dimensions.
+ */
+ @Override
+ public void resizeToScreen() {
+ // Send dtterm/xterm sequences, which will probably not work because
+ // allowWindowOps is defaulted to false.
+ String resizeString = String.format("\033[8;%d;%dt", getHeight(),
+ getWidth());
+ this.output.write(resizeString);
+ this.output.flush();
+ }
+
// ------------------------------------------------------------------------
// TerminalReader ---------------------------------------------------------
// ------------------------------------------------------------------------
// Check for new window size
long windowSizeDelay = nowTime - windowSizeTime;
if (windowSizeDelay > 1000) {
+ int oldTextWidth = getTextWidth();
+ int oldTextHeight = getTextHeight();
+
sessionInfo.queryWindowSize();
int newWidth = sessionInfo.getWindowWidth();
int newHeight = sessionInfo.getWindowHeight();
|| (newHeight != windowResize.getHeight())
) {
+ // Request xterm report window dimensions in pixels again.
+ // Between now and then, ensure that the reported text cell
+ // size is the same by setting widthPixels and heightPixels
+ // to match the new dimensions.
+ widthPixels = oldTextWidth * newWidth;
+ heightPixels = oldTextHeight * newHeight;
+
if (debugToStderr) {
System.err.println("Screen size changed, old size " +
windowResize);
System.err.println(" new size " +
newWidth + " x " + newHeight);
+ System.err.println(" old pixels " +
+ oldTextWidth + " x " + oldTextHeight);
+ System.err.println(" new pixels " +
+ getTextWidth() + " x " + getTextHeight());
}
- // Request xterm report window dimensions in pixels again.
this.output.printf("%s", xtermReportWindowPixelDimensions());
this.output.flush();
rgbArray = cells.get(i).getImage().getRGB(0, 0,
imageWidth, imageHeight, null, 0, imageWidth);
}
+
+ /*
+ System.err.printf("calling image.setRGB(): %d %d %d %d %d\n",
+ i * imageWidth, 0, imageWidth, imageHeight,
+ 0, imageWidth);
+ System.err.printf(" fullWidth %d fullHeight %d cells.size() %d textWidth %d\n",
+ fullWidth, fullHeight, cells.size(), getTextWidth());
+ */
+
image.setRGB(i * imageWidth, 0, imageWidth, imageHeight,
rgbArray, 0, imageWidth);
if (imageHeight < fullHeight) {
*/
public final void setDimensions(final int width, final int height) {
reallocate(width, height);
+ resizeToScreen();
+ }
+
+ /**
+ * Resize the physical screen to match the logical screen dimensions.
+ */
+ public void resizeToScreen() {
+ // Subclasses are expected to override this.
}
/**
* @param y row coordinate. 0 is the top-most row.
*/
public final void unsetImageRow(final int y) {
+ if ((y < 0) || (y >= height)) {
+ return;
+ }
for (int x = 0; x < width; x++) {
if (logical[x][y].isImage()) {
physical[x][y].unset();
*/
public void setDimensions(final int width, final int height) {
for (Screen screen: screens) {
- screen.setDimensions(width, height);
+ // Do not blindly call setDimension() on every screen. Instead
+ // call it only on those screens that do not already have the
+ // requested dimension. With this very small check, we have the
+ // ability for ANY screen in the MultiBackend to resize ALL of
+ // the screens.
+ if ((screen.getWidth() != width)
+ || (screen.getHeight() != height)
+ ) {
+ screen.setDimensions(width, height);
+ } else {
+ // The screen that didn't change is probably the one that
+ // prompted the resize. Force it to repaint.
+ screen.clearPhysical();
+ }
}
}
Insets insets = swing.getInsets();
int width = swing.getWidth() - insets.left - insets.right;
int height = swing.getHeight() - insets.top - insets.bottom;
+ // In theory, if Java reported pixel-perfect dimensions, the
+ // expressions above would precisely line up with the requested
+ // window size from SwingComponent.setDimensions(). In practice,
+ // there appears to be a small difference. Add half a text cell in
+ // both directions before the division to hopefully reach the same
+ // result as setDimensions() was supposed to give us.
+ width += (textWidth / 2);
+ height += (textHeight / 2);
windowWidth = width / textWidth;
windowHeight = height / textHeight;
}
/**
- * Resize to font dimensions.
+ * Resize the physical screen to match the logical screen dimensions.
*/
+ @Override
public void resizeToScreen() {
- swing.setDimensions(textWidth * (width + 1), textHeight * (height + 1));
+ swing.setDimensions(textWidth * width, textHeight * height);
}
/**
import jexer.event.TInputEvent;
import jexer.event.TKeypressEvent;
import jexer.event.TMouseEvent;
+import jexer.event.TResizeEvent;
import jexer.TApplication;
import jexer.TWindow;
private List<TInputEvent> eventQueue;
/**
- * The screen to use.
+ * The screen this window is monitoring.
*/
private Screen otherScreen;
+ /**
+ * The application associated with otherScreen.
+ */
+ private TApplication otherApplication;
+
/**
* The session information.
*/
private SessionInfo sessionInfo;
+ /**
+ * OtherScreen provides a hook to notify TWindowBackend of screen size
+ * changes.
+ */
+ private class OtherScreen extends LogicalScreen {
+
+ /**
+ * The TWindowBackend to notify.
+ */
+ private TWindowBackend window;
+
+ /**
+ * Public constructor.
+ */
+ public OtherScreen(final TWindowBackend window) {
+ this.window = window;
+ }
+
+ /**
+ * Resize the physical screen to match the logical screen dimensions.
+ */
+ @Override
+ public void resizeToScreen() {
+ window.setWidth(getWidth() + 2);
+ window.setHeight(getHeight() + 2);
+ }
+
+ }
+
+
// ------------------------------------------------------------------------
// Constructors -----------------------------------------------------------
// ------------------------------------------------------------------------
this.listener = listener;
eventQueue = new LinkedList<TInputEvent>();
sessionInfo = new TSessionInfo(width, height);
- otherScreen = new LogicalScreen();
+ otherScreen = new OtherScreen(this);
otherScreen.setDimensions(width - 2, height - 2);
drawLock = otherScreen;
setHiddenMouse(true);
this.listener = listener;
eventQueue = new LinkedList<TInputEvent>();
sessionInfo = new TSessionInfo(width, height);
- otherScreen = new LogicalScreen();
+ otherScreen = new OtherScreen(this);
otherScreen.setDimensions(width - 2, height - 2);
drawLock = otherScreen;
setHiddenMouse(true);
this.listener = listener;
eventQueue = new LinkedList<TInputEvent>();
sessionInfo = new TSessionInfo(width, height);
- otherScreen = new LogicalScreen();
+ otherScreen = new OtherScreen(this);
otherScreen.setDimensions(width - 2, height - 2);
drawLock = otherScreen;
setHiddenMouse(true);
this.listener = listener;
eventQueue = new LinkedList<TInputEvent>();
sessionInfo = new TSessionInfo(width, height);
- otherScreen = new LogicalScreen();
+ otherScreen = new OtherScreen(this);
otherScreen.setDimensions(width - 2, height - 2);
drawLock = otherScreen;
setHiddenMouse(true);
// Event handlers ---------------------------------------------------------
// ------------------------------------------------------------------------
+ /**
+ * Handle window/screen resize events.
+ *
+ * @param event resize event
+ */
+ @Override
+ public void onResize(final TResizeEvent event) {
+ if (event.getType() == TResizeEvent.Type.WIDGET) {
+ int newWidth = event.getWidth() - 2;
+ int newHeight = event.getHeight() - 2;
+ if ((newWidth != otherScreen.getWidth())
+ || (newHeight != otherScreen.getHeight())
+ ) {
+ // I was resized, notify the screen I am watching to match my
+ // new size.
+ synchronized (eventQueue) {
+ eventQueue.add(new TResizeEvent(TResizeEvent.Type.SCREEN,
+ newWidth, newHeight));
+ }
+ synchronized (listener) {
+ listener.notifyAll();
+ }
+ }
+ return;
+ } else {
+ super.onResize(event);
+ }
+ }
+
/**
* Returns true if the mouse is currently in the otherScreen window.
*
setCursorVisible(false);
}
}
+
+ // Check if the other application has died. If so, unset hidden
+ // mouse.
+ if (otherApplication != null) {
+ if (otherApplication.isRunning() == false) {
+ setHiddenMouse(false);
+ }
+ }
+
}
/**
return otherScreen;
}
+ /**
+ * Set the other screen's application.
+ *
+ * @param application the application driving the other screen
+ */
+ public void setOtherApplication(final TApplication application) {
+ this.otherApplication = application;
+ }
+
}
*/
package jexer.demos;
+import java.util.ResourceBundle;
+
import jexer.TApplication;
import jexer.backend.*;
import jexer.demos.DemoApplication;
*/
public class Demo6 {
+ /**
+ * Translated strings.
+ */
+ private static final ResourceBundle i18n = ResourceBundle.getBundle(Demo6.class.getName());
+
+ // ------------------------------------------------------------------------
+ // Demo6 ------------------------------------------------------------------
+ // ------------------------------------------------------------------------
+
/**
* Main entry point.
*
* eliminate) screen tearing/artifacts.
*/
TWindowBackend windowBackend = new TWindowBackend(demoApp,
- monitor, "Monitor Window", width + 2, height + 2);
+ monitor, i18n.getString("monitorWindow"),
+ width + 2, height + 2);
windowBackend.setDrawLock(multiScreen);
+ windowBackend.setOtherApplication(demoApp);
multiBackend.addBackend(windowBackend);
/*
--- /dev/null
+monitorWindow=Monitor Window
private void resetTabStops() {
tabStops.clear();
for (int i = 0; (i * 8) <= rightMargin; i++) {
- tabStops.add(new Integer(i * 8));
+ tabStops.add(Integer.valueOf(i * 8));
}
}
* @param keypress keypress received from the local user
* @return string to transmit to the remote side
*/
+ @SuppressWarnings("fallthrough")
private String keypressToString(final TKeypress keypress) {
if ((fullDuplex == false) && (!keypress.isFnKey())) {
switch (currentState.glLockshift) {
case G1_GR:
- assert (false);
+ throw new IllegalArgumentException("programming bug");
case G2_GR:
- assert (false);
+ throw new IllegalArgumentException("programming bug");
case G3_GR:
- assert (false);
+ throw new IllegalArgumentException("programming bug");
case G2_GL:
// LS2
switch (currentState.grLockshift) {
case G2_GL:
- assert (false);
+ throw new IllegalArgumentException("programming bug");
case G3_GL:
- assert (false);
+ throw new IllegalArgumentException("programming bug");
case G1_GR:
// LS1R
*/
private void param(final byte ch) {
if (csiParams.size() == 0) {
- csiParams.add(new Integer(0));
+ csiParams.add(Integer.valueOf(0));
}
Integer x = csiParams.get(csiParams.size() - 1);
if ((ch >= '0') && (ch <= '9')) {
}
if (ch == ';') {
- csiParams.add(new Integer(0));
+ csiParams.add(Integer.valueOf(0));
}
}