aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--common/rfb/EncodeManager.cxx6
-rw-r--r--common/rfb/EncodeManager.h2
-rw-r--r--common/rfb/SConnection.cxx8
-rw-r--r--common/rfb/SConnection.h2
-rw-r--r--common/rfb/SDesktop.h25
-rw-r--r--common/rfb/Timer.cxx67
-rw-r--r--common/rfb/Timer.h77
-rw-r--r--common/rfb/VNCSConnectionST.cxx4
-rw-r--r--common/rfb/VNCSConnectionST.h2
-rw-r--r--common/rfb/VNCServer.h3
-rw-r--r--common/rfb/VNCServerST.cxx80
-rw-r--r--common/rfb/VNCServerST.h5
-rw-r--r--common/rfb/util.h7
-rw-r--r--unix/vncconfig/QueryConnectDialog.cxx5
-rw-r--r--unix/vncconfig/QueryConnectDialog.h2
-rw-r--r--unix/vncconfig/vncconfig.cxx2
-rw-r--r--unix/x0vncserver/XDesktop.cxx10
-rw-r--r--unix/x0vncserver/XDesktop.h3
-rw-r--r--unix/x0vncserver/x0vncserver.cxx7
-rw-r--r--unix/xserver/hw/vnc/Makefile.am4
-rw-r--r--unix/xserver/hw/vnc/XserverDesktop.cc46
-rw-r--r--unix/xserver/hw/vnc/XserverDesktop.h13
-rw-r--r--unix/xserver/hw/vnc/vncExtInit.cc29
-rw-r--r--unix/xserver/hw/vnc/vncExtInit.h6
-rw-r--r--unix/xserver/hw/vnc/vncPresent.c93
-rw-r--r--unix/xserver/hw/vnc/vncPresent.h27
-rw-r--r--unix/xserver/hw/vnc/xvnc.c11
-rw-r--r--vncviewer/EmulateMB.cxx6
-rw-r--r--vncviewer/EmulateMB.h2
-rw-r--r--vncviewer/GestureHandler.cxx4
-rw-r--r--vncviewer/GestureHandler.h2
-rw-r--r--vncviewer/vncviewer.cxx2
-rw-r--r--win/rfb_win32/EventManager.cxx6
-rw-r--r--win/rfb_win32/SDisplay.cxx12
-rw-r--r--win/rfb_win32/SDisplay.h3
-rw-r--r--win/rfb_win32/SocketManager.cxx6
36 files changed, 419 insertions, 170 deletions
diff --git a/common/rfb/EncodeManager.cxx b/common/rfb/EncodeManager.cxx
index bc15e74a..c2658a70 100644
--- a/common/rfb/EncodeManager.cxx
+++ b/common/rfb/EncodeManager.cxx
@@ -297,7 +297,7 @@ void EncodeManager::writeLosslessRefresh(const Region& req, const PixelBuffer* p
Region(), Point(), pb, renderedCursor);
}
-bool EncodeManager::handleTimeout(Timer* t)
+void EncodeManager::handleTimeout(Timer* t)
{
if (t == &recentChangeTimer) {
// Any lossy region that wasn't recently updated can
@@ -307,10 +307,8 @@ bool EncodeManager::handleTimeout(Timer* t)
// Will there be more to do? (i.e. do we need another round)
if (!lossyRegion.subtract(pendingRefreshRegion).is_empty())
- return true;
+ t->repeat();
}
-
- return false;
}
void EncodeManager::doUpdate(bool allowLossy, const Region& changed_,
diff --git a/common/rfb/EncodeManager.h b/common/rfb/EncodeManager.h
index f2fd4ca4..33484db8 100644
--- a/common/rfb/EncodeManager.h
+++ b/common/rfb/EncodeManager.h
@@ -61,7 +61,7 @@ namespace rfb {
size_t maxUpdateSize);
protected:
- virtual bool handleTimeout(Timer* t);
+ virtual void handleTimeout(Timer* t);
void doUpdate(bool allowLossy, const Region& changed,
const Region& copied, const Point& copy_delta,
diff --git a/common/rfb/SConnection.cxx b/common/rfb/SConnection.cxx
index 7a930af5..12ba0f1a 100644
--- a/common/rfb/SConnection.cxx
+++ b/common/rfb/SConnection.cxx
@@ -275,11 +275,11 @@ bool SConnection::processInitMsg()
return reader_->readClientInit();
}
-bool SConnection::handleAuthFailureTimeout(Timer* /*t*/)
+void SConnection::handleAuthFailureTimeout(Timer* /*t*/)
{
if (state_ != RFBSTATE_SECURITY_FAILURE) {
close("SConnection::handleAuthFailureTimeout: invalid state");
- return false;
+ return;
}
try {
@@ -292,12 +292,10 @@ bool SConnection::handleAuthFailureTimeout(Timer* /*t*/)
os->flush();
} catch (rdr::Exception& e) {
close(e.str());
- return false;
+ return;
}
close(authFailureMsg.c_str());
-
- return false;
}
void SConnection::throwConnFailedException(const char* format, ...)
diff --git a/common/rfb/SConnection.h b/common/rfb/SConnection.h
index cc88cd1e..5bc61677 100644
--- a/common/rfb/SConnection.h
+++ b/common/rfb/SConnection.h
@@ -238,7 +238,7 @@ namespace rfb {
bool processSecurityFailure();
bool processInitMsg();
- bool handleAuthFailureTimeout(Timer* t);
+ void handleAuthFailureTimeout(Timer* t);
int defaultMajorVersion, defaultMinorVersion;
diff --git a/common/rfb/SDesktop.h b/common/rfb/SDesktop.h
index 9db08116..94e4b028 100644
--- a/common/rfb/SDesktop.h
+++ b/common/rfb/SDesktop.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- * Copyright 2009-2019 Pierre Ossman for Cendio AB
+ * Copyright 2009-2024 Pierre Ossman 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
@@ -49,20 +49,21 @@ namespace rfb {
class SDesktop : public InputHandler {
public:
+ // init() is called immediately when the VNCServer gets a reference
+ // to the SDesktop, so that a reverse reference can be set up.
+ virtual void init(rfb::VNCServer* vs) = 0;
+
// start() is called by the server when the first client authenticates
// successfully, and can be used to begin any expensive tasks which are not
// needed when there are no clients. A valid PixelBuffer must have been
// set via the VNCServer's setPixelBuffer() method by the time this call
// returns.
-
- virtual void start(VNCServer* vs) = 0;
+ virtual void start() {}
// stop() is called by the server when there are no longer any
// authenticated clients, and therefore the desktop can cease any
- // expensive tasks. No further calls to the VNCServer passed to start()
- // can be made once stop has returned.
-
- virtual void stop() = 0;
+ // expensive tasks.
+ virtual void stop() {}
// queryConnection() is called when a connection has been
// successfully authenticated. The sock and userName arguments
@@ -86,6 +87,10 @@ namespace rfb {
return resultProhibited;
}
+ // frameTick() is called whenever a frame update has been processed,
+ // signalling that a good time to render new data
+ virtual void frameTick(uint64_t msc) { (void)msc; }
+
// InputHandler interface
// pointerEvent(), keyEvent() and clientCutText() are called in response to
// the relevant RFB protocol messages from clients.
@@ -136,14 +141,10 @@ namespace rfb {
if (buffer) delete buffer;
}
- virtual void start(VNCServer* vs) {
+ virtual void init(VNCServer* vs) {
server = vs;
server->setPixelBuffer(buffer);
}
- virtual void stop() {
- server->setPixelBuffer(0);
- server = 0;
- }
virtual void queryConnection(network::Socket* sock,
const char* /*userName*/) {
server->approveConnection(sock, true, NULL);
diff --git a/common/rfb/Timer.cxx b/common/rfb/Timer.cxx
index 4ff15bc5..e9ae5227 100644
--- a/common/rfb/Timer.cxx
+++ b/common/rfb/Timer.cxx
@@ -1,5 +1,5 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- * Copyright 2016-2018 Pierre Ossman for Cendio AB
+ * Copyright 2016-2024 Pierre Ossman 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
@@ -61,36 +61,20 @@ int Timer::checkTimeouts() {
timeval start;
if (pending.empty())
- return 0;
+ return -1;
gettimeofday(&start, 0);
while (pending.front()->isBefore(start)) {
Timer* timer;
- timeval before;
timer = pending.front();
pending.pop_front();
- gettimeofday(&before, 0);
- if (timer->cb->handleTimeout(timer)) {
- timeval now;
+ timer->lastDueTime = timer->dueTime;
+ timer->cb->handleTimeout(timer);
- gettimeofday(&now, 0);
-
- timer->dueTime = addMillis(timer->dueTime, timer->timeoutMs);
- if (timer->isBefore(now)) {
- // Time has jumped forwards, or we're not getting enough
- // CPU time for the timers
-
- timer->dueTime = addMillis(before, timer->timeoutMs);
- if (timer->isBefore(now))
- timer->dueTime = now;
- }
-
- insertTimer(timer);
- } else if (pending.empty()) {
- return 0;
- }
+ if (pending.empty())
+ return -1;
}
return getNextTimeout();
}
@@ -98,7 +82,12 @@ int Timer::checkTimeouts() {
int Timer::getNextTimeout() {
timeval now;
gettimeofday(&now, 0);
- int toWait = __rfbmax(1, pending.front()->getRemainingMs());
+
+ if (pending.empty())
+ return -1;
+
+ int toWait = pending.front()->getRemainingMs();
+
if (toWait > pending.front()->timeoutMs) {
if (toWait - pending.front()->timeoutMs < 1000) {
vlog.info("gettimeofday is broken...");
@@ -107,8 +96,9 @@ int Timer::getNextTimeout() {
// Time has jumped backwards!
vlog.info("time has moved backwards!");
pending.front()->dueTime = now;
- toWait = 1;
+ toWait = 0;
}
+
return toWait;
}
@@ -128,13 +118,36 @@ void Timer::start(int timeoutMs_) {
gettimeofday(&now, 0);
stop();
timeoutMs = timeoutMs_;
- // The rest of the code assumes non-zero timeout
- if (timeoutMs <= 0)
- timeoutMs = 1;
dueTime = addMillis(now, timeoutMs);
insertTimer(this);
}
+void Timer::repeat(int timeoutMs_) {
+ timeval now;
+
+ gettimeofday(&now, 0);
+
+ if (isStarted()) {
+ vlog.error("Incorrectly repeating already running timer");
+ stop();
+ }
+
+ if (msBetween(&lastDueTime, &dueTime) != 0)
+ vlog.error("Timer incorrectly modified whilst repeating");
+
+ if (timeoutMs_ != -1)
+ timeoutMs = timeoutMs_;
+
+ dueTime = addMillis(lastDueTime, timeoutMs);
+ if (isBefore(now)) {
+ // Time has jumped forwards, or we're not getting enough
+ // CPU time for the timers
+ dueTime = now;
+ }
+
+ insertTimer(this);
+}
+
void Timer::stop() {
pending.remove(this);
}
diff --git a/common/rfb/Timer.h b/common/rfb/Timer.h
index ddfce1b2..36ec46c5 100644
--- a/common/rfb/Timer.h
+++ b/common/rfb/Timer.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- * Copyright 2018 Pierre Ossman for Cendio AB
+ * Copyright 2018-2024 Pierre Ossman 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
@@ -27,93 +27,108 @@ namespace rfb {
/* Timer
- Cross-platform timeout handling. The caller creates instances of Timer and passes a
- Callback implementation to each. The Callback will then be called with a pointer to
- the Timer instance that timed-out when the timeout occurs.
+ Cross-platform timeout handling. The caller creates instances of
+ Timer and passes a Callback implementation to each. The Callback
+ will then be called with a pointer to the Timer instance that
+ timed-out when the timeout occurs.
- The static methods of Timer are used by the main loop of the application both to
- dispatch elapsed Timer callbacks and to determine how long to wait in select() for
- the next timeout to occur.
+ The static methods of Timer are used by the main loop of the
+ application both to dispatch elapsed Timer callbacks and to
+ determine how long to wait in select() for the next timeout to
+ occur.
- For classes that can be derived it's best to use MethodTimer which can call a specific
- method on the class, thus avoiding conflicts when subclassing.
+ For classes that can be derived it's best to use MethodTimer which
+ can call a specific method on the class, thus avoiding conflicts
+ when subclassing.
*/
struct Timer {
struct Callback {
// handleTimeout
- // Passed a pointer to the Timer that has timed out. If the handler returns true
- // then the Timer is reset and left running, causing another timeout after the
- // appropriate interval.
+ // Passed a pointer to the Timer that has timed out. If the
+ // handler returns true then the Timer is reset and left
+ // running, causing another timeout after the appropriate
+ // interval.
// If the handler returns false then the Timer is cancelled.
- virtual bool handleTimeout(Timer* t) = 0;
+ virtual void handleTimeout(Timer* t) = 0;
virtual ~Callback() {}
};
// checkTimeouts()
- // Dispatches any elapsed Timers, and returns the number of milliseconds until the
- // next Timer will timeout.
+ // Dispatches any elapsed Timers, and returns the number of
+ // milliseconds until the next Timer will timeout.
static int checkTimeouts();
// getNextTimeout()
- // Returns the number of milliseconds until the next timeout, without dispatching
- // any elapsed Timers.
+ // Returns the number of milliseconds until the next timeout,
+ // without dispatching any elapsed Timers.
static int getNextTimeout();
// Create a Timer with the specified callback handler
Timer(Callback* cb_) {cb = cb_;}
~Timer() {stop();}
- // startTimer
- // Starts the timer, causing a timeout after the specified number of milliseconds.
- // If the timer is already active then it will be implicitly cancelled and re-started.
+ // start()
+ // Starts the timer, causing a timeout after the specified number
+ // of milliseconds. If the timer is already active then it will
+ // be implicitly cancelled and re-started.
void start(int timeoutMs_);
- // stopTimer
+ // repeat()
+ // Restarts the timer in a way that repeats that last timeout.
+ // This allows you to have a periodic timer without the risk of
+ // accumulating drift caused by processing delays.
+ // A new interval can be specified, otherwise the previous
+ // interval is reused.
+ void repeat(int timeoutMs_=-1);
+
+ // stop()
// Cancels the timer.
void stop();
- // isStarted
+ // isStarted()
// Determines whether the timer is started.
bool isStarted();
- // getTimeoutMs
+ // getTimeoutMs()
// Determines the previously used timeout value, if any.
// Usually used with isStarted() to get the _current_ timeout.
int getTimeoutMs();
- // getRemainingMs
+ // getRemainingMs()
// Determines how many milliseconds are left before the Timer
// will timeout. Only valid for an active timer.
int getRemainingMs();
- // isBefore
- // Determine whether the Timer will timeout before the specified time.
+ // isBefore()
+ // Determine whether the Timer will timeout before the specified
+ // time.
bool isBefore(timeval other);
protected:
- timeval dueTime;
+ timeval dueTime, lastDueTime;
int timeoutMs;
Callback* cb;
static void insertTimer(Timer* t);
- // The list of currently active Timers, ordered by time left until timeout.
+ // The list of currently active Timers, ordered by time left until
+ // timeout.
static std::list<Timer*> pending;
};
template<class T> class MethodTimer
: public Timer, public Timer::Callback {
public:
- MethodTimer(T* obj_, bool (T::*cb_)(Timer*))
+ MethodTimer(T* obj_, void (T::*cb_)(Timer*))
: Timer(this), obj(obj_), cb(cb_) {}
- virtual bool handleTimeout(Timer* t) { return (obj->*cb)(t); }
+ virtual void handleTimeout(Timer* t) { (obj->*cb)(t); }
private:
T* obj;
- bool (T::*cb)(Timer*);
+ void (T::*cb)(Timer*);
};
};
diff --git a/common/rfb/VNCSConnectionST.cxx b/common/rfb/VNCSConnectionST.cxx
index f1194eb6..306bba1d 100644
--- a/common/rfb/VNCSConnectionST.cxx
+++ b/common/rfb/VNCSConnectionST.cxx
@@ -800,7 +800,7 @@ void VNCSConnectionST::supportsLEDState()
writer()->writeLEDState();
}
-bool VNCSConnectionST::handleTimeout(Timer* t)
+void VNCSConnectionST::handleTimeout(Timer* t)
{
try {
if ((t == &congestionTimer) ||
@@ -812,8 +812,6 @@ bool VNCSConnectionST::handleTimeout(Timer* t)
if (t == &idleTimer)
close("Idle timeout");
-
- return false;
}
bool VNCSConnectionST::isShiftPressed()
diff --git a/common/rfb/VNCSConnectionST.h b/common/rfb/VNCSConnectionST.h
index 2f117a75..3a9ec242 100644
--- a/common/rfb/VNCSConnectionST.h
+++ b/common/rfb/VNCSConnectionST.h
@@ -141,7 +141,7 @@ namespace rfb {
virtual void supportsLEDState();
// Timer callbacks
- virtual bool handleTimeout(Timer* t);
+ virtual void handleTimeout(Timer* t);
// Internal methods
diff --git a/common/rfb/VNCServer.h b/common/rfb/VNCServer.h
index cf14bd86..3ac9fb94 100644
--- a/common/rfb/VNCServer.h
+++ b/common/rfb/VNCServer.h
@@ -73,6 +73,9 @@ namespace rfb {
virtual void blockUpdates() = 0;
virtual void unblockUpdates() = 0;
+ virtual uint64_t getMsc() = 0;
+ virtual void queueMsc(uint64_t target) = 0;
+
// setPixelBuffer() tells the server to use the given pixel buffer (and
// optionally a modified screen layout). If this differs in size from
// the previous pixel buffer, this may result in protocol messages being
diff --git a/common/rfb/VNCServerST.cxx b/common/rfb/VNCServerST.cxx
index fb421068..b9579f12 100644
--- a/common/rfb/VNCServerST.cxx
+++ b/common/rfb/VNCServerST.cxx
@@ -1,5 +1,5 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- * Copyright 2009-2019 Pierre Ossman for Cendio AB
+ * Copyright 2009-2024 Pierre Ossman 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
@@ -90,10 +90,12 @@ VNCServerST::VNCServerST(const char* name_, SDesktop* desktop_)
renderedCursorInvalid(false),
keyRemapper(&KeyRemapper::defInstance),
idleTimer(this), disconnectTimer(this), connectTimer(this),
- frameTimer(this)
+ msc(0), queuedMsc(0), frameTimer(this)
{
slog.debug("creating single-threaded server %s", name.c_str());
+ desktop_->init(this);
+
// FIXME: Do we really want to kick off these right away?
if (rfb::Server::maxIdleTime)
idleTimer.start(secsToMillis(rfb::Server::maxIdleTime));
@@ -248,11 +250,22 @@ void VNCServerST::unblockUpdates()
blockCounter--;
- // Restart the frame clock if we have updates
- if (blockCounter == 0) {
- if (!comparer->is_empty())
- startFrameClock();
- }
+ // Restart the frame clock in case we have updates
+ if (blockCounter == 0)
+ startFrameClock();
+}
+
+uint64_t VNCServerST::getMsc()
+{
+ return msc;
+}
+
+void VNCServerST::queueMsc(uint64_t target)
+{
+ if (target > queuedMsc)
+ queuedMsc = target;
+
+ startFrameClock();
}
void VNCServerST::setPixelBuffer(PixelBuffer* pb_, const ScreenSet& layout)
@@ -623,22 +636,33 @@ SConnection* VNCServerST::getConnection(network::Socket* sock) {
return 0;
}
-bool VNCServerST::handleTimeout(Timer* t)
+void VNCServerST::handleTimeout(Timer* t)
{
if (t == &frameTimer) {
- // We keep running until we go a full interval without any updates
- if (comparer->is_empty())
- return false;
+ int timeout;
- writeUpdate();
+ // We keep running until we go a full interval without any updates,
+ // or there are no active clients anymore
+ if (comparer->is_empty() || !desktopStarted) {
+ // Unless something waits for us to advance the frame count
+ if (queuedMsc < msc)
+ return;
+ }
// If this is the first iteration then we need to adjust the timeout
- if (frameTimer.getTimeoutMs() != 1000/rfb::Server::frameRate) {
- frameTimer.start(1000/rfb::Server::frameRate);
- return false;
- }
+ timeout = 1000/rfb::Server::frameRate;
- return true;
+ // If there are no clients, then slow down the clock
+ if (!desktopStarted)
+ timeout = 1000;
+
+ frameTimer.repeat(timeout);
+
+ if (!comparer->is_empty() && desktopStarted)
+ writeUpdate();
+
+ msc++;
+ desktop->frameTick(msc);
} else if (t == &idleTimer) {
slog.info("MaxIdleTime reached, exiting");
desktop->terminate();
@@ -649,8 +673,6 @@ bool VNCServerST::handleTimeout(Timer* t)
slog.info("MaxConnectionTime reached, exiting");
desktop->terminate();
}
-
- return false;
}
void VNCServerST::queryConnection(VNCSConnectionST* client,
@@ -714,7 +736,7 @@ void VNCServerST::startDesktop()
{
if (!desktopStarted) {
slog.debug("starting desktop");
- desktop->start(this);
+ desktop->start();
if (!pb)
throw Exception("SDesktop::start() did not set a valid PixelBuffer");
desktopStarted = true;
@@ -722,6 +744,12 @@ void VNCServerST::startDesktop()
// stopped, so flush those out
if (!comparer->is_empty())
writeUpdate();
+ // If the frame clock is running, then it will be running slowly,
+ // so give it a kick to run at normal speed right away
+ if (frameTimer.isStarted()) {
+ stopFrameClock();
+ startFrameClock();
+ }
}
}
@@ -731,7 +759,6 @@ void VNCServerST::stopDesktop()
slog.debug("stopping desktop");
desktopStarted = false;
desktop->stop();
- stopFrameClock();
}
}
@@ -759,9 +786,18 @@ void VNCServerST::startFrameClock()
return;
if (blockCounter > 0)
return;
- if (!desktopStarted)
+
+ // Anyone actually interested in frames?
+ if (comparer->is_empty() && (queuedMsc <= msc))
return;
+ // Run the frame clock very slowly if there are no clients to actually
+ // send updates to
+ if (!desktopStarted) {
+ frameTimer.start(1000);
+ return;
+ }
+
// The first iteration will be just half a frame as we get a very
// unstable update rate if we happen to be perfectly in sync with
// the application's update rate
diff --git a/common/rfb/VNCServerST.h b/common/rfb/VNCServerST.h
index d303831e..90c8d753 100644
--- a/common/rfb/VNCServerST.h
+++ b/common/rfb/VNCServerST.h
@@ -79,6 +79,8 @@ namespace rfb {
virtual void blockUpdates();
virtual void unblockUpdates();
+ virtual uint64_t getMsc();
+ virtual void queueMsc(uint64_t target);
virtual void setPixelBuffer(PixelBuffer* pb, const ScreenSet& layout);
virtual void setPixelBuffer(PixelBuffer* pb);
virtual void setScreenLayout(const ScreenSet& layout);
@@ -153,7 +155,7 @@ namespace rfb {
protected:
// Timer callbacks
- virtual bool handleTimeout(Timer* t);
+ virtual void handleTimeout(Timer* t);
// - Internal methods
@@ -204,6 +206,7 @@ namespace rfb {
Timer disconnectTimer;
Timer connectTimer;
+ uint64_t msc, queuedMsc;
Timer frameTimer;
};
diff --git a/common/rfb/util.h b/common/rfb/util.h
index cafea209..b47ac4c9 100644
--- a/common/rfb/util.h
+++ b/common/rfb/util.h
@@ -73,13 +73,6 @@ namespace rfb {
// HELPER functions for timeout handling
- // soonestTimeout() is a function to help work out the soonest of several
- // timeouts.
- inline void soonestTimeout(int* timeout, int newTimeout) {
- if (newTimeout && (!*timeout || newTimeout < *timeout))
- *timeout = newTimeout;
- }
-
// secsToMillis() turns seconds into milliseconds, capping the value so it
// can't wrap round and become -ve
inline int secsToMillis(int secs) {
diff --git a/unix/vncconfig/QueryConnectDialog.cxx b/unix/vncconfig/QueryConnectDialog.cxx
index e13af34b..e725de7d 100644
--- a/unix/vncconfig/QueryConnectDialog.cxx
+++ b/unix/vncconfig/QueryConnectDialog.cxx
@@ -74,14 +74,13 @@ void QueryConnectDialog::buttonActivate(TXButton* b) {
callback->queryRejected();
}
-bool QueryConnectDialog::handleTimeout(rfb::Timer* /*t*/) {
+void QueryConnectDialog::handleTimeout(rfb::Timer* t) {
if (timeUntilReject-- == 0) {
unmap();
callback->queryTimedOut();
- return false;
} else {
refreshTimeout();
- return true;
+ t->repeat();
}
}
diff --git a/unix/vncconfig/QueryConnectDialog.h b/unix/vncconfig/QueryConnectDialog.h
index f685dc34..dcf64e40 100644
--- a/unix/vncconfig/QueryConnectDialog.h
+++ b/unix/vncconfig/QueryConnectDialog.h
@@ -43,7 +43,7 @@ class QueryConnectDialog : public TXDialog, public TXEventHandler,
void handleEvent(TXWindow*, XEvent* ) { }
void deleteWindow(TXWindow*);
void buttonActivate(TXButton* b);
- bool handleTimeout(rfb::Timer* t);
+ void handleTimeout(rfb::Timer* t);
private:
void refreshTimeout();
TXLabel addressLbl, address, userLbl, user, timeoutLbl, timeout;
diff --git a/unix/vncconfig/vncconfig.cxx b/unix/vncconfig/vncconfig.cxx
index e0c9928a..30d04ca6 100644
--- a/unix/vncconfig/vncconfig.cxx
+++ b/unix/vncconfig/vncconfig.cxx
@@ -313,7 +313,7 @@ int main(int argc, char** argv)
// Process expired timers and get the time until the next one
int timeoutMs = Timer::checkTimeouts();
- if (timeoutMs) {
+ if (timeoutMs >= 0) {
tv.tv_sec = timeoutMs / 1000;
tv.tv_usec = (timeoutMs % 1000) * 1000;
tvp = &tv;
diff --git a/unix/x0vncserver/XDesktop.cxx b/unix/x0vncserver/XDesktop.cxx
index da298d35..55ea9667 100644
--- a/unix/x0vncserver/XDesktop.cxx
+++ b/unix/x0vncserver/XDesktop.cxx
@@ -232,9 +232,13 @@ void XDesktop::poll() {
}
}
+void XDesktop::init(VNCServer* vs)
+{
+ server = vs;
+}
-void XDesktop::start(VNCServer* vs) {
-
+void XDesktop::start()
+{
// Determine actual number of buttons of the X pointer device.
unsigned char btnMap[8];
int numButtons = XGetPointerMapping(dpy, btnMap, 8);
@@ -249,7 +253,6 @@ void XDesktop::start(VNCServer* vs) {
pb = new XPixelBuffer(dpy, factory, geometry->getRect());
vlog.info("Allocated %s", pb->getImage()->classDesc());
- server = vs;
server->setPixelBuffer(pb, computeScreenLayout());
#ifdef HAVE_XDAMAGE
@@ -292,7 +295,6 @@ void XDesktop::stop() {
queryConnectDialog = 0;
server->setPixelBuffer(0);
- server = 0;
delete pb;
pb = 0;
diff --git a/unix/x0vncserver/XDesktop.h b/unix/x0vncserver/XDesktop.h
index 1cb73f43..fc230e5b 100644
--- a/unix/x0vncserver/XDesktop.h
+++ b/unix/x0vncserver/XDesktop.h
@@ -47,7 +47,8 @@ public:
virtual ~XDesktop();
void poll();
// -=- SDesktop interface
- virtual void start(rfb::VNCServer* vs);
+ virtual void init(rfb::VNCServer* vs);
+ virtual void start();
virtual void stop();
virtual void terminate();
bool isRunning();
diff --git a/unix/x0vncserver/x0vncserver.cxx b/unix/x0vncserver/x0vncserver.cxx
index 8e27e62b..ffaf5788 100644
--- a/unix/x0vncserver/x0vncserver.cxx
+++ b/unix/x0vncserver/x0vncserver.cxx
@@ -382,7 +382,7 @@ int main(int argc, char** argv)
PollingScheduler sched((int)pollingCycle, (int)maxProcessorUsage);
while (!caughtSignal) {
- int wait_ms;
+ int wait_ms, nextTimeout;
struct timeval tv;
fd_set rfds, wfds;
std::list<Socket*> sockets;
@@ -426,7 +426,10 @@ int main(int argc, char** argv)
}
}
- soonestTimeout(&wait_ms, Timer::checkTimeouts());
+ // Trigger timers and check when the next will expire
+ nextTimeout = Timer::checkTimeouts();
+ if (nextTimeout >= 0 && nextTimeout < wait_ms)
+ wait_ms = nextTimeout;
tv.tv_sec = wait_ms / 1000;
tv.tv_usec = (wait_ms % 1000) * 1000;
diff --git a/unix/xserver/hw/vnc/Makefile.am b/unix/xserver/hw/vnc/Makefile.am
index 1e985966..40eba4f2 100644
--- a/unix/xserver/hw/vnc/Makefile.am
+++ b/unix/xserver/hw/vnc/Makefile.am
@@ -11,12 +11,12 @@ COMMON_LIBS=$(NETWORK_LIB) $(RFB_LIB) $(RDR_LIB) $(OS_LIB) $(UNIXCOMMON_LIB)
noinst_LTLIBRARIES = libvnccommon.la
HDRS = vncExtInit.h vncHooks.h \
- vncBlockHandler.h vncSelection.h \
+ vncBlockHandler.h vncPresent.h vncSelection.h \
XorgGlue.h XserverDesktop.h xorg-version.h \
vncInput.h RFBGlue.h
libvnccommon_la_SOURCES = $(HDRS) \
- vncExt.c vncExtInit.cc vncHooks.c vncSelection.c \
+ vncExt.c vncExtInit.cc vncHooks.c vncPresent.c vncSelection.c \
vncBlockHandler.c XorgGlue.c RandrGlue.c RFBGlue.cc XserverDesktop.cc \
vncInput.c vncInputXKB.c qnum_to_xorgevdev.c qnum_to_xorgkbd.c
diff --git a/unix/xserver/hw/vnc/XserverDesktop.cc b/unix/xserver/hw/vnc/XserverDesktop.cc
index 4cf37937..d4ee16b8 100644
--- a/unix/xserver/hw/vnc/XserverDesktop.cc
+++ b/unix/xserver/hw/vnc/XserverDesktop.cc
@@ -1,5 +1,5 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- * Copyright 2009-2019 Pierre Ossman for Cendio AB
+ * Copyright 2009-2024 Pierre Ossman for Cendio AB
* Copyright 2014 Brian P. Hinz
*
* This is free software; you can redistribute it and/or modify
@@ -54,6 +54,7 @@
extern "C" {
void vncSetGlueContext(int screenIndex);
+void vncPresentMscEvent(uint64_t id, uint64_t msc);
}
using namespace rfb;
@@ -145,15 +146,26 @@ void XserverDesktop::refreshScreenLayout()
server->setScreenLayout(::computeScreenLayout(&outputIdMap));
}
-void XserverDesktop::start(rfb::VNCServer* vs)
+uint64_t XserverDesktop::getMsc()
{
- // We already own the server object, and we always keep it in a
- // ready state
- assert(vs == server);
+ return server->getMsc();
+}
+
+void XserverDesktop::queueMsc(uint64_t id, uint64_t msc)
+{
+ pendingMsc[id] = msc;
+ server->queueMsc(msc);
}
-void XserverDesktop::stop()
+void XserverDesktop::abortMsc(uint64_t id)
{
+ pendingMsc.erase(id);
+}
+
+void XserverDesktop::init(rfb::VNCServer* vs)
+{
+ // We already own the server object, and we always keep it in a
+ // ready state
}
void XserverDesktop::queryConnection(network::Socket* sock,
@@ -395,7 +407,7 @@ void XserverDesktop::blockHandler(int* timeout)
// Trigger timers and check when the next will expire
int nextTimeout = Timer::checkTimeouts();
- if (nextTimeout > 0 && (*timeout == -1 || nextTimeout < *timeout))
+ if (nextTimeout >= 0 && (*timeout == -1 || nextTimeout < *timeout))
*timeout = nextTimeout;
} catch (rdr::Exception& e) {
vlog.error("XserverDesktop::blockHandler: %s",e.str());
@@ -476,6 +488,22 @@ unsigned int XserverDesktop::setScreenLayout(int fb_width, int fb_height,
return result;
}
+void XserverDesktop::frameTick(uint64_t msc)
+{
+ std::map<uint64_t, uint64_t>::iterator iter, next;
+
+ for (iter = pendingMsc.begin(); iter != pendingMsc.end();) {
+ next = iter; next++;
+
+ if (iter->second <= msc) {
+ pendingMsc.erase(iter->first);
+ vncPresentMscEvent(iter->first, msc);
+ }
+
+ iter = next;
+ }
+}
+
void XserverDesktop::handleClipboardRequest()
{
vncHandleClipboardRequest();
@@ -518,13 +546,11 @@ void XserverDesktop::keyEvent(uint32_t keysym, uint32_t keycode, bool down)
vncKeyboardEvent(keysym, keycode, down);
}
-bool XserverDesktop::handleTimeout(Timer* t)
+void XserverDesktop::handleTimeout(Timer* t)
{
if (t == &queryConnectTimer) {
server->approveConnection(queryConnectSocket, false,
"The attempt to prompt the user to "
"accept the connection failed");
}
-
- return false;
}
diff --git a/unix/xserver/hw/vnc/XserverDesktop.h b/unix/xserver/hw/vnc/XserverDesktop.h
index 9cc5bf79..e604295b 100644
--- a/unix/xserver/hw/vnc/XserverDesktop.h
+++ b/unix/xserver/hw/vnc/XserverDesktop.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- * Copyright 2009-2019 Pierre Ossman for Cendio AB
+ * Copyright 2009-2024 Pierre Ossman 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
@@ -59,6 +59,9 @@ public:
void unblockUpdates();
void setFramebuffer(int w, int h, void* fbptr, int stride);
void refreshScreenLayout();
+ uint64_t getMsc();
+ void queueMsc(uint64_t id, uint64_t msc);
+ void abortMsc(uint64_t id);
void requestClipboard();
void announceClipboard(bool available);
void sendClipboardData(const char* data);
@@ -88,8 +91,7 @@ public:
const char* rejectMsg=0);
// rfb::SDesktop callbacks
- virtual void start(rfb::VNCServer* vs);
- virtual void stop();
+ virtual void init(rfb::VNCServer* vs);
virtual void terminate();
virtual void queryConnection(network::Socket* sock,
const char* userName);
@@ -97,6 +99,7 @@ public:
virtual void keyEvent(uint32_t keysym, uint32_t keycode, bool down);
virtual unsigned int setScreenLayout(int fb_width, int fb_height,
const rfb::ScreenSet& layout);
+ virtual void frameTick(uint64_t msc);
virtual void handleClipboardRequest();
virtual void handleClipboardAnnounce(bool available);
virtual void handleClipboardData(const char* data);
@@ -112,7 +115,7 @@ protected:
rfb::VNCServer* sockserv,
bool read, bool write);
- virtual bool handleTimeout(rfb::Timer* t);
+ virtual void handleTimeout(rfb::Timer* t);
private:
@@ -129,6 +132,8 @@ private:
OutputIdMap outputIdMap;
+ std::map<uint64_t, uint64_t> pendingMsc;
+
rfb::Point oldCursorPos;
};
#endif
diff --git a/unix/xserver/hw/vnc/vncExtInit.cc b/unix/xserver/hw/vnc/vncExtInit.cc
index b260e626..4003e768 100644
--- a/unix/xserver/hw/vnc/vncExtInit.cc
+++ b/unix/xserver/hw/vnc/vncExtInit.cc
@@ -1,5 +1,5 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- * Copyright 2011-2019 Pierre Ossman for Cendio AB
+ * Copyright 2011-2024 Pierre Ossman 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
@@ -484,6 +484,33 @@ void vncRefreshScreenLayout(int scrIdx)
}
}
+uint64_t vncGetMsc(int scrIdx)
+{
+ try {
+ return desktop[scrIdx]->getMsc();
+ } catch (rdr::Exception& e) {
+ vncFatalError("vncGetMsc: %s\n", e.str());
+ }
+}
+
+void vncQueueMsc(int scrIdx, uint64_t id, uint64_t msc)
+{
+ try {
+ desktop[scrIdx]->queueMsc(id, msc);
+ } catch (rdr::Exception& e) {
+ vncFatalError("vncQueueMsc: %s\n", e.str());
+ }
+}
+
+void vncAbortMsc(int scrIdx, uint64_t id)
+{
+ try {
+ desktop[scrIdx]->abortMsc(id);
+ } catch (rdr::Exception& e) {
+ vncFatalError("vncAbortMsc: %s\n", e.str());
+ }
+}
+
int vncOverrideParam(const char *nameAndValue)
{
const char* equalSign = strchr(nameAndValue, '=');
diff --git a/unix/xserver/hw/vnc/vncExtInit.h b/unix/xserver/hw/vnc/vncExtInit.h
index 333e32a9..6b37fe62 100644
--- a/unix/xserver/hw/vnc/vncExtInit.h
+++ b/unix/xserver/hw/vnc/vncExtInit.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- * Copyright 2011-2019 Pierre Ossman for Cendio AB
+ * Copyright 2011-2024 Pierre Ossman 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
@@ -87,6 +87,10 @@ void vncPreScreenResize(int scrIdx);
void vncPostScreenResize(int scrIdx, int success, int width, int height);
void vncRefreshScreenLayout(int scrIdx);
+uint64_t vncGetMsc(int scrIdx);
+void vncQueueMsc(int scrIdx, uint64_t id, uint64_t msc);
+void vncAbortMsc(int scrIdx, uint64_t id);
+
int vncOverrideParam(const char *nameAndValue);
#ifdef __cplusplus
diff --git a/unix/xserver/hw/vnc/vncPresent.c b/unix/xserver/hw/vnc/vncPresent.c
new file mode 100644
index 00000000..89dcc1d0
--- /dev/null
+++ b/unix/xserver/hw/vnc/vncPresent.c
@@ -0,0 +1,93 @@
+/* Copyright 2024 Pierre Ossman 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.
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include "vncExtInit.h"
+#include "vncPresent.h"
+
+#include <present.h>
+
+static RRCrtcPtr vncPresentGetCrtc(WindowPtr window)
+{
+ ScreenPtr pScreen = window->drawable.pScreen;
+ rrScrPrivPtr rp = rrGetScrPriv(pScreen);
+
+ /* All output is synchronized, so just pick the first active crtc */
+ for (int c = 0; c < rp->numCrtcs; c++) {
+ RRCrtcPtr crtc;
+
+ crtc = rp->crtcs[c];
+ if (crtc->mode == NULL)
+ continue;
+
+ return crtc;
+ }
+
+ return NULL;
+}
+
+static int vncPresentGetUstMsc(RRCrtcPtr crtc, CARD64 *ust, CARD64 *msc)
+{
+ *ust = GetTimeInMicros();
+ *msc = vncGetMsc(crtc->pScreen->myNum);
+
+ return Success;
+}
+
+static int vncPresentQueueVBlank(RRCrtcPtr crtc, uint64_t event_id,
+ uint64_t msc)
+{
+ vncQueueMsc(crtc->pScreen->myNum, event_id, msc);
+ return Success;
+}
+
+void vncPresentMscEvent(uint64_t id, uint64_t msc)
+{
+ present_event_notify(id, GetTimeInMicros(), msc);
+}
+
+static void vncPresentAbortVBlank(RRCrtcPtr crtc, uint64_t event_id,
+ uint64_t msc)
+{
+ vncAbortMsc(crtc->pScreen->myNum, event_id);
+}
+
+static void vncPresentFlush(WindowPtr window)
+{
+}
+
+static present_screen_info_rec vncPresentScreenInfo = {
+ .version = PRESENT_SCREEN_INFO_VERSION,
+
+ .get_crtc = vncPresentGetCrtc,
+ .get_ust_msc = vncPresentGetUstMsc,
+ .queue_vblank = vncPresentQueueVBlank,
+ .abort_vblank = vncPresentAbortVBlank,
+ .flush = vncPresentFlush,
+
+ .capabilities = PresentCapabilityNone,
+};
+
+Bool
+vncPresentInit(ScreenPtr screen)
+{
+ return present_screen_init(screen, &vncPresentScreenInfo);
+} \ No newline at end of file
diff --git a/unix/xserver/hw/vnc/vncPresent.h b/unix/xserver/hw/vnc/vncPresent.h
new file mode 100644
index 00000000..17407402
--- /dev/null
+++ b/unix/xserver/hw/vnc/vncPresent.h
@@ -0,0 +1,27 @@
+/* Copyright 2024 Pierre Ossman 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 __PRESENT_H__
+#define __PRESENT_H__
+
+#include <dix.h>
+
+Bool vncPresentInit(ScreenPtr screen);
+void vncPresentMscEvent(uint64_t id, uint64_t msc);
+
+#endif
diff --git a/unix/xserver/hw/vnc/xvnc.c b/unix/xserver/hw/vnc/xvnc.c
index 16a28831..706c9d5a 100644
--- a/unix/xserver/hw/vnc/xvnc.c
+++ b/unix/xserver/hw/vnc/xvnc.c
@@ -36,6 +36,7 @@ from the X Consortium.
#include "RFBGlue.h"
#include "XorgGlue.h"
#include "RandrGlue.h"
+#include "vncPresent.h"
#include "xorg-version.h"
#include <stdio.h>
@@ -670,14 +671,14 @@ vncRandRScreenSetSize(ScreenPtr pScreen,
ret = vncRandRCrtcSet(pScreen, crtc, NULL,
crtc->x, crtc->y, crtc->rotation, 0, NULL);
if (!ret)
- ErrorF("Warning: Unable to disable CRTC that is outside of new screen dimensions");
+ ErrorF("Warning: Unable to disable CRTC that is outside of new screen dimensions\n");
continue;
}
/* Just needs to be resized to a temporary mode */
mode = vncRandRModeGet(width - crtc->x, height - crtc->y);
if (mode == NULL) {
- ErrorF("Warning: Unable to create custom mode for %dx%d",
+ ErrorF("Warning: Unable to create custom mode for %dx%d\n",
width - crtc->x, height - crtc->y);
continue;
}
@@ -687,7 +688,7 @@ vncRandRScreenSetSize(ScreenPtr pScreen,
crtc->numOutputs, crtc->outputs);
RRModeDestroy(mode);
if (!ret)
- ErrorF("Warning: Unable to crop CRTC to new screen dimensions");
+ ErrorF("Warning: Unable to crop CRTC to new screen dimensions\n");
}
return TRUE;
@@ -1085,6 +1086,10 @@ vncScreenInit(ScreenPtr pScreen, int argc, char **argv)
if (!ret)
return FALSE;
+ ret = vncPresentInit(pScreen);
+ if (!ret)
+ ErrorF("Failed to initialize Present extension\n");
+
return TRUE;
} /* end vncScreenInit */
diff --git a/vncviewer/EmulateMB.cxx b/vncviewer/EmulateMB.cxx
index 72335eb8..cc680df4 100644
--- a/vncviewer/EmulateMB.cxx
+++ b/vncviewer/EmulateMB.cxx
@@ -277,13 +277,13 @@ void EmulateMB::filterPointerEvent(const rfb::Point& pos, int buttonMask)
}
}
-bool EmulateMB::handleTimeout(rfb::Timer *t)
+void EmulateMB::handleTimeout(rfb::Timer *t)
{
int action1, action2;
int buttonMask;
if (&timer != t)
- return false;
+ return;
if ((state > 10) || (state < 0))
throw rfb::Exception(_("Invalid state for 3 button emulation"));
@@ -310,8 +310,6 @@ bool EmulateMB::handleTimeout(rfb::Timer *t)
}
state = stateTab[state][4][2];
-
- return false;
}
void EmulateMB::sendAction(const rfb::Point& pos, int buttonMask, int action)
diff --git a/vncviewer/EmulateMB.h b/vncviewer/EmulateMB.h
index 132f44fe..77fdec66 100644
--- a/vncviewer/EmulateMB.h
+++ b/vncviewer/EmulateMB.h
@@ -31,7 +31,7 @@ public:
protected:
virtual void sendPointerEvent(const rfb::Point& pos, int buttonMask)=0;
- virtual bool handleTimeout(rfb::Timer *t);
+ virtual void handleTimeout(rfb::Timer *t);
private:
void sendAction(const rfb::Point& pos, int buttonMask, int action);
diff --git a/vncviewer/GestureHandler.cxx b/vncviewer/GestureHandler.cxx
index c3cc1531..ed99555e 100644
--- a/vncviewer/GestureHandler.cxx
+++ b/vncviewer/GestureHandler.cxx
@@ -323,14 +323,12 @@ bool GestureHandler::hasDetectedGesture()
return true;
}
-bool GestureHandler::handleTimeout(rfb::Timer* t)
+void GestureHandler::handleTimeout(rfb::Timer* t)
{
if (t == &longpressTimer)
longpressTimeout();
else if (t == &twoTouchTimer)
twoTouchTimeout();
-
- return false;
}
void GestureHandler::longpressTimeout()
diff --git a/vncviewer/GestureHandler.h b/vncviewer/GestureHandler.h
index 372b7865..b07454df 100644
--- a/vncviewer/GestureHandler.h
+++ b/vncviewer/GestureHandler.h
@@ -42,7 +42,7 @@ class GestureHandler : public rfb::Timer::Callback {
private:
bool hasDetectedGesture();
- virtual bool handleTimeout(rfb::Timer* t);
+ virtual void handleTimeout(rfb::Timer* t);
void longpressTimeout();
void twoTouchTimeout();
diff --git a/vncviewer/vncviewer.cxx b/vncviewer/vncviewer.cxx
index 91e2be3b..366327fa 100644
--- a/vncviewer/vncviewer.cxx
+++ b/vncviewer/vncviewer.cxx
@@ -188,7 +188,7 @@ static void mainloop(const char* vncserver, network::Socket* sock)
int next_timer;
next_timer = Timer::checkTimeouts();
- if (next_timer == 0)
+ if (next_timer < 0)
next_timer = INT_MAX;
if (Fl::wait((double)next_timer / 1000.0) < 0.0) {
diff --git a/win/rfb_win32/EventManager.cxx b/win/rfb_win32/EventManager.cxx
index 0f33f5ac..f034d36d 100644
--- a/win/rfb_win32/EventManager.cxx
+++ b/win/rfb_win32/EventManager.cxx
@@ -64,14 +64,14 @@ void EventManager::removeEvent(HANDLE event) {
int EventManager::checkTimeouts() {
- return 0;
+ return -1;
}
BOOL EventManager::getMessage(MSG* msg, HWND hwnd, UINT minMsg, UINT maxMsg) {
while (true) {
// - Process any pending timeouts
- DWORD timeout = checkTimeouts();
- if (timeout == 0)
+ int timeout = checkTimeouts();
+ if (timeout < 0)
timeout = INFINITE;
// - Events take precedence over messages
diff --git a/win/rfb_win32/SDisplay.cxx b/win/rfb_win32/SDisplay.cxx
index 612f883b..dd1ac7da 100644
--- a/win/rfb_win32/SDisplay.cxx
+++ b/win/rfb_win32/SDisplay.cxx
@@ -96,7 +96,12 @@ SDisplay::~SDisplay()
// -=- SDesktop interface
-void SDisplay::start(VNCServer* vs)
+void SDisplay::init(VNCServer* vs)
+{
+ server = vs;
+}
+
+void SDisplay::start()
{
vlog.debug("starting");
@@ -105,7 +110,6 @@ void SDisplay::start(VNCServer* vs)
setConsoleSession();
// Start the SDisplay core
- server = vs;
startCore();
vlog.debug("started");
@@ -135,10 +139,8 @@ void SDisplay::stop()
}
// Stop the SDisplayCore
- if (server)
- server->setPixelBuffer(0);
+ server->setPixelBuffer(0);
stopCore();
- server = 0;
vlog.debug("stopped");
diff --git a/win/rfb_win32/SDisplay.h b/win/rfb_win32/SDisplay.h
index febc720e..5b55cd66 100644
--- a/win/rfb_win32/SDisplay.h
+++ b/win/rfb_win32/SDisplay.h
@@ -71,7 +71,8 @@ namespace rfb {
// -=- SDesktop interface
- virtual void start(VNCServer* vs);
+ virtual void init(VNCServer* vs);
+ virtual void start();
virtual void stop();
virtual void terminate();
virtual void queryConnection(network::Socket* sock,
diff --git a/win/rfb_win32/SocketManager.cxx b/win/rfb_win32/SocketManager.cxx
index 8e88b79b..015ba549 100644
--- a/win/rfb_win32/SocketManager.cxx
+++ b/win/rfb_win32/SocketManager.cxx
@@ -169,9 +169,9 @@ void SocketManager::setDisable(VNCServer* srvr, bool disable)
int SocketManager::checkTimeouts() {
int timeout = EventManager::checkTimeouts();
- std::map<HANDLE,ListenInfo>::iterator i;
- for (i=listeners.begin(); i!=listeners.end(); i++)
- soonestTimeout(&timeout, Timer::checkTimeouts());
+ int nextTimeout = Timer::checkTimeouts();
+ if (nextTimeout >= 0 && nextTimeout < timeout)
+ timeout = nextTimeout;
std::list<network::Socket*> shutdownSocks;
std::map<HANDLE,ConnInfo>::iterator j, j_next;