]> source.dussan.org Git - tigervnc.git/commitdiff
Initial commit of new FLTK based vncviewer. Most of the code comes from the
authorPierre Ossman <ossman@cendio.se>
Wed, 9 Mar 2011 09:42:34 +0000 (09:42 +0000)
committerPierre Ossman <ossman@cendio.se>
Wed, 9 Mar 2011 09:42:34 +0000 (09:42 +0000)
current Unix vncviewer.

git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@4345 3789f03b-4d11-0410-bbf8-ca57d06f2519

15 files changed:
CMakeLists.txt
unix/CMakeLists.txt
vncviewer/CConn.cxx [new file with mode: 0644]
vncviewer/CConn.h [new file with mode: 0644]
vncviewer/CMakeLists.txt [new file with mode: 0644]
vncviewer/DesktopWindow.cxx [new file with mode: 0644]
vncviewer/DesktopWindow.h [new file with mode: 0644]
vncviewer/UserDialog.cxx [new file with mode: 0644]
vncviewer/UserDialog.h [new file with mode: 0644]
vncviewer/gettext.h [new file with mode: 0644]
vncviewer/i18n.h [new file with mode: 0644]
vncviewer/parameters.cxx [new file with mode: 0644]
vncviewer/parameters.h [new file with mode: 0644]
vncviewer/vncviewer.cxx [new file with mode: 0644]
win/CMakeLists.txt

index 83926e7a16936f0e874b71059a480adb4677f17c..b8507ab0d0b41c9d2d366ebeb30f6a915388e728 100644 (file)
@@ -15,6 +15,9 @@ set(VERSION 1.0.90)
 # The RC version must always be four comma-separated numbers
 set(RCVERSION 1,0,90,0)
 
+# Manual toggle until we can deprecate the old viewers
+option(BUILD_NEW_VNCVIEWER "Build the new FLTK based vncviewer instead of the old ones")
+
 # Compatibility variables for the migration from autotools
 add_definitions(-DPACKAGE_NAME="${CMAKE_PROJECT_NAME}")
 add_definitions(-DPACKAGE_VERSION="${VERSION}")
@@ -128,6 +131,13 @@ if(NOT FOUND_JPEG_TURBO)
   message(STATUS "WARNING: You are not using libjpeg-turbo. Performance will suffer.")
 endif()
 
+# Check for FLTK
+if(BUILD_NEW_VNCVIEWER)
+  set(FLTK_SKIP_FLUID TRUE)
+  set(FLTK_SKIP_OPENGL TRUE)
+  find_package(FLTK COMPONENTS REQUIRED)
+endif()
+
 # Check for GNUTLS library
 find_package(GnuTLS)
 if(GNUTLS_FOUND)
@@ -179,3 +189,7 @@ if(WIN32)
 else()
   add_subdirectory(unix)
 endif()
+
+if(BUILD_NEW_VNCVIEWER)
+  add_subdirectory(vncviewer)
+endif()
index 176fad36b9d416e09460d5ae9f0a7a9765fd0215..599f26f9644a678ddaf24cfbe0ec82a45933b7d7 100644 (file)
@@ -2,4 +2,7 @@ add_subdirectory(tx)
 
 add_subdirectory(vncconfig)
 add_subdirectory(vncpasswd)
+
+if(NOT BUILD_NEW_VNCVIEWER)
 add_subdirectory(vncviewer)
+endif()
diff --git a/vncviewer/CConn.cxx b/vncviewer/CConn.cxx
new file mode 100644 (file)
index 0000000..e903284
--- /dev/null
@@ -0,0 +1,450 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * Copyright 2009-2011 Pierre Ossman <ossman@cendio.se> for Cendio AB
+ * 
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+#include <assert.h>
+#include <unistd.h>
+
+#include <rfb/CMsgWriter.h>
+#include <rfb/encodings.h>
+#include <rfb/Hostname.h>
+#include <rfb/LogWriter.h>
+#include <rfb/util.h>
+#include <rfb/screenTypes.h>
+#include <rfb/Timer.h>
+#include <network/TcpSocket.h>
+
+#include <FL/Fl.H>
+#include <FL/fl_ask.H>
+
+#include "CConn.h"
+#include "i18n.h"
+#include "parameters.h"
+
+using namespace rdr;
+using namespace rfb;
+using namespace std;
+
+extern void exit_vncviewer();
+
+static rfb::LogWriter vlog("CConn");
+
+CConn::CConn(const char* vncServerName)
+  : serverHost(0), serverPort(0), sock(NULL), desktop(NULL),
+    currentEncoding(encodingTight), lastServerEncoding((unsigned int)-1),
+    formatChange(false), encodingChange(false),
+    firstUpdate(true), pendingUpdate(false)
+{
+  setShared(::shared);
+
+  int encNum = encodingNum(preferredEncoding);
+  if (encNum != -1)
+    currentEncoding = encNum;
+
+  cp.supportsDesktopResize = true;
+  cp.supportsExtendedDesktopSize = true;
+  cp.supportsDesktopRename = true;
+  cp.supportsLocalCursor = useLocalCursor;
+
+  cp.customCompressLevel = customCompressLevel;
+  cp.compressLevel = compressLevel;
+
+  cp.noJpeg = noJpeg;
+  cp.qualityLevel = qualityLevel;
+
+  try {
+    getHostAndPort(vncServerName, &serverHost, &serverPort);
+
+    sock = new network::TcpSocket(serverHost, serverPort);
+    vlog.info(_("connected to host %s port %d"), serverHost, serverPort);
+  } catch (rdr::Exception& e) {
+    vlog.error(e.str());
+    fl_alert(e.str());
+    exit_vncviewer();
+    return;
+  }
+
+  Fl::add_fd(sock->getFd(), FL_READ | FL_EXCEPT, socketEvent, this);
+
+  // See callback below
+  sock->inStream().setBlockCallback(this);
+
+  setServerName(serverHost);
+  setStreams(&sock->inStream(), &sock->outStream());
+
+  initialiseProtocol();
+}
+
+CConn::~CConn()
+{
+  free(serverHost);
+  if (sock)
+    Fl::remove_fd(sock->getFd());
+  delete sock;
+}
+
+// The RFB core is not properly asynchronous, so it calls this callback
+// whenever it needs to block to wait for more data. Since FLTK is
+// monitoring the socket, we just make sure FLTK gets to run.
+
+void CConn::blockCallback()
+{
+  int next_timer;
+
+  next_timer = Timer::checkTimeouts();
+  if (next_timer == 0)
+    next_timer = INT_MAX;
+
+  Fl::wait((double)next_timer / 1000.0);
+}
+
+void CConn::socketEvent(int fd, void *data)
+{
+  CConn *cc;
+  static bool recursing = false;
+
+  assert(data);
+  cc = (CConn*)data;
+
+  // I don't think processMsg() is recursion safe, so add this check
+  if (recursing)
+    return;
+
+  recursing = true;
+
+  try {
+    // processMsg() only processes one message, so we need to loop
+    // until the buffers are empty or things will stall.
+    do {
+      cc->processMsg();
+    } while (cc->sock->inStream().checkNoWait(1));
+  } catch (rdr::EndOfStream& e) {
+    vlog.info(e.str());
+    exit_vncviewer();
+  } catch (rdr::Exception& e) {
+    vlog.error(e.str());
+    fl_alert(e.str());
+    exit_vncviewer();
+  }
+
+  recursing = false;
+}
+
+////////////////////// CConnection callback methods //////////////////////
+
+// serverInit() is called when the serverInit message has been received.  At
+// this point we create the desktop window and display it.  We also tell the
+// server the pixel format and encodings to use and request the first update.
+void CConn::serverInit()
+{
+  CConnection::serverInit();
+
+  // If using AutoSelect with old servers, start in FullColor
+  // mode. See comment in autoSelectFormatAndEncoding. 
+  if (cp.beforeVersion(3, 8) && autoSelect)
+    fullColour.setParam(true);
+
+  serverPF = cp.pf();
+
+  desktop = new DesktopWindow(cp.width, cp.height, cp.name(), serverPF, this);
+  fullColourPF = desktop->getPreferredPF();
+
+  formatChange = encodingChange = true;
+  requestNewUpdate();
+}
+
+// setDesktopSize() is called when the desktop size changes (including when
+// it is set initially).
+void CConn::setDesktopSize(int w, int h)
+{
+  CConnection::setDesktopSize(w,h);
+  resizeFramebuffer();
+}
+
+// setExtendedDesktopSize() is a more advanced version of setDesktopSize()
+void CConn::setExtendedDesktopSize(int reason, int result, int w, int h,
+                                   const rfb::ScreenSet& layout)
+{
+  CConnection::setExtendedDesktopSize(reason, result, w, h, layout);
+
+  if ((reason == reasonClient) && (result != resultSuccess)) {
+    vlog.error(_("SetDesktopSize failed: %d"), result);
+    return;
+  }
+
+  resizeFramebuffer();
+}
+
+// setName() is called when the desktop name changes
+void CConn::setName(const char* name)
+{
+  CConnection::setName(name);
+  if (desktop)
+    desktop->setName(name);
+}
+
+// framebufferUpdateStart() is called at the beginning of an update.
+// Here we try to send out a new framebuffer update request so that the
+// next update can be sent out in parallel with us decoding the current
+// one. We cannot do this if we're in the middle of a format change
+// though.
+void CConn::framebufferUpdateStart()
+{
+  if (!formatChange) {
+    pendingUpdate = true;
+    requestNewUpdate();
+  } else
+    pendingUpdate = false;
+}
+
+// framebufferUpdateEnd() is called at the end of an update.
+// For each rectangle, the FdInStream will have timed the speed
+// of the connection, allowing us to select format and encoding
+// appropriately, and then request another incremental update.
+void CConn::framebufferUpdateEnd()
+{
+  desktop->updateWindow();
+
+  if (firstUpdate) {
+    int width, height;
+
+    if (cp.supportsSetDesktopSize &&
+        sscanf(desktopSize.getValueStr(), "%dx%d", &width, &height) == 2) {
+      ScreenSet layout;
+
+      layout = cp.screenLayout;
+
+      if (layout.num_screens() == 0)
+        layout.add_screen(rfb::Screen());
+      else if (layout.num_screens() != 1) {
+        ScreenSet::iterator iter;
+
+        while (true) {
+          iter = layout.begin();
+          ++iter;
+
+          if (iter == layout.end())
+            break;
+
+          layout.remove_screen(iter->id);
+        }
+      }
+
+      layout.begin()->dimensions.tl.x = 0;
+      layout.begin()->dimensions.tl.y = 0;
+      layout.begin()->dimensions.br.x = width;
+      layout.begin()->dimensions.br.y = height;
+
+      writer()->writeSetDesktopSize(width, height, layout);
+    }
+
+    firstUpdate = false;
+  }
+
+  // A format change prevented us from sending this before the update,
+  // so make sure to send it now.
+  if (formatChange && !pendingUpdate)
+    requestNewUpdate();
+
+  // Compute new settings based on updated bandwidth values
+  if (autoSelect)
+    autoSelectFormatAndEncoding();
+
+  // Make sure that the FLTK handling and the timers gets some CPU time
+  // in case of back to back framebuffer updates.
+  Fl::check();
+  Timer::checkTimeouts();
+}
+
+// The rest of the callbacks are fairly self-explanatory...
+
+void CConn::setColourMapEntries(int firstColour, int nColours, rdr::U16* rgbs)
+{
+  desktop->setColourMapEntries(firstColour, nColours, rgbs);
+}
+
+void CConn::bell()
+{
+  fl_beep();
+}
+
+void CConn::serverCutText(const char* str, rdr::U32 len)
+{
+//  desktop->serverCutText(str,len);
+}
+
+// We start timing on beginRect and stop timing on endRect, to
+// avoid skewing the bandwidth estimation as a result of the server
+// being slow or the network having high latency
+void CConn::beginRect(const Rect& r, int encoding)
+{
+  sock->inStream().startTiming();
+  if (encoding != encodingCopyRect) {
+    lastServerEncoding = encoding;
+  }
+}
+
+void CConn::endRect(const Rect& r, int encoding)
+{
+  sock->inStream().stopTiming();
+}
+
+void CConn::fillRect(const rfb::Rect& r, rfb::Pixel p)
+{
+  desktop->fillRect(r,p);
+}
+void CConn::imageRect(const rfb::Rect& r, void* p)
+{
+  desktop->imageRect(r,p);
+}
+void CConn::copyRect(const rfb::Rect& r, int sx, int sy)
+{
+  desktop->copyRect(r,sx,sy);
+}
+void CConn::setCursor(int width, int height, const Point& hotspot,
+                      void* data, void* mask)
+{
+//  desktop->setCursor(width, height, hotspot, data, mask);
+}
+
+////////////////////// Internal methods //////////////////////
+
+void CConn::resizeFramebuffer()
+{
+/*
+  if (!desktop)
+    return;
+  if ((desktop->width() == cp.width) && (desktop->height() == cp.height))
+    return;
+
+  desktop->resize(cp.width, cp.height);
+*/
+}
+
+// autoSelectFormatAndEncoding() chooses the format and encoding appropriate
+// to the connection speed:
+//
+//   First we wait for at least one second of bandwidth measurement.
+//
+//   Above 16Mbps (i.e. LAN), we choose the second highest JPEG quality,
+//   which should be perceptually lossless.
+//
+//   If the bandwidth is below that, we choose a more lossy JPEG quality.
+//
+//   If the bandwidth drops below 256 Kbps, we switch to palette mode.
+//
+//   Note: The system here is fairly arbitrary and should be replaced
+//         with something more intelligent at the server end.
+//
+void CConn::autoSelectFormatAndEncoding()
+{
+  int kbitsPerSecond = sock->inStream().kbitsPerSecond();
+  unsigned int timeWaited = sock->inStream().timeWaited();
+  bool newFullColour = fullColour;
+  int newQualityLevel = qualityLevel;
+
+  // Always use Tight
+  if (currentEncoding != encodingTight) {
+    currentEncoding = encodingTight;
+    encodingChange = true;
+  }
+
+  // Check that we have a decent bandwidth measurement
+  if ((kbitsPerSecond == 0) || (timeWaited < 10000))
+    return;
+
+  // Select appropriate quality level
+  if (!noJpeg) {
+    if (kbitsPerSecond > 16000)
+      newQualityLevel = 8;
+    else
+      newQualityLevel = 6;
+
+    if (newQualityLevel != qualityLevel) {
+      vlog.info(_("Throughput %d kbit/s - changing to quality %d"),
+                kbitsPerSecond, newQualityLevel);
+      cp.qualityLevel = newQualityLevel;
+      qualityLevel.setParam(newQualityLevel);
+      encodingChange = true;
+    }
+  }
+
+  if (cp.beforeVersion(3, 8)) {
+    // Xvnc from TightVNC 1.2.9 sends out FramebufferUpdates with
+    // cursors "asynchronously". If this happens in the middle of a
+    // pixel format change, the server will encode the cursor with
+    // the old format, but the client will try to decode it
+    // according to the new format. This will lead to a
+    // crash. Therefore, we do not allow automatic format change for
+    // old servers.
+    return;
+  }
+  
+  // Select best color level
+  newFullColour = (kbitsPerSecond > 256);
+  if (newFullColour != fullColour) {
+    vlog.info(_("Throughput %d kbit/s - full color is now %s"), 
+              kbitsPerSecond,
+              newFullColour ? _("enabled") : _("disabled"));
+    fullColour.setParam(newFullColour);
+    formatChange = true;
+  } 
+}
+
+// checkEncodings() sends a setEncodings message if one is needed.
+void CConn::checkEncodings()
+{
+  if (encodingChange && writer()) {
+    vlog.info(_("Using %s encoding"),encodingName(currentEncoding));
+    writer()->writeSetEncodings(currentEncoding, true);
+    encodingChange = false;
+  }
+}
+
+// requestNewUpdate() requests an update from the server, having set the
+// format and encoding appropriately.
+void CConn::requestNewUpdate()
+{
+  if (formatChange) {
+    PixelFormat pf;
+
+    /* Catch incorrect requestNewUpdate calls */
+    assert(pendingUpdate == false);
+
+    if (fullColour) {
+      pf = fullColourPF;
+    } else {
+      if (lowColourLevel == 0)
+        pf = PixelFormat(8,3,0,1,1,1,1,2,1,0);
+      else if (lowColourLevel == 1)
+        pf = PixelFormat(8,6,0,1,3,3,3,4,2,0);
+      else
+        pf = PixelFormat(8,8,0,0);
+    }
+    char str[256];
+    pf.print(str, 256);
+    vlog.info(_("Using pixel format %s"),str);
+    desktop->setServerPF(pf);
+    cp.setPF(pf);
+    writer()->writeSetPixelFormat(pf);
+  }
+  checkEncodings();
+  writer()->writeFramebufferUpdateRequest(Rect(0, 0, cp.width, cp.height),
+                                          !formatChange);
+  formatChange = false;
+}
diff --git a/vncviewer/CConn.h b/vncviewer/CConn.h
new file mode 100644 (file)
index 0000000..0f5be62
--- /dev/null
@@ -0,0 +1,96 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * Copyright 2009-2011 Pierre Ossman <ossman@cendio.se> for Cendio AB
+ * 
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+#ifndef __CCONN_H__
+#define __CCONN_H__
+
+#include <rfb/CConnection.h>
+#include <network/Socket.h>
+
+#include "DesktopWindow.h"
+
+class CConn : public rfb::CConnection,
+              public rdr::FdInStreamBlockCallback
+{
+public:
+  CConn(const char* vncServerName);
+  ~CConn();
+
+  // FdInStreamBlockCallback methods
+  void blockCallback();
+
+  // Callback when socket is ready (or broken)
+  static void socketEvent(int fd, void *data);
+
+  // CConnection callback methods
+  void serverInit();
+
+  void setDesktopSize(int w, int h);
+  void setExtendedDesktopSize(int reason, int result, int w, int h,
+                              const rfb::ScreenSet& layout);
+
+  void setName(const char* name);
+
+  void setColourMapEntries(int firstColour, int nColours, rdr::U16* rgbs);
+
+  void bell();
+
+  void serverCutText(const char* str, rdr::U32 len);
+
+  void framebufferUpdateStart();
+  void framebufferUpdateEnd();
+
+  void beginRect(const rfb::Rect& r, int encoding);
+  void endRect(const rfb::Rect& r, int encoding);
+
+  void fillRect(const rfb::Rect& r, rfb::Pixel p);
+  void imageRect(const rfb::Rect& r, void* p);
+  void copyRect(const rfb::Rect& r, int sx, int sy);
+
+  void setCursor(int width, int height, const rfb::Point& hotspot,
+                 void* data, void* mask);
+
+private:
+
+  void resizeFramebuffer();
+
+  void autoSelectFormatAndEncoding();
+  void checkEncodings();
+  void requestNewUpdate();
+
+private:
+  char* serverHost;
+  int serverPort;
+  network::Socket* sock;
+
+  DesktopWindow *desktop;
+
+  rfb::PixelFormat serverPF;
+  rfb::PixelFormat fullColourPF;
+
+  int currentEncoding, lastServerEncoding;
+
+  bool formatChange;
+  bool encodingChange;
+
+  bool firstUpdate;
+  bool pendingUpdate;
+};
+
+#endif
diff --git a/vncviewer/CMakeLists.txt b/vncviewer/CMakeLists.txt
new file mode 100644 (file)
index 0000000..742ba13
--- /dev/null
@@ -0,0 +1,12 @@
+include_directories(${FLTK_INCLUDE_DIR})
+
+include_directories(${CMAKE_SOURCE_DIR}/common)
+
+add_executable(vncviewer 
+  CConn.cxx
+  DesktopWindow.cxx
+  UserDialog.cxx
+  parameters.cxx
+  vncviewer.cxx)
+
+target_link_libraries(vncviewer rfb network rdr os Xregion ${FLTK_LIBRARIES})
diff --git a/vncviewer/DesktopWindow.cxx b/vncviewer/DesktopWindow.cxx
new file mode 100644 (file)
index 0000000..28f6c09
--- /dev/null
@@ -0,0 +1,186 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * Copyright 2011 Pierre Ossman <ossman@cendio.se> for Cendio AB
+ * 
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <FL/fl_draw.H>
+
+#include <rfb/CMsgWriter.h>
+#include <rfb/LogWriter.h>
+
+#include "DesktopWindow.h"
+#include "CConn.h"
+#include "i18n.h"
+#include "parameters.h"
+
+using namespace rfb;
+
+extern void exit_vncviewer();
+
+static rfb::LogWriter vlog("DesktopWindow");
+
+DesktopWindow::DesktopWindow(int w, int h, const char *name,
+                             const rfb::PixelFormat& serverPF,
+                             CConn* cc_)
+  : Fl_Window(w, h), cc(cc_), frameBuffer(NULL), pixelTrans(NULL)
+{
+  callback(handleClose, this);
+
+  setName(name);
+
+  frameBuffer = new ManagedPixelBuffer(getPreferredPF(), w, h);
+  assert(frameBuffer);
+
+  setServerPF(serverPF);
+
+  show();
+}
+
+
+DesktopWindow::~DesktopWindow()
+{
+  delete frameBuffer;
+
+  if (pixelTrans)
+    delete pixelTrans;
+}
+
+
+void DesktopWindow::setServerPF(const rfb::PixelFormat& pf)
+{
+  if (pixelTrans)
+    delete pixelTrans;
+  pixelTrans = NULL;
+
+  if (pf.equal(getPreferredPF()))
+    return;
+
+  pixelTrans = new PixelTransformer();
+  pixelTrans->init(pf, &colourMap, getPreferredPF());
+}
+
+
+const rfb::PixelFormat &DesktopWindow::getPreferredPF()
+{
+  static PixelFormat prefPF(32, 24, false, true, 255, 255, 255, 0, 8, 16);
+
+  return prefPF;
+}
+
+
+// Cursor stuff
+
+void DesktopWindow::setCursor(int width, int height, const Point& hotspot,
+                              void* data, void* mask)
+{
+}
+
+
+void DesktopWindow::setName(const char *name)
+{
+  CharArray windowNameStr;
+  windowNameStr.replaceBuf(new char[256]);
+
+  snprintf(windowNameStr.buf, 256, _("TigerVNC: %.240s"), name);
+
+  copy_label(windowNameStr.buf);
+}
+
+// setColourMapEntries() changes some of the entries in the colourmap.
+// Unfortunately these messages are often sent one at a time, so we delay the
+// settings taking effect by 100ms.  This is because recalculating the internal
+// translation table can be expensive.
+void DesktopWindow::setColourMapEntries(int firstColour, int nColours,
+                                        rdr::U16* rgbs)
+{
+  for (int i = 0; i < nColours; i++)
+    colourMap.set(firstColour+i, rgbs[i*3], rgbs[i*3+1], rgbs[i*3+2]);
+
+  if (!Fl::has_timeout(handleColourMap, this))
+    Fl::add_timeout(0.100, handleColourMap, this);
+}
+
+
+// Copy the areas of the framebuffer that have been changed (damaged)
+// to the displayed window.
+
+void DesktopWindow::updateWindow()
+{
+  Rect r;
+
+  Fl::remove_timeout(handleUpdateTimeout, this);
+
+  r = damage.get_bounding_rect();
+  Fl_Window::damage(FL_DAMAGE_USER1, r.tl.x, r.tl.y, r.width(), r.height());
+
+  damage.clear();
+}
+
+
+void DesktopWindow::draw()
+{
+  int X, Y, W, H;
+
+  int pixel_bytes, stride_bytes;
+  const uchar *buf_start;
+
+  // Check what actually needs updating
+  fl_clip_box(0, 0, w(), h(), X, Y, W, H);
+  if ((W == 0) || (H == 0))
+    return;
+
+  pixel_bytes = frameBuffer->getPF().bpp/8;
+  stride_bytes = pixel_bytes * frameBuffer->getStride();
+  buf_start = frameBuffer->data +
+              pixel_bytes * X +
+              stride_bytes * Y;
+
+  // FIXME: Check how efficient this thing really is
+  fl_draw_image(buf_start, X, Y, W, H, pixel_bytes, stride_bytes);
+}
+
+
+void DesktopWindow::handleUpdateTimeout(void *data)
+{
+  DesktopWindow *self = (DesktopWindow *)data;
+
+  assert(self);
+
+  self->updateWindow();
+}
+
+
+void DesktopWindow::handleColourMap(void *data)
+{
+  DesktopWindow *self = (DesktopWindow *)data;
+
+  assert(self);
+
+  if (self->pixelTrans != NULL)
+    self->pixelTrans->setColourMapEntries(0, 0);
+
+  self->Fl_Window::damage(FL_DAMAGE_ALL);
+}
+
+void DesktopWindow::handleClose(Fl_Widget *wnd, void *data)
+{
+  exit_vncviewer();
+}
diff --git a/vncviewer/DesktopWindow.h b/vncviewer/DesktopWindow.h
new file mode 100644 (file)
index 0000000..de85add
--- /dev/null
@@ -0,0 +1,110 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * Copyright 2011 Pierre Ossman <ossman@cendio.se> for Cendio AB
+ * 
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+#ifndef __DESKTOPWINDOW_H__
+#define __DESKTOPWINDOW_H__
+
+#include <FL/Fl.H>
+#include <FL/Fl_Window.H>
+
+#include <rfb/Rect.h>
+#include <rfb/Region.h>
+#include <rfb/Timer.h>
+#include <rfb/PixelBuffer.h>
+#include <rfb/PixelTransformer.h>
+
+class CConn;
+
+class DesktopWindow : public Fl_Window {
+public:
+
+  DesktopWindow(int w, int h, const char *name,
+                const rfb::PixelFormat& serverPF, CConn* cc_);
+  ~DesktopWindow();
+
+  // PixelFormat of incoming write operations
+  void setServerPF(const rfb::PixelFormat& pf);
+  // Most efficient format (from DesktopWindow's point of view)
+  const rfb::PixelFormat &getPreferredPF();
+
+  // setCursor() sets the shape of the local cursor
+  void setCursor(int width, int height, const rfb::Point& hotspot,
+                 void* data, void* mask);
+
+  // Flush updates to screen
+  void updateWindow();
+
+  // Methods forwarded from CConn
+  void setName(const char *name);
+
+  void setColourMapEntries(int firstColour, int nColours, rdr::U16* rgbs);
+
+  void fillRect(const rfb::Rect& r, rfb::Pixel pix) {
+    if (pixelTrans) {
+      rfb::Pixel pix2;
+      pixelTrans->translatePixels(&pix, &pix2, 1);
+      pix = pix2;
+    }
+
+    frameBuffer->fillRect(r, pix);
+    damageRect(r);
+  }
+  void imageRect(const rfb::Rect& r, void* pixels) {
+    if (pixelTrans)
+      pixelTrans->translateRect(pixels, r.width(),
+                                rfb::Rect(0, 0, r.width(), r.height()),
+                                frameBuffer->data, frameBuffer->getStride(),
+                                r.tl);
+    else
+      frameBuffer->imageRect(r, pixels);
+    damageRect(r);
+  }
+  void copyRect(const rfb::Rect& r, int srcX, int srcY) {
+    frameBuffer->copyRect(r, rfb::Point(r.tl.x-srcX, r.tl.y-srcY));
+    damageRect(r);
+  }
+
+  // Fl_Window callback methods
+  void draw();
+
+private:
+
+  void damageRect(const rfb::Rect& r) {
+    damage.assign_union(rfb::Region(r));
+    if (!Fl::has_timeout(handleUpdateTimeout, this))
+      Fl::add_timeout(0.100, handleUpdateTimeout, this);
+  };
+
+  static void handleUpdateTimeout(void *data);
+  static void handleColourMap(void *data);
+
+  static void handleClose(Fl_Widget *wnd, void *data);
+
+private:
+  CConn* cc;
+
+  rfb::ManagedPixelBuffer* frameBuffer;
+
+  rfb::PixelTransformer *pixelTrans;
+  rfb::SimpleColourMap colourMap;
+
+  rfb::Region damage;
+};
+
+#endif
diff --git a/vncviewer/UserDialog.cxx b/vncviewer/UserDialog.cxx
new file mode 100644 (file)
index 0000000..992ea78
--- /dev/null
@@ -0,0 +1,86 @@
+/* Copyright 2011 Pierre Ossman <ossman@cendio.se> for Cendio AB
+ * 
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <FL/fl_ask.H>
+
+#include <rfb/util.h>
+#include <rfb/Password.h>
+#include <rfb/Exception.h>
+
+#include "i18n.h"
+#include "parameters.h"
+#include "UserDialog.h"
+
+using namespace rfb;
+
+UserDialog::UserDialog()
+{
+}
+
+UserDialog::~UserDialog()
+{
+}
+
+void UserDialog::getUserPasswd(char** user, char** password)
+{
+  CharArray passwordFileStr(passwordFile.getData());
+
+  assert(password);
+
+  if (!user && passwordFileStr.buf[0]) {
+    ObfuscatedPasswd obfPwd(256);
+    FILE* fp;
+
+    fp = fopen(passwordFileStr.buf, "r");
+    if (!fp)
+      throw rfb::Exception(_("Opening password file failed"));
+
+    obfPwd.length = fread(obfPwd.buf, 1, obfPwd.length, fp);
+    fclose(fp);
+
+    PlainPasswd passwd(obfPwd);
+    *password = passwd.takeBuf();
+
+    return;
+  }
+
+  if (!user) {
+    *password = strDup(fl_password(_("VNC authentication"), ""));
+    if (!*password)
+      throw rfb::Exception(_("Authentication cancelled"));
+
+    return;
+  }
+
+  fl_alert(_("NOT IMPLEMENTED!"));
+
+  *user = strDup("");
+  *password = strDup("");
+}
+
+bool UserDialog::showMsgBox(int flags, const char* title, const char* text)
+{
+  fl_message_title(title);
+  fl_message(text);
+
+  return false;
+}
diff --git a/vncviewer/UserDialog.h b/vncviewer/UserDialog.h
new file mode 100644 (file)
index 0000000..c6756a8
--- /dev/null
@@ -0,0 +1,41 @@
+/* Copyright 2011 Pierre Ossman <ossman@cendio.se> for Cendio AB
+ * 
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+#ifndef __USERDIALOG_H__
+#define __USERDIALOG_H__
+
+#include <rfb/UserPasswdGetter.h>
+#include <rfb/UserMsgBox.h>
+
+class UserDialog : public rfb::UserPasswdGetter,
+                   public rfb::UserMsgBox
+{
+public:
+  UserDialog();
+  ~UserDialog();
+
+  // UserPasswdGetter callbacks
+
+  void getUserPasswd(char** user, char** password);
+
+  // UserMsgBox callbacks
+
+  bool showMsgBox(int flags, const char* title, const char* text);
+};
+
+#endif
diff --git a/vncviewer/gettext.h b/vncviewer/gettext.h
new file mode 100644 (file)
index 0000000..209921e
--- /dev/null
@@ -0,0 +1,271 @@
+/* Convenience header for conditional use of GNU <libintl.h>.
+   Copyright (C) 1995-1998, 2000-2002, 2004-2006 Free Software Foundation, Inc.
+
+   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, 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
+   Library 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.  */
+
+#ifndef _LIBGETTEXT_H
+#define _LIBGETTEXT_H 1
+
+/* NLS can be disabled through the configure --disable-nls option.  */
+#if ENABLE_NLS
+
+/* Get declarations of GNU message catalog functions.  */
+# include <libintl.h>
+
+/* You can set the DEFAULT_TEXT_DOMAIN macro to specify the domain used by
+   the gettext() and ngettext() macros.  This is an alternative to calling
+   textdomain(), and is useful for libraries.  */
+# ifdef DEFAULT_TEXT_DOMAIN
+#  undef gettext
+#  define gettext(Msgid) \
+     dgettext (DEFAULT_TEXT_DOMAIN, Msgid)
+#  undef ngettext
+#  define ngettext(Msgid1, Msgid2, N) \
+     dngettext (DEFAULT_TEXT_DOMAIN, Msgid1, Msgid2, N)
+# endif
+
+#else
+
+/* Solaris /usr/include/locale.h includes /usr/include/libintl.h, which
+   chokes if dcgettext is defined as a macro.  So include it now, to make
+   later inclusions of <locale.h> a NOP.  We don't include <libintl.h>
+   as well because people using "gettext.h" will not include <libintl.h>,
+   and also including <libintl.h> would fail on SunOS 4, whereas <locale.h>
+   is OK.  */
+#if defined(__sun)
+# include <locale.h>
+#endif
+
+/* Many header files from the libstdc++ coming with g++ 3.3 or newer include
+   <libintl.h>, which chokes if dcgettext is defined as a macro.  So include
+   it now, to make later inclusions of <libintl.h> a NOP.  */
+#if defined(__cplusplus) && defined(__GNUG__) && (__GNUC__ >= 3)
+# include <cstdlib>
+# if (__GLIBC__ >= 2) || _GLIBCXX_HAVE_LIBINTL_H
+#  include <libintl.h>
+# endif
+#endif
+
+/* Disabled NLS.
+   The casts to 'const char *' serve the purpose of producing warnings
+   for invalid uses of the value returned from these functions.
+   On pre-ANSI systems without 'const', the config.h file is supposed to
+   contain "#define const".  */
+# define gettext(Msgid) ((const char *) (Msgid))
+# define dgettext(Domainname, Msgid) ((void) (Domainname), gettext (Msgid))
+# define dcgettext(Domainname, Msgid, Category) \
+    ((void) (Category), dgettext (Domainname, Msgid))
+# define ngettext(Msgid1, Msgid2, N) \
+    ((N) == 1 \
+     ? ((void) (Msgid2), (const char *) (Msgid1)) \
+     : ((void) (Msgid1), (const char *) (Msgid2)))
+# define dngettext(Domainname, Msgid1, Msgid2, N) \
+    ((void) (Domainname), ngettext (Msgid1, Msgid2, N))
+# define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \
+    ((void) (Category), dngettext(Domainname, Msgid1, Msgid2, N))
+# define textdomain(Domainname) ((const char *) (Domainname))
+# define bindtextdomain(Domainname, Dirname) \
+    ((void) (Domainname), (const char *) (Dirname))
+# define bind_textdomain_codeset(Domainname, Codeset) \
+    ((void) (Domainname), (const char *) (Codeset))
+
+#endif
+
+/* A pseudo function call that serves as a marker for the automated
+   extraction of messages, but does not call gettext().  The run-time
+   translation is done at a different place in the code.
+   The argument, String, should be a literal string.  Concatenated strings
+   and other string expressions won't work.
+   The macro's expansion is not parenthesized, so that it is suitable as
+   initializer for static 'char[]' or 'const char[]' variables.  */
+#define gettext_noop(String) String
+
+/* The separator between msgctxt and msgid in a .mo file.  */
+#define GETTEXT_CONTEXT_GLUE "\004"
+
+/* Pseudo function calls, taking a MSGCTXT and a MSGID instead of just a
+   MSGID.  MSGCTXT and MSGID must be string literals.  MSGCTXT should be
+   short and rarely need to change.
+   The letter 'p' stands for 'particular' or 'special'.  */
+#ifdef DEFAULT_TEXT_DOMAIN
+# define pgettext(Msgctxt, Msgid) \
+   pgettext_aux (DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES)
+#else
+# define pgettext(Msgctxt, Msgid) \
+   pgettext_aux (NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES)
+#endif
+#define dpgettext(Domainname, Msgctxt, Msgid) \
+  pgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES)
+#define dcpgettext(Domainname, Msgctxt, Msgid, Category) \
+  pgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, Category)
+#ifdef DEFAULT_TEXT_DOMAIN
+# define npgettext(Msgctxt, Msgid, MsgidPlural, N) \
+   npgettext_aux (DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES)
+#else
+# define npgettext(Msgctxt, Msgid, MsgidPlural, N) \
+   npgettext_aux (NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES)
+#endif
+#define dnpgettext(Domainname, Msgctxt, Msgid, MsgidPlural, N) \
+  npgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES)
+#define dcnpgettext(Domainname, Msgctxt, Msgid, MsgidPlural, N, Category) \
+  npgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, Category)
+
+#ifdef __GNUC__
+__inline
+#else
+#ifdef __cplusplus
+inline
+#endif
+#endif
+static const char *
+pgettext_aux (const char *domain,
+             const char *msg_ctxt_id, const char *msgid,
+             int category)
+{
+  const char *translation = dcgettext (domain, msg_ctxt_id, category);
+  if (translation == msg_ctxt_id)
+    return msgid;
+  else
+    return translation;
+}
+
+#ifdef __GNUC__
+__inline
+#else
+#ifdef __cplusplus
+inline
+#endif
+#endif
+static const char *
+npgettext_aux (const char *domain,
+              const char *msg_ctxt_id, const char *msgid,
+              const char *msgid_plural, unsigned long int n,
+              int category)
+{
+  const char *translation =
+    dcngettext (domain, msg_ctxt_id, msgid_plural, n, category);
+  if (translation == msg_ctxt_id || translation == msgid_plural)
+    return (n == 1 ? msgid : msgid_plural);
+  else
+    return translation;
+}
+
+/* The same thing extended for non-constant arguments.  Here MSGCTXT and MSGID
+   can be arbitrary expressions.  But for string literals these macros are
+   less efficient than those above.  */
+
+#include <string.h>
+
+#define _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS \
+  (((__GNUC__ >= 3 || __GNUG__ >= 2) && !__STRICT_ANSI__) \
+   /* || __STDC_VERSION__ >= 199901L */ )
+
+#if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
+#include <stdlib.h>
+#endif
+
+#define pgettext_expr(Msgctxt, Msgid) \
+  dcpgettext_expr (NULL, Msgctxt, Msgid, LC_MESSAGES)
+#define dpgettext_expr(Domainname, Msgctxt, Msgid) \
+  dcpgettext_expr (Domainname, Msgctxt, Msgid, LC_MESSAGES)
+
+#ifdef __GNUC__
+__inline
+#else
+#ifdef __cplusplus
+inline
+#endif
+#endif
+static const char *
+dcpgettext_expr (const char *domain,
+                const char *msgctxt, const char *msgid,
+                int category)
+{
+  size_t msgctxt_len = strlen (msgctxt) + 1;
+  size_t msgid_len = strlen (msgid) + 1;
+  const char *translation;
+#if _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
+  char msg_ctxt_id[msgctxt_len + msgid_len];
+#else
+  char buf[1024];
+  char *msg_ctxt_id =
+    (msgctxt_len + msgid_len <= sizeof (buf)
+     ? buf
+     : (char *) malloc (msgctxt_len + msgid_len));
+  if (msg_ctxt_id != NULL)
+#endif
+    {
+      memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1);
+      msg_ctxt_id[msgctxt_len - 1] = '\004';
+      memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len);
+      translation = dcgettext (domain, msg_ctxt_id, category);
+#if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
+      if (msg_ctxt_id != buf)
+       free (msg_ctxt_id);
+#endif
+      if (translation != msg_ctxt_id)
+       return translation;
+    }
+  return msgid;
+}
+
+#define npgettext_expr(Msgctxt, Msgid, MsgidPlural, N) \
+  dcnpgettext_expr (NULL, Msgctxt, Msgid, MsgidPlural, N, LC_MESSAGES)
+#define dnpgettext_expr(Domainname, Msgctxt, Msgid, MsgidPlural, N) \
+  dcnpgettext_expr (Domainname, Msgctxt, Msgid, MsgidPlural, N, LC_MESSAGES)
+
+#ifdef __GNUC__
+__inline
+#else
+#ifdef __cplusplus
+inline
+#endif
+#endif
+static const char *
+dcnpgettext_expr (const char *domain,
+                 const char *msgctxt, const char *msgid,
+                 const char *msgid_plural, unsigned long int n,
+                 int category)
+{
+  size_t msgctxt_len = strlen (msgctxt) + 1;
+  size_t msgid_len = strlen (msgid) + 1;
+  const char *translation;
+#if _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
+  char msg_ctxt_id[msgctxt_len + msgid_len];
+#else
+  char buf[1024];
+  char *msg_ctxt_id =
+    (msgctxt_len + msgid_len <= sizeof (buf)
+     ? buf
+     : (char *) malloc (msgctxt_len + msgid_len));
+  if (msg_ctxt_id != NULL)
+#endif
+    {
+      memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1);
+      msg_ctxt_id[msgctxt_len - 1] = '\004';
+      memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len);
+      translation = dcngettext (domain, msg_ctxt_id, msgid_plural, n, category);
+#if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
+      if (msg_ctxt_id != buf)
+       free (msg_ctxt_id);
+#endif
+      if (!(translation == msg_ctxt_id || translation == msgid_plural))
+       return translation;
+    }
+  return (n == 1 ? msgid : msgid_plural);
+}
+
+#endif /* _LIBGETTEXT_H */
diff --git a/vncviewer/i18n.h b/vncviewer/i18n.h
new file mode 100644 (file)
index 0000000..bf5a50c
--- /dev/null
@@ -0,0 +1,29 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * Copyright 2011 Pierre Ossman <ossman@cendio.se> for Cendio AB
+ * 
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+#ifndef _I18N_H
+#define _I18N_H 1
+
+#include "gettext.h"
+
+#define _(String) gettext (String)
+#define gettext_noop(String) String
+#define N_(String) gettext_noop (String)
+
+#endif /* _I18N_H */
diff --git a/vncviewer/parameters.cxx b/vncviewer/parameters.cxx
new file mode 100644 (file)
index 0000000..ff0e49c
--- /dev/null
@@ -0,0 +1,90 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * Copyright 2011 Pierre Ossman <ossman@cendio.se> for Cendio AB
+ * 
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+#include "parameters.h"
+
+using namespace rfb;
+
+IntParameter pointerEventInterval("PointerEventInterval",
+                                  "Time in milliseconds to rate-limit"
+                                  " successive pointer events", 0);
+BoolParameter useLocalCursor("UseLocalCursor",
+                             "Render the mouse cursor locally", true);
+BoolParameter dotWhenNoCursor("DotWhenNoCursor",
+                              "Show the dot cursor when the server sends an "
+                              "invisible cursor", true);
+
+StringParameter passwordFile("PasswordFile",
+                             "Password file for VNC authentication", "");
+AliasParameter passwd("passwd", "Alias for PasswordFile", &passwordFile);
+
+BoolParameter autoSelect("AutoSelect",
+                         "Auto select pixel format and encoding. "
+                         "Default if PreferredEncoding and FullColor are not specified.", 
+                         true);
+BoolParameter fullColour("FullColor",
+                         "Use full color", true);
+AliasParameter fullColourAlias("FullColour", "Alias for FullColor", &fullColour);
+IntParameter lowColourLevel("LowColorLevel",
+                            "Color level to use on slow connections. "
+                            "0 = Very Low (8 colors), 1 = Low (64 colors), "
+                            "2 = Medium (256 colors)", 2);
+AliasParameter lowColourLevelAlias("LowColourLevel", "Alias for LowColorLevel", &lowColourLevel);
+StringParameter preferredEncoding("PreferredEncoding",
+                                  "Preferred encoding to use (Tight, ZRLE, Hextile or"
+                                  " Raw)", "Tight");
+BoolParameter customCompressLevel("CustomCompressLevel",
+                                  "Use custom compression level. "
+                                  "Default if CompressLevel is specified.", false);
+IntParameter compressLevel("CompressLevel",
+                           "Use specified compression level 0 = Low, 9 = High",
+                           6);
+BoolParameter noJpeg("NoJPEG",
+                     "Disable lossy JPEG compression in Tight encoding.",
+                     false);
+IntParameter qualityLevel("QualityLevel",
+                          "JPEG quality level. 0 = Low, 9 = High",
+                          8);
+
+BoolParameter fullScreen("FullScreen", "Full screen mode", false);
+StringParameter desktopSize("DesktopSize",
+                            "Reconfigure desktop size on the server on "
+                            "connect (if possible)", "");
+
+BoolParameter viewOnly("ViewOnly",
+                       "Don't send any mouse or keyboard events to the server",
+                       false);
+BoolParameter shared("Shared",
+                     "Don't disconnect other viewers upon connection - "
+                     "share the desktop instead",
+                     false);
+
+BoolParameter acceptClipboard("AcceptClipboard",
+                              "Accept clipboard changes from the server",
+                              true);
+BoolParameter sendClipboard("SendClipboard",
+                            "Send clipboard changes to the server", true);
+BoolParameter sendPrimary("SendPrimary",
+                          "Send the primary selection and cut buffer to the "
+                          "server as well as the clipboard selection",
+                          true);
+
+StringParameter menuKey("MenuKey", "The key which brings up the popup menu",
+                        "F8");
+
diff --git a/vncviewer/parameters.h b/vncviewer/parameters.h
new file mode 100644 (file)
index 0000000..df4b080
--- /dev/null
@@ -0,0 +1,53 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * Copyright 2011 Pierre Ossman <ossman@cendio.se> for Cendio AB
+ * 
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+#ifndef __PARAMETERS_H__
+#define __PARAMETERS_H__
+
+#include <rfb/Configuration.h>
+
+extern rfb::IntParameter pointerEventInterval;
+extern rfb::BoolParameter useLocalCursor;
+extern rfb::BoolParameter dotWhenNoCursor;
+
+extern rfb::StringParameter passwordFile;
+
+extern rfb::BoolParameter autoSelect;
+extern rfb::BoolParameter fullColour;
+extern rfb::AliasParameter fullColourAlias;
+extern rfb::IntParameter lowColourLevel;
+extern rfb::AliasParameter lowColourLevelAlias;
+extern rfb::StringParameter preferredEncoding;
+extern rfb::BoolParameter customCompressLevel;
+extern rfb::IntParameter compressLevel;
+extern rfb::BoolParameter noJpeg;
+extern rfb::IntParameter qualityLevel;
+
+extern rfb::BoolParameter fullScreen;
+extern rfb::StringParameter desktopSize;
+
+extern rfb::BoolParameter viewOnly;
+extern rfb::BoolParameter shared;
+
+extern rfb::BoolParameter acceptClipboard;
+extern rfb::BoolParameter sendClipboard;
+extern rfb::BoolParameter sendPrimary;
+
+extern rfb::StringParameter menuKey;
+
+#endif
diff --git a/vncviewer/vncviewer.cxx b/vncviewer/vncviewer.cxx
new file mode 100644 (file)
index 0000000..a6244cb
--- /dev/null
@@ -0,0 +1,250 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * Copyright 2011 Pierre Ossman <ossman@cendio.se> for Cendio AB
+ * 
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <signal.h>
+#include <locale.h>
+#include <sys/stat.h>
+
+#ifdef WIN32
+#include <direct.h>
+#define mkdir(path, mode) _mkdir(path)
+#endif
+
+#include <os/os.h>
+#include <rfb/Logger_stdio.h>
+#include <rfb/SecurityClient.h>
+#include <rfb/Security.h>
+#ifdef HAVE_GNUTLS
+#include <rfb/CSecurityTLS.h>
+#endif
+#include <rfb/LogWriter.h>
+#include <rfb/Timer.h>
+#include <network/TcpSocket.h>
+
+#include <FL/Fl.H>
+#include <FL/Fl_Widget.H>
+#include <FL/fl_ask.H>
+
+#include "i18n.h"
+#include "parameters.h"
+#include "CConn.h"
+#include "UserDialog.h"
+
+rfb::LogWriter vlog("main");
+
+using namespace network;
+using namespace rfb;
+using namespace std;
+
+char aboutText[1024];
+
+static bool exitMainloop = false;
+
+void exit_vncviewer()
+{
+  exitMainloop = true;
+}
+
+static void CleanupSignalHandler(int sig)
+{
+  // CleanupSignalHandler allows C++ object cleanup to happen because it calls
+  // exit() rather than the default which is to abort.
+  vlog.info("CleanupSignalHandler called");
+  exit(1);
+}
+
+static void init_fltk()
+{
+  // Basic text size (10pt @ 96 dpi => 13px)
+  FL_NORMAL_SIZE = 13;
+
+#ifndef __APPLE__
+  // Select a FLTK scheme and background color that looks somewhat
+  // close to modern Linux and Windows.
+  Fl::scheme("gtk+");
+  Fl::background(220, 220, 220);
+#else
+  // On Mac OS X there is another scheme that fits better though.
+  Fl::scheme("plastic");
+#endif
+
+  // This makes the "icon" in dialogs rounded, which fits better
+  // with the above schemes.
+  fl_message_icon()->box(FL_UP_BOX);
+
+  // Turn off the annoying behaviour where popups track the mouse.
+  fl_message_hotspot(false);
+
+  // Avoid empty titles for popups
+  fl_message_title_default(_("TigerVNC Viewer"));
+
+#ifdef WIN32
+  // Most "normal" Windows apps use this font for UI elements.
+  Fl::set_font(FL_HELVETICA, "Tahoma");
+#endif
+
+  // FLTK exposes these so that we can translate them.
+  fl_no     = _("No");
+  fl_yes    = _("Yes");
+  fl_ok     = _("OK");
+  fl_cancel = _("Cancel");
+  fl_close  = _("Close");
+}
+
+static void mkvnchomedir()
+{
+  // Create .vnc in the user's home directory if it doesn't already exist
+  char* homeDir = NULL;
+
+  if (getvnchomedir(&homeDir) == -1) {
+    vlog.error(_("Could not create VNC home directory: can't obtain home "
+                 "directory path."));
+  } else {
+    int result = mkdir(homeDir, 0755);
+    if (result == -1 && errno != EEXIST)
+      vlog.error(_("Could not create VNC home directory: %s."), strerror(errno));
+    delete [] homeDir;
+  }
+}
+
+static void usage(const char *programName)
+{
+  fprintf(stderr,
+          "\nusage: %s [parameters] [host:displayNum] [parameters]\n"
+          "       %s [parameters] -listen [port] [parameters]\n",
+          programName, programName);
+  fprintf(stderr,"\n"
+          "Parameters can be turned on with -<param> or off with -<param>=0\n"
+          "Parameters which take a value can be specified as "
+          "-<param> <value>\n"
+          "Other valid forms are <param>=<value> -<param>=<value> "
+          "--<param>=<value>\n"
+          "Parameter names are case-insensitive.  The parameters are:\n\n");
+  Configuration::listParams(79, 14);
+  exit(1);
+}
+
+int main(int argc, char** argv)
+{
+  char* vncServerName = 0;
+  UserDialog dlg;
+
+  const char englishAbout[] = N_("TigerVNC Viewer version %s\n"
+                                 "Copyright (C) 2002-2005 RealVNC Ltd.\n"
+                                 "Copyright (C) 2000-2006 TightVNC Group\n"
+                                 "Copyright (C) 2004-2009 Peter Astrand for Cendio AB\n"
+                                 "See http://www.tigervnc.org for information on TigerVNC.");
+
+  setlocale(LC_ALL, "");
+  bindtextdomain(PACKAGE_NAME, LOCALEDIR);
+  textdomain(PACKAGE_NAME);
+
+  rfb::SecurityClient::setDefaults();
+
+  // Write about text to console, still using normal locale codeset
+  snprintf(aboutText, sizeof(aboutText),
+           gettext(englishAbout), PACKAGE_VERSION);
+  fprintf(stderr,"\n%s\n", aboutText);
+
+  // Set gettext codeset to what our GUI toolkit uses. Since we are
+  // passing strings from strerror/gai_strerror to the GUI, these must
+  // be in GUI codeset as well.
+  bind_textdomain_codeset(PACKAGE_NAME, "UTF-8");
+  bind_textdomain_codeset("libc", "UTF-8");
+
+  // Re-create the aboutText for the GUI, now using GUI codeset
+  snprintf(aboutText, sizeof(aboutText),
+           gettext(englishAbout), PACKAGE_VERSION);
+
+  rfb::initStdIOLoggers();
+  rfb::LogWriter::setLogParams("*:stderr:30");
+
+#ifdef SIGHUP
+  signal(SIGHUP, CleanupSignalHandler);
+#endif
+  signal(SIGINT, CleanupSignalHandler);
+  signal(SIGTERM, CleanupSignalHandler);
+
+  init_fltk();
+
+  Configuration::enableViewerParams();
+
+  for (int i = 1; i < argc; i++) {
+    if (Configuration::setParam(argv[i]))
+      continue;
+
+    if (argv[i][0] == '-') {
+      if (i+1 < argc) {
+        if (Configuration::setParam(&argv[i][1], argv[i+1])) {
+          i++;
+          continue;
+        }
+      }
+      usage(argv[0]);
+    }
+
+    vncServerName = argv[i];
+  }
+
+  if (!::autoSelect.hasBeenSet()) {
+    // Default to AutoSelect=0 if -PreferredEncoding or -FullColor is used
+    ::autoSelect.setParam(!::preferredEncoding.hasBeenSet() &&
+                          !::fullColour.hasBeenSet() &&
+                          !::fullColourAlias.hasBeenSet());
+  }
+  if (!::fullColour.hasBeenSet() && !::fullColourAlias.hasBeenSet()) {
+    // Default to FullColor=0 if AutoSelect=0 && LowColorLevel is set
+    if (!::autoSelect && (::lowColourLevel.hasBeenSet() ||
+                          ::lowColourLevelAlias.hasBeenSet())) {
+      ::fullColour.setParam(false);
+    }
+  }
+  if (!::customCompressLevel.hasBeenSet()) {
+    // Default to CustomCompressLevel=1 if CompressLevel is used.
+    ::customCompressLevel.setParam(::compressLevel.hasBeenSet());
+  }
+
+  mkvnchomedir();
+
+  CSecurity::upg = &dlg;
+#ifdef HAVE_GNUTLS
+  CSecurityTLS::msg = &dlg;
+#endif
+
+  CConn cc(vncServerName);
+
+  while (!exitMainloop) {
+    int next_timer;
+
+    next_timer = Timer::checkTimeouts();
+    if (next_timer == 0)
+      next_timer = INT_MAX;
+
+    if (Fl::wait((double)next_timer / 1000.0) < 0.0) {
+      vlog.error(_("Internal FLTK error. Exiting."));
+      break;
+    }
+  }
+
+  return 0;
+}
index ab311aeede2f0770d5b07ef762ec52d1ccf7e87e..0bd5a3a4cca0fcaa951d2a74a40b59129a369cc0 100644 (file)
@@ -3,7 +3,10 @@ include_directories(${CMAKE_SOURCE_DIR}/common ${CMAKE_SOURCE_DIR}/win)
 configure_file(resdefs.h.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/resdefs.h)
 
 add_subdirectory(rfb_win32)
+
+if(NOT BUILD_NEW_VNCVIEWER)
 add_subdirectory(vncviewer)
+endif()
 
 if(BUILD_WINVNC)
 add_subdirectory(vncconfig)