/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2009-2013 Pierre Ossman <ossman@cendio.se> for Cendio AB
* Copyright (C) 2011-2013 D. R. Commander. All Rights Reserved.
- * Copyright (C) 2011-2013 Brian P. Hinz
+ * Copyright (C) 2011-2014 Brian P. Hinz
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
import com.tigervnc.network.Socket;
import com.tigervnc.network.TcpSocket;
-public class CConn extends CConnection
- implements UserPasswdGetter, UserMsgBox, OptionsDialogCallback, FdInStreamBlockCallback
-{
+public class CConn extends CConnection implements
+ UserPasswdGetter, UserMsgBox, OptionsDialogCallback,
+ FdInStreamBlockCallback, ActionListener {
public final PixelFormat getPreferredPF() { return fullColourPF; }
static final PixelFormat verylowColourPF =
cp.setPF(pendingPF);
pendingPFChange = false;
- recreateViewport();
+ if (viewer.embed.getValue()) {
+ desktop.setScaledSize();
+ setupEmbeddedFrame();
+ } else {
+ recreateViewport();
+ }
+ }
+
+ void setupEmbeddedFrame() {
+ UIManager.getDefaults().put("ScrollPane.ancestorInputMap",
+ new UIDefaults.LazyInputMap(new Object[]{}));
+ JScrollPane sp = new JScrollPane();
+ sp.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
+ sp.getViewport().setBackground(Color.BLACK);
+ InputMap im = sp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
+ int ctrlAltShiftMask = Event.SHIFT_MASK | Event.CTRL_MASK | Event.ALT_MASK;
+ if (im != null) {
+ im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, ctrlAltShiftMask),
+ "unitScrollUp");
+ im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, ctrlAltShiftMask),
+ "unitScrollDown");
+ im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, ctrlAltShiftMask),
+ "unitScrollLeft");
+ im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, ctrlAltShiftMask),
+ "unitScrollRight");
+ im.put(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, ctrlAltShiftMask),
+ "scrollUp");
+ im.put(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, ctrlAltShiftMask),
+ "scrollDown");
+ im.put(KeyStroke.getKeyStroke(KeyEvent.VK_HOME, ctrlAltShiftMask),
+ "scrollLeft");
+ im.put(KeyStroke.getKeyStroke(KeyEvent.VK_END, ctrlAltShiftMask),
+ "scrollRight");
+ }
+ sp.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
+ sp.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
+ sp.getViewport().setView(desktop);
+ viewer.getContentPane().removeAll();
+ viewer.add(sp);
+ viewer.addFocusListener(new FocusAdapter() {
+ public void focusGained(FocusEvent e) {
+ if (desktop.isAncestorOf(viewer))
+ desktop.requestFocus();
+ }
+ public void focusLost(FocusEvent e) {
+ releaseModifiers();
+ }
+ });
+ viewer.validate();
+ desktop.requestFocus();
}
// setDesktopSize() is called when the desktop size changes (including when
return;
desktop.resize();
- recreateViewport();
+ if (viewer.embed.getValue()) {
+ desktop.setScaledSize();
+ setupEmbeddedFrame();
+ } else {
+ recreateViewport();
+ }
+ }
+
+ public void setEmbeddedFeatures(boolean s) {
+ menu.fullScreen.setEnabled(s);
+ menu.newConn.setEnabled(s);
+ options.fullScreen.setEnabled(s);
+ options.scalingFactor.setEnabled(s);
}
// recreateViewport() recreates our top-level window. This seems to be
// better than attempting to resize the existing window, at least with
// various X window managers.
- private void recreateViewport()
- {
+ public void recreateViewport() {
+ if (viewer.embed.getValue())
+ return;
if (viewport != null) viewport.dispose();
viewport = new Viewport(cp.name(), this);
viewport.setUndecorated(fullScreen);
desktop.requestFocusInWindow();
}
- private void reconfigureViewport()
- {
+ private void reconfigureViewport() {
//viewport.setMaxSize(cp.width, cp.height);
boolean pack = true;
Dimension dpySize = viewport.getToolkit().getScreenSize();
// close() shuts down the socket, thus waking up the RFB thread.
public void close() {
+ if (closeListener != null) {
+ viewer.embed.setParam(true);
+ if (VncViewer.nViewers == 1) {
+ JFrame f = (JFrame)JOptionPane.getFrameForComponent(viewer);
+ if (f != null)
+ f.dispatchEvent(new WindowEvent(f, WindowEvent.WINDOW_CLOSING));
+ }
+ }
deleteWindow();
shuttingDown = true;
try {
JOptionPane op =
new JOptionPane(msg, JOptionPane.INFORMATION_MESSAGE,
JOptionPane.DEFAULT_OPTION, VncViewer.logoIcon);
- JDialog dlg = op.createDialog("About TigerVNC Viewer for Java");
+ JDialog dlg = op.createDialog(desktop, "About TigerVNC Viewer for Java");
dlg.setIconImage(VncViewer.frameIcon);
dlg.setVisible(true);
if (fullScreenWindow != null)
csecurity.description());
JOptionPane op = new JOptionPane(msg, JOptionPane.PLAIN_MESSAGE,
JOptionPane.DEFAULT_OPTION);
- JDialog dlg = op.createDialog("VNC connection info");
+ JDialog dlg = op.createDialog(desktop, "VNC connection info");
dlg.setIconImage(VncViewer.frameIcon);
dlg.setVisible(true);
if (fullScreenWindow != null)
}
public void toggleFullScreen() {
+ if (viewer.embed.getValue())
+ return;
fullScreen = !fullScreen;
menu.fullScreen.setSelected(fullScreen);
if (viewport != null) {
writeKeyEvent(Keysyms.Super_R, true);
}
+ // this is a special ActionListener passed in by the
+ // Java Plug-in software to control applet's close behavior
+ public void setCloseListener(ActionListener cl) {
+ closeListener = cl;
+ }
+
+ public void actionPerformed(ActionEvent e) {}
////////////////////////////////////////////////////////////////////
// The following methods are called from both RFB and GUI threads
private boolean autoSelect;
boolean fullScreen;
private HashMap<Integer, Integer> downKeySym;
+ public ActionListener closeListener = null;
static LogWriter vlog = new LogWriter("CConn");
}
* Copyright (C) 2006 Constantin Kaplinsky. All Rights Reserved.
* Copyright (C) 2009 Paul Donohue. All Rights Reserved.
* Copyright (C) 2010, 2012-2013 D. R. Commander. All Rights Reserved.
- * Copyright (C) 2011-2013 Brian P. Hinz
+ * Copyright (C) 2011-2014 Brian P. Hinz
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
public void mouseReleased(MouseEvent e) { mouseCB(e); }
public void mousePressed(MouseEvent e) { mouseCB(e); }
public void mouseClicked(MouseEvent e) {}
- public void mouseEntered(MouseEvent e) {}
+ public void mouseEntered(MouseEvent e) {
+ if (cc.viewer.embed.getValue())
+ requestFocus();
+ }
public void mouseExited(MouseEvent e) {}
// MouseWheel callback function
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- * Copyright (C) 2011 Brian P. Hinz
+ * Copyright (C) 2011-2014 Brian P. Hinz
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
fullScreen.setMnemonic(KeyEvent.VK_F);
fullScreen.setSelected(cc.fullScreen);
fullScreen.addActionListener(this);
+ fullScreen.setEnabled(!cc.viewer.embed.getValue());
add(fullScreen);
addSeparator();
clipboard = addMenuItem("Clipboard...");
refresh = addMenuItem("Refresh Screen", KeyEvent.VK_H);
addSeparator();
newConn = addMenuItem("New connection...", KeyEvent.VK_W);
+ newConn.setEnabled(!cc.viewer.embed.getValue());
options = addMenuItem("Options...", KeyEvent.VK_O);
save = addMenuItem("Save connection info as...", KeyEvent.VK_S);
info = addMenuItem("Connection info...", KeyEvent.VK_I);
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- * Copyright (C) 2011-2012 Brian P. Hinz
+ * Copyright (C) 2011-2014 Brian P. Hinz
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
// Static variables
static LogWriter vlog = new LogWriter("OptionsDialog");
- OptionsDialogCallback cb;
+ CConn cc;
JPanel FormatPanel, InputsPanel, MiscPanel, DefaultsPanel, SecPanel;
JCheckBox autoSelect, customCompressLevel, noJpeg;
@SuppressWarnings({"rawtypes"})
JButton cfLoadButton, cfSaveAsButton, defSaveButton, defReloadButton, defClearButton;
@SuppressWarnings({"rawtypes","unchecked"})
- public OptionsDialog(OptionsDialogCallback cb_) {
+ public OptionsDialog(CConn cc_) {
super(true);
- cb = cb_;
+ cc = cc_;
setResizable(false);
setTitle("VNC Viewer Options");
fullScreen = new JCheckBox("Full-screen mode");
fullScreen.addItemListener(this);
+ fullScreen.setEnabled(!cc.viewer.embed.getValue());
shared = new JCheckBox("Shared connection (do not disconnect other viewers)");
shared.addItemListener(this);
useLocalCursor = new JCheckBox("Render cursor locally");
}
scalingFactor.setEditable(true);
scalingFactor.addItemListener(this);
+ scalingFactor.setEnabled(!cc.viewer.embed.getValue());
addGBComponent(fullScreen,MiscPanel, 0, 0, 2, 1, 2, 2, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(4,5,0,5));
addGBComponent(shared,MiscPanel, 0, 1, 2, 1, 2, 2, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(4,5,0,5));
addGBComponent(useLocalCursor,MiscPanel, 0, 2, 2, 1, 2, 2, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(4,5,0,5));
addGBComponent(configPanel,DefaultsPanel, 0, 0, 1, GridBagConstraints.REMAINDER, 0, 0, 1, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.PAGE_START, new Insets(4,5,4,5));
addGBComponent(defaultsPanel,DefaultsPanel, 1, 0, 1, GridBagConstraints.REMAINDER, 0, 0, 1, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.PAGE_START, new Insets(4,0,4,5));
- //defReloadButton.setEnabled(!applet);
// security tab
SecPanel=new JPanel(new GridBagLayout());
}
public void initDialog() {
- if (cb != null) cb.setOptions();
+ if (cc != null) cc.setOptions();
zrle.setEnabled(!autoSelect.isSelected());
hextile.setEnabled(!autoSelect.isSelected());
tight.setEnabled(!autoSelect.isSelected());
public void endDialog() {
super.endDialog();
- CConn cc = (CConn)cb;
if (cc.viewport != null && cc.viewport.isVisible()) {
cc.viewport.toFront();
cc.viewport.requestFocus();
public void actionPerformed(ActionEvent e) {
Object s = e.getSource();
if (s instanceof JButton && (JButton)s == okButton) {
- if (cb != null) cb.getOptions();
+ if (cc != null) cc.getOptions();
endDialog();
} else if (s instanceof JButton && (JButton)s == cancelButton) {
endDialog();
String filename = fc.getSelectedFile().toString();
if (filename != null)
Configuration.load(filename);
- cb.setOptions();
+ cc.setOptions();
}
} else if (s instanceof JButton && (JButton)s == cfSaveAsButton) {
JFileChooser fc = new JFileChooser();
restorePreferences();
} else if (s instanceof JButton && (JButton)s == defClearButton) {
UserPreferences.clear();
- cb.setOptions();
+ cc.setOptions();
} else if (s instanceof JButton && (JButton)s == ca) {
JFileChooser fc = new JFileChooser(new File(CSecurityTLS.getDefaultCA()));
fc.setDialogTitle("Path to X509 CA certificate");
Copyright (C) 2005 Martin Koegler
Copyright (C) 2009 Pierre Ossman for Cendio AB
Copyright (C) 2009-2013 TigerVNC Team
+ Copyright (C) 2011-2014 Brian P. Hinz
All rights reserved.
This software is distributed under the GNU General Public Licence as
Java Viewer by simply copying a new version of VncViewer.jar and/or
index.vnc into the VNC classes directory.
+ On Windows and Linux, the embedded applet can be drag-undocked from the
+ browser window and converted to a standalone application. The drag
+ gesture ALT+drag on Windows, and SHIFT+drag on Linux.
+
In the case of the Windows TigerVNC Server, VncViewer.jar and index.vnc
are embedded as resources in the WinVNC executable, so deploying a
modified version of the TigerVNC Java Viewer on a Windows server requires
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- * Copyright (C) 2011-2013 Brian P. Hinz
+ * Copyright (C) 2011-2014 Brian P. Hinz
* Copyright (C) 2012-2013 D. R. Commander. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
if (VncViewer.nViewers == 1) {
- cc.viewer.exit(1);
+ if (cc.closeListener != null) {
+ cc.close();
+ } else {
+ cc.viewer.exit(1);
+ }
} else {
cc.close();
}
}
public static Window getFullScreenWindow() {
- GraphicsEnvironment ge =
- GraphicsEnvironment.getLocalGraphicsEnvironment();
- GraphicsDevice gd = ge.getDefaultScreenDevice();
- Window fullScreenWindow = gd.getFullScreenWindow();
- return fullScreenWindow;
+ GraphicsEnvironment ge =
+ GraphicsEnvironment.getLocalGraphicsEnvironment();
+ GraphicsDevice gd = ge.getDefaultScreenDevice();
+ Window fullScreenWindow = gd.getFullScreenWindow();
+ return fullScreenWindow;
}
public static void setFullScreenWindow(Window fullScreenWindow) {
- GraphicsEnvironment ge =
- GraphicsEnvironment.getLocalGraphicsEnvironment();
- GraphicsDevice gd = ge.getDefaultScreenDevice();
- if (gd.isFullScreenSupported())
- gd.setFullScreenWindow(fullScreenWindow);
+ GraphicsEnvironment ge =
+ GraphicsEnvironment.getLocalGraphicsEnvironment();
+ GraphicsDevice gd = ge.getDefaultScreenDevice();
+ if (gd.isFullScreenSupported())
+ gd.setFullScreenWindow(fullScreenWindow);
}
CConn cc;
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2011 Pierre Ossman <ossman@cendio.se> for Cendio AB
* Copyright (C) 2011-2013 D. R. Commander. All Rights Reserved.
- * Copyright (C) 2011-2013 Brian P. Hinz
+ * Copyright (C) 2011-2014 Brian P. Hinz
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
package com.tigervnc.vncviewer;
import java.awt.*;
+import java.awt.event.*;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import com.tigervnc.rfb.*;
import com.tigervnc.network.*;
-public class VncViewer extends java.applet.Applet implements Runnable
-{
+public class VncViewer extends javax.swing.JApplet
+ implements Runnable, ActionListener {
+
public static final String aboutText = new String("TigerVNC Java Viewer v%s (%s)%n"+
"Built on %s at %s%n"+
"Copyright (C) 1999-2013 TigerVNC Team and many others (see README.txt)%n"+
public VncViewer(String[] argv) {
- applet = false;
+ embed.setParam(false);
// load user preferences
UserPreferences.load("global");
public VncViewer() {
UserPreferences.load("global");
- applet = true;
+ embed.setParam(true);
}
public static void newViewer(VncViewer oldViewer, Socket sock, boolean close) {
VncViewer viewer = new VncViewer();
- viewer.applet = oldViewer.applet;
+ viewer.embed.setParam(oldViewer.embed.getValue());
viewer.sock = sock;
viewer.start();
if (close)
newViewer(oldViewer, null);
}
+ public boolean isAppletDragStart(MouseEvent e) {
+ if(e.getID() == MouseEvent.MOUSE_DRAGGED) {
+ // Drag undocking on Mac works, but introduces a host of
+ // problems so disable it for now.
+ if (os.startsWith("mac os x"))
+ return false;
+ else if (os.startsWith("windows"))
+ return (e.getModifiersEx() & MouseEvent.ALT_DOWN_MASK) != 0;
+ else
+ return (e.getModifiersEx() & MouseEvent.SHIFT_DOWN_MASK) != 0;
+ } else {
+ return false;
+ }
+ }
+
+ public void appletDragStarted() {
+ embed.setParam(false);
+ cc.recreateViewport();
+ JFrame f = (JFrame)JOptionPane.getFrameForComponent(this);
+ // The default JFrame created by the drag event will be
+ // visible briefly between appletDragStarted and Finished.
+ if (f != null)
+ f.setSize(0, 0);
+ }
+
+ public void appletDragFinished() {
+ cc.setEmbeddedFeatures(true);
+ JFrame f = (JFrame)JOptionPane.getFrameForComponent(this);
+ if (f != null)
+ f.dispose();
+ }
+
+ public void setAppletCloseListener(ActionListener cl) {
+ cc.setCloseListener(cl);
+ }
+
+ public void appletRestored() {
+ cc.setEmbeddedFeatures(false);
+ cc.setCloseListener(null);
+ }
+
public void init() {
vlog.debug("init called");
+ Container parent = getParent();
+ while (!parent.isFocusCycleRoot()) {
+ parent = parent.getParent();
+ }
+ ((Frame)parent).setModalExclusionType(null);
+ parent.setFocusable(false);
+ parent.setFocusTraversalKeysEnabled(false);
setLookAndFeel();
setBackground(Color.white);
}
public void start() {
vlog.debug("start called");
getTimestamp();
- if (applet && nViewers == 0) {
+ if (embed.getValue() && nViewers == 0) {
alwaysShowServerDialog.setParam(true);
Configuration.global().readAppletParams(this);
+ fullScreen.setParam(false);
+ scalingFactor.setParam("100");
String host = getCodeBase().getHost();
if (vncServerName.getValue() == null && vncServerPort.getValue() != 0) {
int port = vncServerPort.getValue();
nViewers--;
if (nViewers > 0)
return;
- if (applet) {
+ if (embed.getValue())
destroy();
- } else {
+ else
System.exit(n);
- }
}
- public void paint(Graphics g) {
- g.drawImage(logoImage, 0, 0, this);
- int h = logoImage.getHeight(this)+20;
- g.drawString(String.format(aboutText, version, build,
- buildDate, buildTime), 0, h);
+ // If "Reconnect" button is pressed
+ public void actionPerformed(ActionEvent e) {
+ getContentPane().removeAll();
+ start();
}
+ void reportException(java.lang.Exception e) {
+ String title, msg = e.getMessage();
+ int msgType = JOptionPane.ERROR_MESSAGE;
+ title = "TigerVNC Viewer : Error";
+ e.printStackTrace();
+ if (embed.getValue()) {
+ getContentPane().removeAll();
+ JLabel label = new JLabel("<html><center><b>" + title + "</b><p><i>" +
+ msg + "</i></center></html>", JLabel.CENTER);
+ label.setFont(new Font("Helvetica", Font.PLAIN, 24));
+ label.setMaximumSize(new Dimension(getSize().width, 100));
+ label.setVerticalAlignment(JLabel.CENTER);
+ label.setAlignmentX(Component.CENTER_ALIGNMENT);
+ JButton button = new JButton("Reconnect");
+ button.addActionListener(this);
+ button.setMaximumSize(new Dimension(200, 30));
+ button.setAlignmentX(Component.CENTER_ALIGNMENT);
+ setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
+ add(label);
+ add(button);
+ validate();
+ repaint();
+ } else {
+ JOptionPane.showMessageDialog(null, msg, title, msgType);
+ }
+ }
+
+ CConn cc;
public void run() {
- CConn cc = null;
+ cc = null;
if (listenMode.getValue()) {
int port = 5500;
try {
listener = new TcpListener(null, port);
} catch (java.lang.Exception e) {
- System.out.println(e.toString());
+ reportException(e);
exit(1);
}
while (!cc.shuttingDown)
cc.processMsg();
} catch (java.lang.Exception e) {
- if (e instanceof EndOfStream) {
- vlog.info(e.getMessage());
- } else if (cc == null || !cc.shuttingDown) {
- e.printStackTrace();
- JOptionPane op =
- new JOptionPane(e.getMessage(), JOptionPane.WARNING_MESSAGE);
- JDialog dlg = op.createDialog("TigerVNC Viewer");
- dlg.setIconImage(frameIcon);
- dlg.setVisible(true);
+ if (cc == null || !cc.shuttingDown) {
+ reportException(e);
+ if (cc != null)
+ cc.deleteWindow();
+ exit(1);
+ } else if (embed.getValue()) {
+ reportException(new java.lang.Exception("Connection closed"));
} else {
- if (!cc.shuttingDown)
- vlog.info(e.toString());
cc = null;
}
}
static BoolParameter noLionFS
= new BoolParameter("NoLionFS", null, false);
+ BoolParameter embed
+ = new BoolParameter("Embed",
+ "If the viewer is being run as an applet, display its output to " +
+ "an embedded frame in the browser window rather than to a dedicated " +
+ "window. This also has the effect of setting FullScreen=0, and Scale=100.",
+ false);
+
BoolParameter useLocalCursor
= new BoolParameter("UseLocalCursor",
"Render the mouse cursor locally",
Thread thread;
Socket sock;
- boolean applet;
static int nViewers;
static LogWriter vlog = new LogWriter("main");
}
<APPLET CODE=com.tigervnc.vncviewer.VncViewer ARCHIVE=VncViewer.jar
WIDTH=$APPLETWIDTH HEIGHT=$APPLETHEIGHT>
<param name=PORT value=$PORT>
+<param name="Embed" value="true">
+<param name="draggable" value="true">
</APPLET>
<BR>
<A href="http://www.tigervnc.org/">TigerVNC site</A>
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2009-2011 Pierre Ossman for Cendio AB
+ * Copyright 2014 Brian P. Hinz
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
}
if (strcmp(varName, "$APPLETHEIGHT") == 0) {
char* str = new char[10];
- sprintf(str, "%d", height() + 32);
+ sprintf(str, "%d", height());
return str;
}
if (strcmp(varName, "$DESKTOP") == 0) {