From 430d8cf098aef3d1223a51cfd7d52ca2552b52df Mon Sep 17 00:00:00 2001 From: Brian Hinz Date: Thu, 2 Jan 2014 01:23:56 +0000 Subject: [PATCH] Re-introduces embedded applet mode for the java viewer. On Windows and Linux, the embedded applet can be dragged from the browser window and detached from the browser process. The mouse gesture for detaching the applet is ALT+drag on Windows and SHIFT+drag on Linux. git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@5149 3789f03b-4d11-0410-bbf8-ca57d06f2519 --- java/com/tigervnc/vncviewer/CConn.java | 103 +++++++++++-- .../com/tigervnc/vncviewer/DesktopWindow.java | 7 +- java/com/tigervnc/vncviewer/F8Menu.java | 4 +- .../com/tigervnc/vncviewer/OptionsDialog.java | 20 +-- java/com/tigervnc/vncviewer/README | 5 + java/com/tigervnc/vncviewer/Viewport.java | 28 ++-- java/com/tigervnc/vncviewer/VncViewer.java | 138 ++++++++++++++---- java/com/tigervnc/vncviewer/index.vnc | 2 + unix/xserver/hw/vnc/XserverDesktop.cc | 3 +- 9 files changed, 243 insertions(+), 67 deletions(-) diff --git a/java/com/tigervnc/vncviewer/CConn.java b/java/com/tigervnc/vncviewer/CConn.java index dd01d9db..e48e93b2 100644 --- a/java/com/tigervnc/vncviewer/CConn.java +++ b/java/com/tigervnc/vncviewer/CConn.java @@ -1,7 +1,7 @@ /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. * Copyright 2009-2013 Pierre Ossman 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 @@ -56,9 +56,9 @@ import com.tigervnc.rfb.Exception; 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 = @@ -265,7 +265,56 @@ public class CConn extends CConnection 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 @@ -487,15 +536,28 @@ public class CConn extends CConnection 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); @@ -506,8 +568,7 @@ public class CConn extends CConnection desktop.requestFocusInWindow(); } - private void reconfigureViewport() - { + private void reconfigureViewport() { //viewport.setMaxSize(cp.width, cp.height); boolean pack = true; Dimension dpySize = viewport.getToolkit().getScreenSize(); @@ -680,6 +741,14 @@ public class CConn extends CConnection // 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 { @@ -723,7 +792,7 @@ public class CConn extends CConnection 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) @@ -758,7 +827,7 @@ public class CConn extends CConnection 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) @@ -1134,6 +1203,8 @@ public class CConn extends CConnection } public void toggleFullScreen() { + if (viewer.embed.getValue()) + return; fullScreen = !fullScreen; menu.fullScreen.setSelected(fullScreen); if (viewport != null) { @@ -1319,6 +1390,13 @@ public class CConn extends CConnection 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 @@ -1401,6 +1479,7 @@ public class CConn extends CConnection private boolean autoSelect; boolean fullScreen; private HashMap downKeySym; + public ActionListener closeListener = null; static LogWriter vlog = new LogWriter("CConn"); } diff --git a/java/com/tigervnc/vncviewer/DesktopWindow.java b/java/com/tigervnc/vncviewer/DesktopWindow.java index 3dc4c25a..4749eb2a 100644 --- a/java/com/tigervnc/vncviewer/DesktopWindow.java +++ b/java/com/tigervnc/vncviewer/DesktopWindow.java @@ -2,7 +2,7 @@ * 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 @@ -426,7 +426,10 @@ class DesktopWindow extends JPanel implements Runnable, MouseListener, 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 diff --git a/java/com/tigervnc/vncviewer/F8Menu.java b/java/com/tigervnc/vncviewer/F8Menu.java index 543f7408..5045b77f 100644 --- a/java/com/tigervnc/vncviewer/F8Menu.java +++ b/java/com/tigervnc/vncviewer/F8Menu.java @@ -1,5 +1,5 @@ /* 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 @@ -49,6 +49,7 @@ public class F8Menu extends JPopupMenu implements ActionListener { fullScreen.setMnemonic(KeyEvent.VK_F); fullScreen.setSelected(cc.fullScreen); fullScreen.addActionListener(this); + fullScreen.setEnabled(!cc.viewer.embed.getValue()); add(fullScreen); addSeparator(); clipboard = addMenuItem("Clipboard..."); @@ -59,6 +60,7 @@ public class F8Menu extends JPopupMenu implements ActionListener { 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); diff --git a/java/com/tigervnc/vncviewer/OptionsDialog.java b/java/com/tigervnc/vncviewer/OptionsDialog.java index 3d73d4c3..24c7b0e0 100644 --- a/java/com/tigervnc/vncviewer/OptionsDialog.java +++ b/java/com/tigervnc/vncviewer/OptionsDialog.java @@ -1,5 +1,5 @@ /* 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 @@ -36,7 +36,7 @@ class OptionsDialog extends Dialog implements // Static variables static LogWriter vlog = new LogWriter("OptionsDialog"); - OptionsDialogCallback cb; + CConn cc; JPanel FormatPanel, InputsPanel, MiscPanel, DefaultsPanel, SecPanel; JCheckBox autoSelect, customCompressLevel, noJpeg; @SuppressWarnings({"rawtypes"}) @@ -53,9 +53,9 @@ class OptionsDialog extends Dialog implements 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"); @@ -149,6 +149,7 @@ class OptionsDialog extends Dialog implements 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"); @@ -172,6 +173,7 @@ class OptionsDialog extends Dialog implements } 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)); @@ -205,7 +207,6 @@ class OptionsDialog extends Dialog implements 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()); @@ -278,7 +279,7 @@ class OptionsDialog extends Dialog implements } 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()); @@ -472,7 +473,6 @@ class OptionsDialog extends Dialog implements public void endDialog() { super.endDialog(); - CConn cc = (CConn)cb; if (cc.viewport != null && cc.viewport.isVisible()) { cc.viewport.toFront(); cc.viewport.requestFocus(); @@ -482,7 +482,7 @@ class OptionsDialog extends Dialog implements 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(); @@ -496,7 +496,7 @@ class OptionsDialog extends Dialog implements 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(); @@ -516,7 +516,7 @@ class OptionsDialog extends Dialog implements 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"); diff --git a/java/com/tigervnc/vncviewer/README b/java/com/tigervnc/vncviewer/README index 196df40f..446bbf96 100644 --- a/java/com/tigervnc/vncviewer/README +++ b/java/com/tigervnc/vncviewer/README @@ -13,6 +13,7 @@ optimizations, major GUI improvements, and more. 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 @@ -46,6 +47,10 @@ There are three basic ways to use the TigerVNC Java Viewer: 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 diff --git a/java/com/tigervnc/vncviewer/Viewport.java b/java/com/tigervnc/vncviewer/Viewport.java index f43f592d..19c51c94 100644 --- a/java/com/tigervnc/vncviewer/Viewport.java +++ b/java/com/tigervnc/vncviewer/Viewport.java @@ -1,5 +1,5 @@ /* 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 @@ -64,7 +64,11 @@ public class Viewport extends JFrame 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(); } @@ -163,19 +167,19 @@ public class Viewport extends JFrame } 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; diff --git a/java/com/tigervnc/vncviewer/VncViewer.java b/java/com/tigervnc/vncviewer/VncViewer.java index 8a1f930e..e63ec3b1 100644 --- a/java/com/tigervnc/vncviewer/VncViewer.java +++ b/java/com/tigervnc/vncviewer/VncViewer.java @@ -1,7 +1,7 @@ /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. * Copyright 2011 Pierre Ossman 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 @@ -31,6 +31,7 @@ package com.tigervnc.vncviewer; import java.awt.*; +import java.awt.event.*; import java.awt.Color; import java.awt.Graphics; import java.awt.Image; @@ -49,8 +50,9 @@ import com.tigervnc.rdr.*; 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"+ @@ -122,7 +124,7 @@ public class VncViewer extends java.applet.Applet implements Runnable public VncViewer(String[] argv) { - applet = false; + embed.setParam(false); // load user preferences UserPreferences.load("global"); @@ -268,12 +270,12 @@ public class VncViewer extends java.applet.Applet implements Runnable 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) @@ -288,8 +290,56 @@ public class VncViewer extends java.applet.Applet implements Runnable 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); } @@ -310,9 +360,11 @@ public class VncViewer extends java.applet.Applet implements Runnable 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(); @@ -330,22 +382,48 @@ public class VncViewer extends java.applet.Applet implements Runnable 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("
" + title + "

" + + msg + "

", 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; @@ -358,7 +436,7 @@ public class VncViewer extends java.applet.Applet implements Runnable try { listener = new TcpListener(null, port); } catch (java.lang.Exception e) { - System.out.println(e.toString()); + reportException(e); exit(1); } @@ -376,18 +454,14 @@ public class VncViewer extends java.applet.Applet implements Runnable 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; } } @@ -400,6 +474,13 @@ public class VncViewer extends java.applet.Applet implements Runnable 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", @@ -568,7 +649,6 @@ public class VncViewer extends java.applet.Applet implements Runnable Thread thread; Socket sock; - boolean applet; static int nViewers; static LogWriter vlog = new LogWriter("main"); } diff --git a/java/com/tigervnc/vncviewer/index.vnc b/java/com/tigervnc/vncviewer/index.vnc index e8899875..27bdebcb 100644 --- a/java/com/tigervnc/vncviewer/index.vnc +++ b/java/com/tigervnc/vncviewer/index.vnc @@ -14,6 +14,8 @@ $USER's $DESKTOP desktop ($DISPLAY) + +
TigerVNC site diff --git a/unix/xserver/hw/vnc/XserverDesktop.cc b/unix/xserver/hw/vnc/XserverDesktop.cc index b0872793..b0d4601e 100644 --- a/unix/xserver/hw/vnc/XserverDesktop.cc +++ b/unix/xserver/hw/vnc/XserverDesktop.cc @@ -1,5 +1,6 @@ /* 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 @@ -338,7 +339,7 @@ char* XserverDesktop::substitute(const char* varName) } 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) { -- 2.39.5