aboutsummaryrefslogtreecommitdiffstats
path: root/java
diff options
context:
space:
mode:
authorConstantin Kaplinsky <const@tightvnc.com>2008-05-27 08:38:28 +0000
committerConstantin Kaplinsky <const@tightvnc.com>2008-05-27 08:38:28 +0000
commitf7cb2bf231d8003fba5537563c1e32a89cb4cbfc (patch)
tree6ada00dcabad7e0484a130c784d1c758e62f05ae /java
parentcf689b3cd1317eaf4ca4f517f66f575cbe93fca7 (diff)
downloadtigervnc-f7cb2bf231d8003fba5537563c1e32a89cb4cbfc.tar.gz
tigervnc-f7cb2bf231d8003fba5537563c1e32a89cb4cbfc.zip
Support for video area selection (revision range 2467:2563 from branches/javaviewer-selectvideo) merged back to trunk.
git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@2564 3789f03b-4d11-0410-bbf8-ca57d06f2519
Diffstat (limited to 'java')
-rw-r--r--java/src/com/tightvnc/vncviewer/ButtonPanel.java33
-rw-r--r--java/src/com/tightvnc/vncviewer/RfbProto.java47
-rw-r--r--java/src/com/tightvnc/vncviewer/VncCanvas.java242
-rw-r--r--java/src/com/tightvnc/vncviewer/VncViewer.java10
4 files changed, 294 insertions, 38 deletions
diff --git a/java/src/com/tightvnc/vncviewer/ButtonPanel.java b/java/src/com/tightvnc/vncviewer/ButtonPanel.java
index bd4cbca4..422e6e2c 100644
--- a/java/src/com/tightvnc/vncviewer/ButtonPanel.java
+++ b/java/src/com/tightvnc/vncviewer/ButtonPanel.java
@@ -38,6 +38,10 @@ class ButtonPanel extends Panel implements ActionListener {
Button clipboardButton;
Button ctrlAltDelButton;
Button refreshButton;
+ Button selectButton;
+
+ final String selectEnterLabel = "Select Video Area";
+ final String selectLeaveLabel = "Hide Selection";
ButtonPanel(VncViewer v) {
viewer = v;
@@ -69,6 +73,16 @@ class ButtonPanel extends Panel implements ActionListener {
refreshButton.addActionListener(this);
}
+ /**
+ * Add video selection button to the ButtonPanel.
+ */
+ public void addSelectButton() {
+ selectButton = new Button(selectEnterLabel);
+ selectButton.setEnabled(false);
+ add(selectButton);
+ selectButton.addActionListener(this);
+ }
+
//
// Enable buttons on successful connection.
//
@@ -77,6 +91,9 @@ class ButtonPanel extends Panel implements ActionListener {
disconnectButton.setEnabled(true);
clipboardButton.setEnabled(true);
refreshButton.setEnabled(true);
+ if (selectButton != null) {
+ selectButton.setEnabled(true);
+ }
}
//
@@ -94,8 +111,9 @@ class ButtonPanel extends Panel implements ActionListener {
clipboardButton.setEnabled(false);
ctrlAltDelButton.setEnabled(false);
refreshButton.setEnabled(false);
-
- validate();
+ if (selectButton != null) {
+ selectButton.setEnabled(false);
+ }
}
//
@@ -150,6 +168,17 @@ class ButtonPanel extends Panel implements ActionListener {
} catch (IOException e) {
e.printStackTrace();
}
+ } else if (selectButton != null && evt.getSource() == selectButton) {
+ if (viewer.vc != null) {
+ boolean isSelecting = viewer.vc.isInSelectionMode();
+ if (!isSelecting) {
+ selectButton.setLabel(selectLeaveLabel);
+ viewer.vc.enableSelection(true);
+ } else {
+ selectButton.setLabel(selectEnterLabel);
+ viewer.vc.enableSelection(false);
+ }
+ }
}
}
}
diff --git a/java/src/com/tightvnc/vncviewer/RfbProto.java b/java/src/com/tightvnc/vncviewer/RfbProto.java
index 89a4caeb..39656fc9 100644
--- a/java/src/com/tightvnc/vncviewer/RfbProto.java
+++ b/java/src/com/tightvnc/vncviewer/RfbProto.java
@@ -98,10 +98,10 @@ class RfbProto {
ClientCutText = 6;
// Non-standard client-to-server messages
- final static int
- EnableContinuousUpdates = 150;
- final static String
- SigEnableContinuousUpdates = "CUC_ENCU";
+ final static int EnableContinuousUpdates = 150;
+ final static int VideoRectangleSelection = 151;
+ final static String SigEnableContinuousUpdates = "CUC_ENCU";
+ final static String SigVideoRectangleSelection = "VRECTSEL";
// Supported encodings and pseudo-encodings
final static int
@@ -499,6 +499,9 @@ class RfbProto {
clientMsgCaps.add(EnableContinuousUpdates, TightVncVendor,
SigEnableContinuousUpdates,
"Enable/disable continuous updates");
+ clientMsgCaps.add(VideoRectangleSelection, TightVncVendor,
+ SigVideoRectangleSelection,
+ "Select a rectangle to be treated as video");
// Supported encoding types
encodingCaps.add(EncodingCopyRect, StandardVendor,
@@ -1357,6 +1360,42 @@ class RfbProto {
return continuousUpdatesActive;
}
+ /**
+ * Send a rectangle selection to be treated as video by the server (but
+ * only if VideoRectangleSelection message is supported by the server).
+ * @param rect specifies coordinates and size of the rectangule.
+ * @throws java.io.IOException
+ */
+ void trySendVideoSelection(Rectangle rect) throws IOException
+ {
+ if (!clientMsgCaps.isEnabled(VideoRectangleSelection)) {
+ System.out.println("Video area selection is not supported by the server");
+ return;
+ }
+
+ int x = rect.x;
+ int y = rect.y;
+ int w = rect.width;
+ int h = rect.height;
+
+ byte[] b = new byte[10];
+
+ b[0] = (byte) VideoRectangleSelection;
+ b[1] = (byte) 0; // reserved
+ b[2] = (byte) ((x >> 8) & 0xff);
+ b[3] = (byte) (x & 0xff);
+ b[4] = (byte) ((y >> 8) & 0xff);
+ b[5] = (byte) (y & 0xff);
+ b[6] = (byte) ((w >> 8) & 0xff);
+ b[7] = (byte) (w & 0xff);
+ b[8] = (byte) ((h >> 8) & 0xff);
+ b[9] = (byte) (h & 0xff);
+
+ os.write(b);
+
+ System.out.println("Video rectangle selection message sent");
+ }
+
//
// Compress and write the data into the recorded session file. This
diff --git a/java/src/com/tightvnc/vncviewer/VncCanvas.java b/java/src/com/tightvnc/vncviewer/VncCanvas.java
index 4f8122ea..332efa38 100644
--- a/java/src/com/tightvnc/vncviewer/VncCanvas.java
+++ b/java/src/com/tightvnc/vncviewer/VncCanvas.java
@@ -121,13 +121,16 @@ class VncCanvas extends Canvas
setPixelFormat();
+ resetSelection();
+
inputEnabled = false;
if (!viewer.options.viewOnly)
enableInput(true);
- // Keyboard listener is enabled even in view-only mode, to catch
- // 'r' or 'R' key presses used to request screen update.
+ // Enable mouse and keyboard event listeners.
addKeyListener(this);
+ addMouseListener(this);
+ addMouseMotionListener(this);
}
public VncCanvas(VncViewer v) throws IOException {
@@ -173,6 +176,17 @@ class VncCanvas extends Canvas
g.drawImage(softCursor, x0, y0, null);
}
}
+ if (isInSelectionMode()) {
+ Rectangle r = getSelection(true);
+ if (r.width > 0 && r.height > 0) {
+ // Don't forget to correct the coordinates for the right and bottom
+ // borders, so that the borders are the part of the selection.
+ r.width -= 1;
+ r.height -= 1;
+ g.setXORMode(Color.yellow);
+ g.drawRect(r.x, r.y, r.width, r.height);
+ }
+ }
}
public void paintScaledFrameBuffer(Graphics g) {
@@ -213,16 +227,12 @@ class VncCanvas extends Canvas
public synchronized void enableInput(boolean enable) {
if (enable && !inputEnabled) {
inputEnabled = true;
- addMouseListener(this);
- addMouseMotionListener(this);
if (viewer.showControls) {
viewer.buttonPanel.enableRemoteAccessControls(true);
}
createSoftCursor(); // scaled cursor
} else if (!enable && inputEnabled) {
inputEnabled = false;
- removeMouseListener(this);
- removeMouseMotionListener(this);
if (viewer.showControls) {
viewer.buttonPanel.enableRemoteAccessControls(false);
}
@@ -1589,7 +1599,19 @@ class VncCanvas extends Canvas
processLocalMouseEvent(evt, true);
}
- public void processLocalKeyEvent(KeyEvent evt) {
+ //
+ // Ignored events.
+ //
+
+ public void mouseClicked(MouseEvent evt) {}
+ public void mouseEntered(MouseEvent evt) {}
+ public void mouseExited(MouseEvent evt) {}
+
+ //
+ // Actual event processing.
+ //
+
+ private void processLocalKeyEvent(KeyEvent evt) {
if (viewer.rfb != null && rfb.inNormalProtocol) {
if (!inputEnabled) {
if ((evt.getKeyChar() == 'r' || evt.getKeyChar() == 'R') &&
@@ -1619,34 +1641,36 @@ class VncCanvas extends Canvas
evt.consume();
}
- public void processLocalMouseEvent(MouseEvent evt, boolean moved) {
+ private void processLocalMouseEvent(MouseEvent evt, boolean moved) {
if (viewer.rfb != null && rfb.inNormalProtocol) {
- if (moved) {
- softCursorMove(evt.getX(), evt.getY());
- }
- if (rfb.framebufferWidth != scaledWidth) {
- int sx = (evt.getX() * 100 + scalingFactor/2) / scalingFactor;
- int sy = (evt.getY() * 100 + scalingFactor/2) / scalingFactor;
- evt.translatePoint(sx - evt.getX(), sy - evt.getY());
- }
- synchronized(rfb) {
- try {
- rfb.writePointerEvent(evt);
- } catch (Exception e) {
- e.printStackTrace();
- }
- rfb.notify();
+ if (!inSelectionMode) {
+ if (inputEnabled) {
+ sendMouseEvent(evt, moved);
+ }
+ } else {
+ handleSelectionMouseEvent(evt);
}
}
}
- //
- // Ignored events.
- //
-
- public void mouseClicked(MouseEvent evt) {}
- public void mouseEntered(MouseEvent evt) {}
- public void mouseExited(MouseEvent evt) {}
+ private void sendMouseEvent(MouseEvent evt, boolean moved) {
+ if (moved) {
+ softCursorMove(evt.getX(), evt.getY());
+ }
+ if (rfb.framebufferWidth != scaledWidth) {
+ int sx = (evt.getX() * 100 + scalingFactor/2) / scalingFactor;
+ int sy = (evt.getY() * 100 + scalingFactor/2) / scalingFactor;
+ evt.translatePoint(sx - evt.getX(), sy - evt.getY());
+ }
+ synchronized(rfb) {
+ try {
+ rfb.writePointerEvent(evt);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ rfb.notify();
+ }
+ }
//
// Reset update statistics.
@@ -1914,4 +1938,162 @@ class VncCanvas extends Canvas
cursorX - hotX, cursorY - hotY, cursorWidth, cursorHeight);
}
}
+
+ //////////////////////////////////////////////////////////////////
+ //
+ // Support for selecting a rectangular video area.
+ //
+
+ /** This flag is false in normal operation, and true in the selection mode. */
+ private boolean inSelectionMode;
+
+ /** The point where the selection was started. */
+ private Point selectionStart;
+
+ /** The second point of the selection. */
+ private Point selectionEnd;
+
+ /**
+ * We change cursor when enabling the selection mode. In this variable, we
+ * save the original cursor so we can restore it on returning to the normal
+ * mode.
+ */
+ private Cursor savedCursor;
+
+ /**
+ * Initialize selection-related varibles.
+ */
+ private synchronized void resetSelection() {
+ inSelectionMode = false;
+ selectionStart = new Point(0, 0);
+ selectionEnd = new Point(0, 0);
+
+ savedCursor = getCursor();
+ }
+
+ /**
+ * Check current state of the selection mode.
+ * @return true in the selection mode, false otherwise.
+ */
+ public boolean isInSelectionMode() {
+ return inSelectionMode;
+ }
+
+ /**
+ * Get current selection.
+ * @param useScreenCoords use screen coordinates if true, or framebuffer
+ * coordinates if false. This makes difference when scaling factor is not 100.
+ * @return The selection as a {@link Rectangle}.
+ */
+ private synchronized Rectangle getSelection(boolean useScreenCoords) {
+ int x = selectionStart.x;
+ int y = selectionStart.y;
+ int w = selectionEnd.x - selectionStart.x;
+ int h = selectionEnd.y - selectionStart.y;
+ // Make x and y point to the upper left corner of the selection.
+ boolean horizSwap = false;
+ boolean vertSwap = false;
+ if (w < 0) {
+ w = -w;
+ x = x - w;
+ horizSwap = true;
+ }
+ if (h < 0) {
+ h = -h;
+ y = y - h;
+ vertSwap = true;
+ }
+ // Make sure the borders are included in the selection.
+ if (w > 0 && h > 0) {
+ w += 1;
+ h += 1;
+ }
+ // Translate from screen coordinates to framebuffer coordinates.
+ if (rfb.framebufferWidth != scaledWidth) {
+ x = (x * 100 + scalingFactor/2) / scalingFactor;
+ y = (y * 100 + scalingFactor/2) / scalingFactor;
+ w = (w * 100 + scalingFactor/2) / scalingFactor;
+ h = (h * 100 + scalingFactor/2) / scalingFactor;
+ }
+ // Make width a multiple of 16.
+ int widthCorrection = w % 16;
+ if (widthCorrection >= 8) {
+ widthCorrection -= 16;
+ }
+ w -= widthCorrection;
+ if (horizSwap) {
+ x += widthCorrection;
+ }
+ // Make height a multiple of 8.
+ int heightCorrection = h % 8;
+ if (heightCorrection >= 4) {
+ heightCorrection -= 8;
+ }
+ h -= heightCorrection;
+ if (vertSwap) {
+ y += heightCorrection;
+ }
+ // Translate the selection back to screen coordinates if requested.
+ int clipWidth = rfb.framebufferWidth;
+ int clipHeight = rfb.framebufferHeight;
+ if (useScreenCoords && rfb.framebufferWidth != scaledWidth) {
+ x = (x * scalingFactor + 50) / 100;
+ y = (y * scalingFactor + 50) / 100;
+ w = (w * scalingFactor + 50) / 100;
+ h = (h * scalingFactor + 50) / 100;
+ clipWidth = scaledWidth;
+ clipHeight = scaledHeight;
+ }
+ // Clip the selection to screen/framebuffer and return the result.
+ Rectangle selection = new Rectangle(x, y, w, h);
+ Rectangle clip = new Rectangle(0, 0, clipWidth, clipHeight);
+ return selection.intersection(clip);
+ }
+
+ /**
+ * Enable or disable the selection mode.
+ * @param enable enables the selection mode if true, disables if fasle.
+ */
+ public synchronized void enableSelection(boolean enable) {
+ if (enable && !inSelectionMode) {
+ // Enter the selection mode.
+ inSelectionMode = true;
+ savedCursor = getCursor();
+ setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
+ repaint();
+ } else if (!enable && inSelectionMode) {
+ // Leave the selection mode.
+ inSelectionMode = false;
+ setCursor(savedCursor);
+ repaint();
+ }
+ }
+
+ /**
+ * Process mouse events in the selection mode.
+ *
+ * @param evt mouse event that was originally passed to
+ * {@link MouseListener} or {@link MouseMotionListener}.
+ */
+ private synchronized void handleSelectionMouseEvent(MouseEvent evt) {
+ int id = evt.getID();
+ boolean button1 = (evt.getModifiers() & InputEvent.BUTTON1_MASK) != 0;
+
+ if (id == MouseEvent.MOUSE_PRESSED && button1) {
+ selectionStart = selectionEnd = evt.getPoint();
+ repaint();
+ }
+ if (id == MouseEvent.MOUSE_DRAGGED && button1) {
+ selectionEnd = evt.getPoint();
+ repaint();
+ }
+ if (id == MouseEvent.MOUSE_RELEASED && button1) {
+ try {
+ rfb.trySendVideoSelection(getSelection(false));
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
}
diff --git a/java/src/com/tightvnc/vncviewer/VncViewer.java b/java/src/com/tightvnc/vncviewer/VncViewer.java
index 6fa77f85..c6fa1579 100644
--- a/java/src/com/tightvnc/vncviewer/VncViewer.java
+++ b/java/src/com/tightvnc/vncviewer/VncViewer.java
@@ -160,6 +160,11 @@ public class VncViewer extends java.applet.Applet
connectAndAuthenticate();
doProtocolInitialisation();
+ if (showControls &&
+ rfb.clientMsgCaps.isEnabled(RfbProto.VideoRectangleSelection)) {
+ buttonPanel.addSelectButton();
+ }
+
// FIXME: Use auto-scaling not only in a separate frame.
if (options.autoScale && inSeparateFrame) {
Dimension screenSize;
@@ -206,8 +211,9 @@ public class VncViewer extends java.applet.Applet
}
- if (showControls)
- buttonPanel.enableButtons();
+ if (showControls) {
+ buttonPanel.enableButtons();
+ }
moveFocusToDesktop();
processNormalProtocol();