current Unix vncviewer. git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@4345 3789f03b-4d11-0410-bbf8-ca57d06f2519tags/v1.1.90
@@ -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() |
@@ -2,4 +2,7 @@ add_subdirectory(tx) | |||
add_subdirectory(vncconfig) | |||
add_subdirectory(vncpasswd) | |||
if(NOT BUILD_NEW_VNCVIEWER) | |||
add_subdirectory(vncviewer) | |||
endif() |
@@ -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; | |||
} |
@@ -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 |
@@ -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}) |
@@ -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(); | |||
} |
@@ -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 |
@@ -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; | |||
} |
@@ -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 |
@@ -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 */ |
@@ -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 */ |
@@ -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"); | |||
@@ -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 |
@@ -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,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) |