Mercurial > hg > Applications > TreeVNC
view src/viewer_swing/java/com/glavsoft/viewer/Viewer.java @ 43:6687aa9dd55e
add flag for screen change in ReciverTask.java.
author | one |
---|---|
date | Tue, 06 Nov 2012 15:36:46 +0900 |
parents | fe38611c4b2b |
children | 20326a4b9d88 |
line wrap: on
line source
// Copyright (C) 2010, 2011 GlavSoft LLC. // All rights reserved. // //------------------------------------------------------------------------- // This file is part of the TightVNC software. Please visit our Web site: // // http://www.tightvnc.com/ // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with this program; if not, write to the Free Software Foundation, Inc., // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. //------------------------------------------------------------------------- // package com.glavsoft.viewer; import com.glavsoft.core.SettingsChangedEvent; import com.glavsoft.exceptions.*; import com.glavsoft.rfb.IChangeSettingsListener; import com.glavsoft.rfb.IPasswordRetriever; import com.glavsoft.rfb.IRfbSessionListener; import com.glavsoft.rfb.client.KeyEventMessage; import com.glavsoft.rfb.protocol.Protocol; import com.glavsoft.rfb.protocol.ProtocolContext; import com.glavsoft.rfb.protocol.ProtocolSettings; import com.glavsoft.transport.Reader; import com.glavsoft.transport.Writer; import com.glavsoft.utils.Keymap; import com.glavsoft.utils.Strings; import com.glavsoft.viewer.cli.Parser; import com.glavsoft.viewer.swing.*; import com.glavsoft.viewer.swing.gui.OptionsDialog; import com.glavsoft.viewer.swing.gui.PasswordDialog; import javax.swing.*; import java.awt.*; import java.awt.Dialog.ModalityType; import java.awt.event.*; import java.io.IOException; import java.io.InputStream; import java.net.Socket; import java.util.LinkedList; import java.util.List; import java.util.jar.Attributes; import java.util.jar.Manifest; import java.util.logging.Logger; import jp.ac.u_ryukyu.treevnc.AcceptThread; import jp.ac.u_ryukyu.treevnc.MyRfbProto; @SuppressWarnings("serial") public class Viewer extends JApplet implements Runnable, IRfbSessionListener, WindowListener, IChangeSettingsListener { public static final int DEFAULT_PORT = 5900; public static Logger logger = Logger.getLogger("com.glavsoft"); private static final Insets BUTTONS_MARGIN = new Insets(2, 2, 2, 2); private boolean isZoomToFitSelected; protected boolean forceReconnection; protected String reconnectionReason; private ContainerManager containerManager; protected ConnectionManager connectionManager; private MyRfbProto rfb; public Protocol getWorkingProtocol() { return workingProtocol; } public boolean isZoomToFitSelected() { return isZoomToFitSelected; } public Surface getSurface() { return surface; } public UiSettings getUiSettings() { return uiSettings; } public void setZoomToFitSelected(boolean zoomToFitSelected) { isZoomToFitSelected = zoomToFitSelected; } public void setType(ConnectionManager _connectionManager,MyRfbProto _rfb) { connectionManager = _connectionManager; rfb = _rfb; } /** * Ask user for password if needed */ public class PasswordChooser implements IPasswordRetriever { private final String passwordPredefined; private final ParametersHandler.ConnectionParams connectionParams; PasswordDialog passwordDialog; private final JFrame owner; private final WindowListener onClose; public PasswordChooser(String passwordPredefined, ParametersHandler.ConnectionParams connectionParams, JFrame owner, WindowListener onClose) { this.passwordPredefined = passwordPredefined; this.connectionParams = connectionParams; this.owner = owner; this.onClose = onClose; } @Override public String getPassword() { return Strings.isTrimmedEmpty(passwordPredefined) ? getPasswordFromGUI() : passwordPredefined; } private String getPasswordFromGUI() { if (null == passwordDialog) { passwordDialog = new PasswordDialog(owner, onClose, isApplet); } passwordDialog.setServerHostName(connectionParams.hostName); passwordDialog.setVisible(true); return passwordDialog.getPassword(); } } public static void main(String[] args) { Parser parser = new Parser(); ParametersHandler.completeParserOptions(parser); parser.parse(args); if (parser.isSet(ParametersHandler.ARG_HELP)) { printUsage(parser.optionsUsage()); System.exit(0); } Viewer viewer = new Viewer(parser); SwingUtilities.invokeLater(viewer); } public static void printUsage(String additional) { System.out.println("Usage: java -jar (progfilename) [hostname [port_number]] [Options]\n" + " or\n"+ " java -jar (progfilename) [Options]\n" + " or\n java -jar (progfilename) -help\n to view this help\n\n" + "Where Options are:\n" + additional + "\nOptions format: -optionName=optionValue. Ex. -host=localhost -port=5900 -viewonly=yes\n" + "Both option name and option value are case insensitive."); } protected final ParametersHandler.ConnectionParams connectionParams; protected String passwordFromParams; protected Socket workingSocket; protected Protocol workingProtocol; protected JFrame containerFrame; boolean isSeparateFrame = true; protected boolean isApplet = true; protected boolean showControls = true; protected Surface surface; protected final ProtocolSettings settings; protected final UiSettings uiSettings; protected boolean tryAgain; private boolean isAppletStopped = false; private volatile boolean isStoppingProcess; private List<JComponent> kbdButtons; public Viewer() { connectionParams = new ParametersHandler.ConnectionParams(); settings = ProtocolSettings.getDefaultSettings(); uiSettings = new UiSettings(); connectionManager = new ConnectionManager(this, isApplet); } private Viewer(Parser parser) { this(); ParametersHandler.completeSettingsFromCLI(parser, connectionParams, settings, uiSettings); showControls = ParametersHandler.showControls; passwordFromParams = parser.getValueFor(ParametersHandler.ARG_PASSWORD); logger.info("TightVNC Viewer version " + ver()); isApplet = false; } @Override public void rfbSessionStopped(final String reason) { if (isStoppingProcess) return; cleanUpUISessionAndConnection(); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { forceReconnection = true; reconnectionReason = reason; } }); // start new session SwingUtilities.invokeLater(this); } private synchronized void cleanUpUISessionAndConnection() { isStoppingProcess = true; if (workingSocket != null && workingSocket.isConnected()) { try { workingSocket.close(); } catch (IOException e) { /*nop*/ } } if (containerFrame != null) { containerFrame.dispose(); containerFrame = null; } isStoppingProcess = false; } @Override public void windowClosing(WindowEvent e) { if (e != null && e.getComponent() != null) { e.getWindow().setVisible(false); } closeApp(); } /** * Closes App(lication) or stops App(let). */ protected void closeApp() { if (workingProtocol != null) { workingProtocol.cleanUpSession(); } cleanUpUISessionAndConnection(); tryAgain = false; if (isApplet) { logger.severe("Applet is stopped."); isAppletStopped = true; repaint(); } else { System.exit(0); } } @Override public void paint(Graphics g) { if ( ! isAppletStopped) { super.paint(g); } else { getContentPane().removeAll(); g.clearRect(0, 0, getWidth(), getHeight()); g.drawString("Disconnected", 10, 20); } } @Override public void destroy() { closeApp(); super.destroy(); } @Override public void init() { ParametersHandler.completeSettingsFromApplet(this, connectionParams, settings, uiSettings); showControls = ParametersHandler.showControls; isSeparateFrame = ParametersHandler.isSeparateFrame; passwordFromParams = getParameter(ParametersHandler.ARG_PASSWORD); isApplet = true; repaint(); SwingUtilities.invokeLater(this); } @Override public void start() { setSurfaceToHandleKbdFocus(); super.start(); } @Override public void run() { if (forceReconnection) { connectionManager.showReconnectDialog("Connection lost", reconnectionReason); forceReconnection = false; } tryAgain = true; while (tryAgain) { if(workingSocket==null) workingSocket = connectionManager.connectToHost(connectionParams, settings, rfb); if (null == workingSocket) { closeApp(); break; } logger.info("Connected"); System.out.println("-------------"+connectionParams.hostName); try { workingSocket.setTcpNoDelay(true); // disable Nagle algorithm Reader reader = new Reader(workingSocket.getInputStream()); Writer writer = new Writer(workingSocket.getOutputStream()); workingProtocol = new Protocol(reader, writer, new PasswordChooser(passwordFromParams, connectionParams, containerFrame, this), settings); workingProtocol.handshake(); ClipboardControllerImpl clipboardController = new ClipboardControllerImpl(workingProtocol, settings.getRemoteCharsetName()); clipboardController.setEnabled(settings.isAllowClipboardTransfer()); settings.addListener(clipboardController); surface = new Surface(workingProtocol, this, uiSettings.getScaleFactor()); settings.addListener(this); uiSettings.addListener(surface); containerFrame = createContainer(); connectionManager.setContainerFrame(containerFrame); updateFrameTitle(); if(rfb != null) { rfb.setViewer(this); runAcceptThread(); rfb.setProtocolContext(workingProtocol); rfb.notProxy(); workingProtocol.startTreeClientHandling(this,surface, clipboardController,rfb); } else { workingProtocol.startNormalHandling(this, surface, clipboardController); } tryAgain = false; } catch (UnsupportedProtocolVersionException e) { connectionManager.showReconnectDialog("Unsupported Protocol Version", e.getMessage()); logger.severe(e.getMessage()); } catch (UnsupportedSecurityTypeException e) { connectionManager.showReconnectDialog("Unsupported Security Type", e.getMessage()); logger.severe(e.getMessage()); } catch (AuthenticationFailedException e) { passwordFromParams = null; connectionManager.showReconnectDialog("Authentication Failed", e.getMessage()); logger.severe(e.getMessage()); } catch (TransportException e) { connectionManager.showReconnectDialog("Connection Error", "Connection Error" + ": " + e.getMessage()); logger.severe(e.getMessage()); } catch (IOException e) { connectionManager.showReconnectDialog("Connection Error", "Connection Error" + ": " + e.getMessage()); logger.severe(e.getMessage()); } catch (FatalException e) { connectionManager.showReconnectDialog("Connection Error", "Connection Error" + ": " + e.getMessage()); logger.severe(e.getMessage()); } } } protected JFrame createContainer() { containerManager = new ContainerManager(this); Container container = containerManager.createContainer(surface, isSeparateFrame, isApplet); if (showControls) { createButtonsPanel(container, workingProtocol, containerManager); containerManager.registerResizeListener(container); containerManager.updateZoomButtonsState(); } setSurfaceToHandleKbdFocus(); return isSeparateFrame ? (JFrame)container : null; } public void packContainer() { containerManager.pack(); } protected void createButtonsPanel(final Container container, final ProtocolContext context, ContainerManager containerManager) { JPanel buttonBar = new JPanel(new FlowLayout(FlowLayout.LEFT, 4, 1)); JButton optionsButton = new JButton(Utils.getButtonIcon("options")); optionsButton.setToolTipText("Set Options"); optionsButton.setMargin(BUTTONS_MARGIN); buttonBar.add(optionsButton); optionsButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { showOptionsDialog(); setSurfaceToHandleKbdFocus(); } }); JButton infoButton = new JButton(Utils.getButtonIcon("info")); infoButton.setToolTipText("Show connection info"); infoButton.setMargin(BUTTONS_MARGIN); buttonBar.add(infoButton); infoButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { showConnectionInfoMessage(context.getRemoteDesktopName()); setSurfaceToHandleKbdFocus(); } }); buttonBar.add(Box.createHorizontalStrut(10)); JButton refreshButton = new JButton(Utils.getButtonIcon("refresh")); refreshButton.setToolTipText("Refresh screen"); refreshButton.setMargin(BUTTONS_MARGIN); buttonBar.add(refreshButton); refreshButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { context.sendRefreshMessage(); setSurfaceToHandleKbdFocus(); } }); containerManager.addZoomButtons(buttonBar, BUTTONS_MARGIN); kbdButtons = new LinkedList<JComponent>(); buttonBar.add(Box.createHorizontalStrut(10)); JButton ctrlAltDelButton = new JButton(Utils.getButtonIcon("ctrl-alt-del")); ctrlAltDelButton.setToolTipText("Send 'Ctrl-Alt-Del'"); ctrlAltDelButton.setMargin(BUTTONS_MARGIN); buttonBar.add(ctrlAltDelButton); kbdButtons.add(ctrlAltDelButton); ctrlAltDelButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { sendCtrlAltDel(context); setSurfaceToHandleKbdFocus(); } }); JButton winButton = new JButton(Utils.getButtonIcon("win")); winButton.setToolTipText("Send 'Win' key as 'Ctrl-Esc'"); winButton.setMargin(BUTTONS_MARGIN); buttonBar.add(winButton); kbdButtons.add(winButton); winButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { sendWinKey(context); setSurfaceToHandleKbdFocus(); } }); JButton testButton = new JButton(Utils.getButtonIcon("test")); testButton.setToolTipText("test"); testButton.setMargin(BUTTONS_MARGIN); buttonBar.add(testButton); kbdButtons.add(testButton); testButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { testKey(context); setSurfaceToHandleKbdFocus(); } }); JToggleButton ctrlButton = new JToggleButton(Utils.getButtonIcon("ctrl")); ctrlButton.setToolTipText("Ctrl Lock"); ctrlButton.setMargin(BUTTONS_MARGIN); buttonBar.add(ctrlButton); kbdButtons.add(ctrlButton); ctrlButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { setSurfaceToHandleKbdFocus(); } }); ctrlButton.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { if (e.getStateChange() == ItemEvent.SELECTED) { context.sendMessage(new KeyEventMessage(Keymap.K_CTRL_LEFT, true)); } else { context.sendMessage(new KeyEventMessage(Keymap.K_CTRL_LEFT, false)); } } }); JToggleButton altButton = new JToggleButton(Utils.getButtonIcon("alt")); kbdButtons.add(altButton); altButton.setToolTipText("Alt Lock"); altButton.setMargin(BUTTONS_MARGIN); buttonBar.add(altButton); kbdButtons.add(altButton); altButton.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { if (e.getStateChange() == ItemEvent.SELECTED) { context.sendMessage(new KeyEventMessage(Keymap.K_ALT_LEFT, true)); } else { context.sendMessage(new KeyEventMessage(Keymap.K_ALT_LEFT, false)); } } }); altButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { setSurfaceToHandleKbdFocus(); } }); ModifierButtonEventListener modifierButtonListener = new ModifierButtonEventListener(); modifierButtonListener.addButton(KeyEvent.VK_CONTROL, ctrlButton); modifierButtonListener.addButton(KeyEvent.VK_ALT, altButton); surface.addModifierListener(modifierButtonListener); // JButton fileTransferButton = new JButton(Utils.getButtonIcon("file-transfer")); // fileTransferButton.setMargin(buttonsMargin); // buttonBar.add(fileTransferButton); buttonBar.add(Box.createHorizontalStrut(10)); JButton closeButton = new JButton(Utils.getButtonIcon("close")); closeButton.setToolTipText(isApplet ? "Disconnect" : "Close"); closeButton.setMargin(BUTTONS_MARGIN); closeButton.setAlignmentX(RIGHT_ALIGNMENT); buttonBar.add(closeButton); closeButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { closeApp(); } }); container.add(buttonBar, BorderLayout.NORTH); } protected void updateFrameTitle() { if (containerFrame != null) { containerFrame.setTitle( workingProtocol.getRemoteDesktopName() + " [zoom: " + uiSettings.getScalePercentFormatted() + "%]"); } } protected void setSurfaceToHandleKbdFocus() { if (surface != null && ! surface.requestFocusInWindow()) { surface.requestFocus(); } } @Override public void settingsChanged(SettingsChangedEvent e) { ProtocolSettings settings = (ProtocolSettings) e.getSource(); setEnabledKbdButtons( ! settings.isViewOnly()); } private void setEnabledKbdButtons(boolean enabled) { if (kbdButtons != null) { for (JComponent b : kbdButtons) { b.setEnabled(enabled); } } } private void showOptionsDialog() { OptionsDialog optionsDialog = new OptionsDialog(containerFrame); optionsDialog.initControlsFromSettings(settings, false); optionsDialog.setVisible(true); } private void showConnectionInfoMessage(final String title) { StringBuilder message = new StringBuilder(); message.append("Connected to: ").append(title).append("\n"); message.append("Host: ").append(connectionParams.hostName) .append(" Port: ").append(connectionParams.portNumber).append("\n\n"); message.append("Desktop geometry: ") .append(String.valueOf(surface.getWidth())) .append(" \u00D7 ") // multiplication sign .append(String.valueOf(surface.getHeight())).append("\n"); message.append("Color format: ") .append(String.valueOf(Math.round(Math.pow(2, workingProtocol.getPixelFormat().depth)))) .append(" colors (") .append(String.valueOf(workingProtocol.getPixelFormat().depth)) .append(" bits)\n"); message.append("Current protocol version: ") .append(settings.getProtocolVersion()); if (settings.isTight()) { message.append("tight"); } message.append("\n"); JOptionPane infoPane = new JOptionPane(message.toString(), JOptionPane.INFORMATION_MESSAGE); final JDialog infoDialog = infoPane.createDialog(containerFrame, "VNC connection info"); infoDialog.setModalityType(ModalityType.MODELESS); try { infoDialog.setAlwaysOnTop(true); } catch (SecurityException e) { /*nop*/ } infoDialog.setVisible(true); } private void sendCtrlAltDel(ProtocolContext context) { context.sendMessage(new KeyEventMessage(Keymap.K_CTRL_LEFT, true)); context.sendMessage(new KeyEventMessage(Keymap.K_ALT_LEFT, true)); context.sendMessage(new KeyEventMessage(Keymap.K_DELETE, true)); context.sendMessage(new KeyEventMessage(Keymap.K_DELETE, false)); context.sendMessage(new KeyEventMessage(Keymap.K_ALT_LEFT, false)); context.sendMessage(new KeyEventMessage(Keymap.K_CTRL_LEFT, false)); } private void sendWinKey(ProtocolContext context) { context.sendMessage(new KeyEventMessage(Keymap.K_CTRL_LEFT, true)); context.sendMessage(new KeyEventMessage(Keymap.K_ESCAPE, true)); context.sendMessage(new KeyEventMessage(Keymap.K_ESCAPE, false)); context.sendMessage(new KeyEventMessage(Keymap.K_CTRL_LEFT, false)); } private void testKey(ProtocolContext context) { System.out.println("test"); } @Override public void windowOpened(WindowEvent e) { /* nop */ } @Override public void windowClosed(WindowEvent e) { /* nop */ } @Override public void windowIconified(WindowEvent e) { /* nop */ } @Override public void windowDeiconified(WindowEvent e) { /* nop */ } @Override public void windowActivated(WindowEvent e) { /* nop */ } @Override public void windowDeactivated(WindowEvent e) { /* nop */ } protected static String ver() { final InputStream mfStream = Viewer.class.getClassLoader().getResourceAsStream( "META-INF/MANIFEST.MF"); if (null == mfStream) { System.out.println("No Manifest file found."); return "-1"; } try { Manifest mf = new Manifest(); mf.read(mfStream); Attributes atts = mf.getMainAttributes(); return atts.getValue(Attributes.Name.IMPLEMENTATION_VERSION); } catch (IOException e) { return "-2"; } } private void runAcceptThread() { Thread accThread = new Thread(new AcceptThread(rfb, connectionParams.portNumber)); accThread.start(); } public void startViewer(String[] args) { Parser parser = new Parser(); ParametersHandler.completeParserOptions(parser); parser.parse(args); if (parser.isSet(ParametersHandler.ARG_HELP)) { printUsage(parser.optionsUsage()); System.exit(0); } Viewer viewer = new Viewer(parser); SwingUtilities.invokeLater(viewer); } public void setSocket(Socket soc) { workingSocket = soc; } /* public void setSocket(String[] socAddr) { connectionParams.hostName = socAddr[0]; connectionParams.portNumber = Integer.parseInt(socAddr[1]); System.out.println(connectionParams.hostName+" "+connectionParams.portNumber); } */ public void close() { try { workingProtocol.getWriter().close(); workingProtocol.getReader().close(); cleanUpUISessionAndConnection(); } catch (IOException e) { e.printStackTrace(); } catch (TransportException e) { e.printStackTrace(); } } public int getPort() { return connectionParams.portNumber; } public void stopTask() { workingProtocol.cleanUpSession(); } public void setTeminationType(boolean setType) { rfb.setTerminationType(true); } }