Browse Source

Initial commit of new FLTK based vncviewer. Most of the code comes from the

current Unix vncviewer.


git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@4345 3789f03b-4d11-0410-bbf8-ca57d06f2519
tags/v1.1.90
Pierre Ossman 13 years ago
parent
commit
5156d5e49b

+ 14
- 0
CMakeLists.txt View 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()

+ 3
- 0
unix/CMakeLists.txt View File

@@ -2,4 +2,7 @@ add_subdirectory(tx)

add_subdirectory(vncconfig)
add_subdirectory(vncpasswd)

if(NOT BUILD_NEW_VNCVIEWER)
add_subdirectory(vncviewer)
endif()

+ 450
- 0
vncviewer/CConn.cxx View File

@@ -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;
}

+ 96
- 0
vncviewer/CConn.h View File

@@ -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

+ 12
- 0
vncviewer/CMakeLists.txt View File

@@ -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})

+ 186
- 0
vncviewer/DesktopWindow.cxx View File

@@ -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();
}

+ 110
- 0
vncviewer/DesktopWindow.h View File

@@ -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

+ 86
- 0
vncviewer/UserDialog.cxx View File

@@ -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;
}

+ 41
- 0
vncviewer/UserDialog.h View File

@@ -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

+ 271
- 0
vncviewer/gettext.h View File

@@ -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 */

+ 29
- 0
vncviewer/i18n.h View File

@@ -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 */

+ 90
- 0
vncviewer/parameters.cxx View File

@@ -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");


+ 53
- 0
vncviewer/parameters.h View File

@@ -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

+ 250
- 0
vncviewer/vncviewer.cxx View File

@@ -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;
}

+ 3
- 0
win/CMakeLists.txt View 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)

Loading…
Cancel
Save