Added support on X11 for a global option to delay switching screens

when the mouse reaches a jump zone.
This commit is contained in:
crs 2003-02-22 21:53:25 +00:00
parent aef50800e3
commit 7bbd33d787
15 changed files with 306 additions and 79 deletions

View File

@ -102,6 +102,12 @@ CXWindowsPrimaryScreen::setOptions(const COptionsList& options)
} }
} }
UInt32
CXWindowsPrimaryScreen::addOneShotTimer(double timeout)
{
return m_screen->addOneShotTimer(timeout);
}
KeyModifierMask KeyModifierMask
CXWindowsPrimaryScreen::getToggleMask() const CXWindowsPrimaryScreen::getToggleMask() const
{ {
@ -387,6 +393,12 @@ CXWindowsPrimaryScreen::onEvent(CEvent* event)
return false; return false;
} }
void
CXWindowsPrimaryScreen::onOneShotTimerExpired(UInt32 id)
{
m_receiver->onOneShotTimerExpired(id);
}
SInt32 SInt32
CXWindowsPrimaryScreen::getJumpZoneSize() const CXWindowsPrimaryScreen::getJumpZoneSize() const
{ {

View File

@ -40,6 +40,7 @@ public:
virtual void warpCursor(SInt32 x, SInt32 y); virtual void warpCursor(SInt32 x, SInt32 y);
virtual void resetOptions(); virtual void resetOptions();
virtual void setOptions(const COptionsList& options); virtual void setOptions(const COptionsList& options);
virtual UInt32 addOneShotTimer(double timeout);
virtual KeyModifierMask getToggleMask() const; virtual KeyModifierMask getToggleMask() const;
virtual bool isLockedToScreen() const; virtual bool isLockedToScreen() const;
virtual IScreen* getScreen() const; virtual IScreen* getScreen() const;
@ -48,6 +49,7 @@ public:
virtual void onScreensaver(bool activated); virtual void onScreensaver(bool activated);
virtual bool onPreDispatch(const CEvent* event); virtual bool onPreDispatch(const CEvent* event);
virtual bool onEvent(CEvent* event); virtual bool onEvent(CEvent* event);
virtual void onOneShotTimerExpired(UInt32 id);
virtual SInt32 getJumpZoneSize() const; virtual SInt32 getJumpZoneSize() const;
protected: protected:

View File

@ -54,14 +54,13 @@
// CXWindowsScreen::CTimer // CXWindowsScreen::CTimer
// //
CXWindowsScreen::CTimer::CTimer(IJob* job, double timeout) : CXWindowsScreen::CTimer::CTimer(IJob* job, double startTime, double resetTime) :
m_job(job), m_job(job),
m_timeout(timeout) m_timeout(resetTime),
m_time(resetTime),
m_startTime(startTime)
{ {
assert(m_job != NULL);
assert(m_timeout > 0.0); assert(m_timeout > 0.0);
reset();
} }
CXWindowsScreen::CTimer::~CTimer() CXWindowsScreen::CTimer::~CTimer()
@ -72,19 +71,23 @@ CXWindowsScreen::CTimer::~CTimer()
void void
CXWindowsScreen::CTimer::run() CXWindowsScreen::CTimer::run()
{ {
m_job->run(); if (m_job != NULL) {
m_job->run();
}
} }
void void
CXWindowsScreen::CTimer::reset() CXWindowsScreen::CTimer::reset()
{ {
m_time = m_timeout; m_time = m_timeout;
m_startTime = 0.0;
} }
CXWindowsScreen::CTimer::CTimer& CXWindowsScreen::CTimer::CTimer&
CXWindowsScreen::CTimer::operator-=(double dt) CXWindowsScreen::CTimer::operator-=(double dt)
{ {
m_time -= dt; m_time -= dt - m_startTime;
m_startTime = 0.0;
return *this; return *this;
} }
@ -118,7 +121,8 @@ CXWindowsScreen::CXWindowsScreen(IScreenReceiver* receiver,
m_w(0), m_h(0), m_w(0), m_h(0),
m_screensaver(NULL), m_screensaver(NULL),
m_screensaverNotify(false), m_screensaverNotify(false),
m_atomScreensaver(None) m_atomScreensaver(None),
m_oneShotTimer(NULL)
{ {
assert(s_screen == NULL); assert(s_screen == NULL);
assert(m_receiver != NULL); assert(m_receiver != NULL);
@ -137,6 +141,7 @@ CXWindowsScreen::~CXWindowsScreen()
assert(s_screen != NULL); assert(s_screen != NULL);
assert(m_display == NULL); assert(m_display == NULL);
delete m_oneShotTimer;
s_screen = NULL; s_screen = NULL;
} }
@ -145,7 +150,7 @@ CXWindowsScreen::addTimer(IJob* job, double timeout)
{ {
CLock lock(&m_timersMutex); CLock lock(&m_timersMutex);
removeTimerNoLock(job); removeTimerNoLock(job);
m_timers.push(CTimer(job, timeout)); m_timers.push(CTimer(job, m_time.getTime(), timeout));
} }
void void
@ -172,6 +177,15 @@ CXWindowsScreen::removeTimerNoLock(IJob* job)
m_timers.swap(tmp); m_timers.swap(tmp);
} }
UInt32
CXWindowsScreen::addOneShotTimer(double timeout)
{
CLock lock(&m_timersMutex);
// FIXME -- support multiple one-shot timers
m_oneShotTimer = new CTimer(NULL, m_time.getTime(), timeout);
return 0;
}
void void
CXWindowsScreen::setWindow(Window window) CXWindowsScreen::setWindow(Window window)
{ {
@ -262,19 +276,27 @@ CXWindowsScreen::mainLoop()
#endif #endif
while (!m_stop) { while (!m_stop) {
// compute timeout to next timer // compute timeout to next timer
double dtimeout;
{
CLock timersLock(&m_timersMutex);
dtimeout = (m_timers.empty() ? -1.0 : m_timers.top());
if (m_oneShotTimer != NULL &&
(dtimeout == -1.0 || *m_oneShotTimer < dtimeout)) {
dtimeout = *m_oneShotTimer;
}
}
#if HAVE_POLL #if HAVE_POLL
int timeout = (m_timers.empty() ? -1 : int timeout = static_cast<int>(1000.0 * dtimeout);
static_cast<int>(1000.0 * m_timers.top()));
#else #else
struct timeval timeout; struct timeval timeout;
struct timeval* timeoutPtr; struct timeval* timeoutPtr;
if (m_timers.empty()) { if (dtimeout < 0.0) {
timeoutPtr = NULL; timeoutPtr = NULL;
} }
else { else {
timeout.tv_sec = static_cast<int>(m_timers.top()); timeout.tv_sec = static_cast<int>(dtimeout);
timeout.tv_usec = static_cast<int>(1.0e+6 * timeout.tv_usec = static_cast<int>(1.0e+6 *
(m_timers.top() - timeout.tv_sec)); (dtimeout - timeout.tv_sec));
timeoutPtr = &timeout; timeoutPtr = &timeout;
} }
@ -697,6 +719,7 @@ CXWindowsScreen::createBlankCursor()
bool bool
CXWindowsScreen::processTimers() CXWindowsScreen::processTimers()
{ {
bool oneShot = false;
std::vector<IJob*> jobs; std::vector<IJob*> jobs;
{ {
CLock lock(&m_timersMutex); CLock lock(&m_timersMutex);
@ -705,10 +728,21 @@ CXWindowsScreen::processTimers()
const double time = m_time.getTime(); const double time = m_time.getTime();
// done if no timers have expired // done if no timers have expired
if (m_timers.empty() || m_timers.top() > time) { if ((m_oneShotTimer == NULL || *m_oneShotTimer > time) &&
(m_timers.empty() || m_timers.top() > time)) {
return false; return false;
} }
// handle one shot timers
if (m_oneShotTimer != NULL) {
*m_oneShotTimer -= time;
if (*m_oneShotTimer <= 0.0) {
delete m_oneShotTimer;
m_oneShotTimer = NULL;
oneShot = true;
}
}
// subtract current time from all timers. note that this won't // subtract current time from all timers. note that this won't
// change the order of elements in the priority queue (except // change the order of elements in the priority queue (except
// for floating point round off which we'll ignore). // for floating point round off which we'll ignore).
@ -718,18 +752,27 @@ CXWindowsScreen::processTimers()
} }
// process all timers at or below zero, saving the jobs // process all timers at or below zero, saving the jobs
while (m_timers.top() <= 0.0) { if (!m_timers.empty()) {
CTimer timer = m_timers.top(); while (m_timers.top() <= 0.0) {
jobs.push_back(timer.getJob()); CTimer timer = m_timers.top();
timer.reset(); jobs.push_back(timer.getJob());
m_timers.pop(); timer.reset();
m_timers.push(timer); m_timers.pop();
m_timers.push(timer);
}
} }
// reset the clock // reset the clock
m_time.reset(); m_time.reset();
} }
// now notify of the one shot timers
if (oneShot) {
m_mutex.unlock();
m_eventHandler->onOneShotTimerExpired(0);
m_mutex.lock();
}
// now run the jobs. note that if one of these jobs removes // now run the jobs. note that if one of these jobs removes
// a timer later in the jobs list and deletes that job pointer // a timer later in the jobs list and deletes that job pointer
// then this will crash when it tries to run that job. // then this will crash when it tries to run that job.

View File

@ -69,6 +69,14 @@ public:
*/ */
void removeTimer(IJob*); void removeTimer(IJob*);
//! Install a one-shot timer
/*!
Installs a one-shot timer for \c timeout seconds and returns the
id of the timer (which will be passed to the receiver's
\c onTimerExpired()).
*/
UInt32 addOneShotTimer(double timeout);
//! Set window //! Set window
/*! /*!
Set the window (created by the subclass). This performs some Set the window (created by the subclass). This performs some
@ -216,7 +224,7 @@ private:
// a timer priority queue element // a timer priority queue element
class CTimer { class CTimer {
public: public:
CTimer(IJob* job, double timeout); CTimer(IJob* job, double startTime, double resetTime);
~CTimer(); ~CTimer();
// manipulators // manipulators
@ -242,6 +250,7 @@ private:
IJob* m_job; IJob* m_job;
double m_timeout; double m_timeout;
double m_time; double m_time;
double m_startTime;
}; };
private: private:
@ -278,6 +287,7 @@ private:
CTimerPriorityQueue m_timers; CTimerPriorityQueue m_timers;
CStopwatch m_time; CStopwatch m_time;
CMutex m_timersMutex; CMutex m_timersMutex;
CTimer* m_oneShotTimer;
// pointer to (singleton) screen. this is only needed by // pointer to (singleton) screen. this is only needed by
// ioErrorHandler(). // ioErrorHandler().

View File

@ -263,6 +263,12 @@ CXWindowsSecondaryScreen::onEvent(CEvent* event)
} }
} }
void
CXWindowsSecondaryScreen::onOneShotTimerExpired(UInt32)
{
// ignore
}
SInt32 SInt32
CXWindowsSecondaryScreen::getJumpZoneSize() const CXWindowsSecondaryScreen::getJumpZoneSize() const
{ {

View File

@ -51,6 +51,7 @@ public:
virtual void onScreensaver(bool activated); virtual void onScreensaver(bool activated);
virtual bool onPreDispatch(const CEvent* event); virtual bool onPreDispatch(const CEvent* event);
virtual bool onEvent(CEvent* event); virtual bool onEvent(CEvent* event);
virtual void onOneShotTimerExpired(UInt32 id);
virtual SInt32 getJumpZoneSize() const; virtual SInt32 getJumpZoneSize() const;
protected: protected:

View File

@ -624,6 +624,9 @@ CConfig::getOptionName(OptionID id)
if (id == kOptionHeartbeat) { if (id == kOptionHeartbeat) {
return "heartbeat"; return "heartbeat";
} }
if (id == kOptionScreenSwitchDelay) {
return "switchDelay";
}
return NULL; return NULL;
} }
@ -659,7 +662,8 @@ CConfig::getOptionValue(OptionID id, OptionValue value)
return "none"; return "none";
} }
} }
if (id == kOptionHeartbeat) { if (id == kOptionHeartbeat ||
id == kOptionScreenSwitchDelay) {
return CStringUtil::print("%d", value); return CStringUtil::print("%d", value);
} }
@ -767,6 +771,9 @@ CConfig::readSectionOptions(std::istream& s)
else if (name == "heartbeat") { else if (name == "heartbeat") {
addOption("", kOptionHeartbeat, parseInt(value)); addOption("", kOptionHeartbeat, parseInt(value));
} }
else if (name == "switchDelay") {
addOption("", kOptionScreenSwitchDelay, parseInt(value));
}
else { else {
throw XConfigRead("unknown argument"); throw XConfigRead("unknown argument");
} }

View File

@ -63,6 +63,12 @@ CPrimaryClient::reconfigure(UInt32 activeSides)
m_screen->reconfigure(activeSides); m_screen->reconfigure(activeSides);
} }
UInt32
CPrimaryClient::addOneShotTimer(double timeout)
{
return m_screen->addOneShotTimer(timeout);
}
void void
CPrimaryClient::getClipboard(ClipboardID id, CString& data) const CPrimaryClient::getClipboard(ClipboardID id, CString& data) const
{ {

View File

@ -59,6 +59,13 @@ public:
*/ */
void reconfigure(UInt32 activeSides); void reconfigure(UInt32 activeSides);
//! Install a one-shot timer
/*!
Installs a one-shot timer for \c timeout seconds and returns the
id of the timer (which will be passed to \c onTimerExpired()).
*/
UInt32 addOneShotTimer(double timeout);
//@} //@}
//! @name accessors //! @name accessors
//@{ //@{

View File

@ -59,7 +59,9 @@ CServer::CServer(const CString& serverName) :
m_seqNum(0), m_seqNum(0),
m_activeSaver(NULL), m_activeSaver(NULL),
m_httpServer(NULL), m_httpServer(NULL),
m_httpAvailable(&m_mutex, s_httpMaxSimultaneousRequests) m_httpAvailable(&m_mutex, s_httpMaxSimultaneousRequests),
m_switchWaitDelay(0.0),
m_switchWaitScreen(NULL)
{ {
// do nothing // do nothing
} }
@ -220,13 +222,18 @@ CServer::setConfig(const CConfig& config)
// process global options // process global options
const CConfig::CScreenOptions* options = m_config.getOptions(""); const CConfig::CScreenOptions* options = m_config.getOptions("");
if (options != NULL && options->size() > 0) { if (options != NULL && options->size() > 0) {
/*
for (CConfig::CScreenOptions::const_iterator index = options->begin(); for (CConfig::CScreenOptions::const_iterator index = options->begin();
index != options->end(); ++index) { index != options->end(); ++index) {
const OptionID id = index->first; const OptionID id = index->first;
const OptionValue value = index->second; const OptionValue value = index->second;
if (id == kOptionScreenSwitchDelay) {
m_switchWaitDelay = 1.0e-3 * static_cast<double>(value);
if (m_switchWaitDelay < 0.0) {
m_switchWaitDelay = 0.0;
}
clearSwitchWait();
}
} }
*/
} }
// tell primary screen about reconfiguration // tell primary screen about reconfiguration
@ -496,6 +503,36 @@ CServer::onScreensaver(bool activated)
} }
} }
void
CServer::onOneShotTimerExpired(UInt32 id)
{
CLock lock(&m_mutex);
// ignore old timer or if there's no jump screen anymore
if (m_switchWaitScreen == NULL || id != m_switchWaitTimer) {
clearSwitchWait();
return;
}
// ignore if mouse is locked to screen
if (isLockedToScreenNoLock()) {
clearSwitchWait();
return;
}
// switch screen
switchScreen(m_switchWaitScreen, m_switchWaitX, m_switchWaitY, false);
}
void
CServer::clearSwitchWait()
{
if (m_switchWaitScreen != NULL) {
LOG((CLOG_DEBUG1 "cancel switch wait"));
m_switchWaitScreen = NULL;
}
}
void void
CServer::onKeyDown(KeyID id, KeyModifierMask mask) CServer::onKeyDown(KeyID id, KeyModifierMask mask)
{ {
@ -582,11 +619,6 @@ CServer::onMouseMovePrimaryNoLock(SInt32 x, SInt32 y)
assert(m_primaryClient != NULL); assert(m_primaryClient != NULL);
assert(m_active == m_primaryClient); assert(m_active == m_primaryClient);
// ignore if mouse is locked to screen
if (isLockedToScreenNoLock()) {
return false;
}
// get screen shape // get screen shape
SInt32 ax, ay, aw, ah; SInt32 ax, ay, aw, ah;
m_active->getShape(ax, ay, aw, ah); m_active->getShape(ax, ay, aw, ah);
@ -616,6 +648,7 @@ CServer::onMouseMovePrimaryNoLock(SInt32 x, SInt32 y)
} }
else { else {
// still on local screen // still on local screen
clearSwitchWait();
return false; return false;
} }
@ -623,6 +656,27 @@ CServer::onMouseMovePrimaryNoLock(SInt32 x, SInt32 y)
// then ignore the move. // then ignore the move.
IClient* newScreen = getNeighbor(m_active, dir, x, y); IClient* newScreen = getNeighbor(m_active, dir, x, y);
if (newScreen == NULL) { if (newScreen == NULL) {
clearSwitchWait();
return false;
}
// if waiting before a switch then prepare to switch later
if (m_switchWaitDelay > 0.0) {
if (m_switchWaitScreen == NULL || dir != m_switchWaitDir) {
m_switchWaitDir = dir;
m_switchWaitScreen = newScreen;
m_switchWaitX = x;
m_switchWaitY = y;
m_switchWaitTimer = m_primaryClient->addOneShotTimer(
m_switchWaitDelay);
LOG((CLOG_DEBUG1 "waiting to switch"));
}
return false;
}
// ignore if mouse is locked to screen
if (isLockedToScreenNoLock()) {
LOG((CLOG_DEBUG1 "locked to screen"));
return false; return false;
} }
@ -667,72 +721,110 @@ CServer::onMouseMoveSecondaryNoLock(SInt32 dx, SInt32 dy)
SInt32 ax, ay, aw, ah; SInt32 ax, ay, aw, ah;
m_active->getShape(ax, ay, aw, ah); m_active->getShape(ax, ay, aw, ah);
// find direction of neighbor
EDirection dir;
IClient* newScreen = NULL;
if (m_x < ax) {
dir = kLeft;
}
else if (m_x > ax + aw - 1) {
dir = kRight;
}
else if (m_y < ay) {
dir = kTop;
}
else if (m_y > ay + ah - 1) {
dir = kBottom;
}
else {
newScreen = m_active;
// keep compiler quiet about unset variable
dir = kLeft;
}
// switch screens if the mouse is outside the screen and not // switch screens if the mouse is outside the screen and not
// locked to the screen // locked to the screen
IClient* newScreen = NULL; bool clamp = false;
if (!isLockedToScreenNoLock()) { if (newScreen == NULL) {
// find direction of neighbor // get neighbor we should switch to
EDirection dir; newScreen = getNeighbor(m_active, dir, m_x, m_y);
if (m_x < ax) { LOG((CLOG_DEBUG1 "leave \"%s\" on %s", m_active->getName().c_str(), CConfig::dirName(dir)));
dir = kLeft;
}
else if (m_x > ax + aw - 1) {
dir = kRight;
}
else if (m_y < ay) {
dir = kTop;
}
else if (m_y > ay + ah - 1) {
dir = kBottom;
}
else {
newScreen = m_active;
// keep compiler quiet about unset variable
dir = kLeft;
}
// get neighbor if we should switch
if (newScreen == NULL) { if (newScreen == NULL) {
LOG((CLOG_DEBUG1 "leave \"%s\" on %s", m_active->getName().c_str(), CConfig::dirName(dir))); LOG((CLOG_DEBUG1 "no neighbor %s", CConfig::dirName(dir)));
clamp = true;
// get new position or clamp to current screen }
newScreen = getNeighbor(m_active, dir, m_x, m_y); else if (m_switchWaitDelay > 0.0) {
if (newScreen == NULL) { // wait to switch; prepare to switch later
LOG((CLOG_DEBUG1 "no neighbor; clamping")); if (m_switchWaitScreen == NULL || dir != m_switchWaitDir) {
if (m_x < ax) { m_switchWaitDir = dir;
m_x = ax; m_switchWaitScreen = newScreen;
} m_switchWaitX = m_x;
else if (m_x > ax + aw - 1) { m_switchWaitY = m_y;
m_x = ax + aw - 1; m_switchWaitTimer = m_primaryClient->addOneShotTimer(
} m_switchWaitDelay);
if (m_y < ay) { LOG((CLOG_DEBUG1 "waiting to switch"));
m_y = ay;
}
else if (m_y > ay + ah - 1) {
m_y = ay + ah - 1;
}
} }
// don't try to switch screen now
m_x = xOld + dx;
m_y = yOld + dy;
clamp = true;
}
else if (isLockedToScreenNoLock()) {
// clamp to edge when locked to screen
LOG((CLOG_DEBUG1 "locked to screen"));
clamp = true;
} }
} }
else { else {
// clamp to edge when locked // on same screen. if waiting and mouse is not on the border
// we're waiting on then stop waiting.
if (m_switchWaitScreen != NULL) {
bool clearWait;
SInt32 zoneSize = m_primaryClient->getJumpZoneSize();
switch (m_switchWaitDir) {
case kLeft:
clearWait = (m_x >= ax + zoneSize);
break;
case kRight:
clearWait = (m_x <= ax + aw - 1 - zoneSize);
break;
case kTop:
clearWait = (m_y >= ay + zoneSize);
break;
case kBottom:
clearWait = (m_y <= ay + ah - 1 + zoneSize);
break;
}
if (clearWait) {
clearSwitchWait();
}
}
}
// clamp mouse to edge
if (clamp) {
if (m_x < ax) { if (m_x < ax) {
m_x = ax; m_x = ax;
LOG((CLOG_DEBUG1 "clamp to left of \"%s\"", m_active->getName().c_str())); LOG((CLOG_DEBUG2 "clamp to left of \"%s\"", m_active->getName().c_str()));
} }
else if (m_x > ax + aw - 1) { else if (m_x > ax + aw - 1) {
m_x = ax + aw - 1; m_x = ax + aw - 1;
LOG((CLOG_DEBUG1 "clamp to right of \"%s\"", m_active->getName().c_str())); LOG((CLOG_DEBUG2 "clamp to right of \"%s\"", m_active->getName().c_str()));
} }
if (m_y < ay) { if (m_y < ay) {
m_y = ay; m_y = ay;
LOG((CLOG_DEBUG1 "clamp to top of \"%s\"", m_active->getName().c_str())); LOG((CLOG_DEBUG2 "clamp to top of \"%s\"", m_active->getName().c_str()));
} }
else if (m_y > ay + ah - 1) { else if (m_y > ay + ah - 1) {
m_y = ay + ah - 1; m_y = ay + ah - 1;
LOG((CLOG_DEBUG1 "clamp to bottom of \"%s\"", m_active->getName().c_str())); LOG((CLOG_DEBUG2 "clamp to bottom of \"%s\"", m_active->getName().c_str()));
} }
newScreen = NULL;
} }
// warp cursor if on same screen // warp cursor if on same screen
@ -801,6 +893,9 @@ CServer::switchScreen(IClient* dst, SInt32 x, SInt32 y, bool forScreensaver)
LOG((CLOG_INFO "switch from \"%s\" to \"%s\" at %d,%d", m_active->getName().c_str(), dst->getName().c_str(), x, y)); LOG((CLOG_INFO "switch from \"%s\" to \"%s\" at %d,%d", m_active->getName().c_str(), dst->getName().c_str(), x, y));
// stop waiting to switch
clearSwitchWait();
// record new position // record new position
m_x = x; m_x = x;
m_y = y; m_y = y;
@ -1099,6 +1194,11 @@ CServer::closeClients(const CConfig& config)
// close that client // close that client
assert(index2->second != m_primaryClient); assert(index2->second != m_primaryClient);
index2->second->close(); index2->second->close();
// don't switch to it if we planned to
if (index2->second == m_switchWaitScreen) {
clearSwitchWait();
}
} }
else { else {
++index; ++index;
@ -1789,6 +1889,9 @@ CServer::removeConnection(const CString& name)
// record new position (center of primary screen) // record new position (center of primary screen)
m_primaryClient->getCursorCenter(m_x, m_y); m_primaryClient->getCursorCenter(m_x, m_y);
// stop waiting to switch if we were
clearSwitchWait();
// don't notify active screen since it probably already disconnected // don't notify active screen since it probably already disconnected
LOG((CLOG_INFO "jump from \"%s\" to \"%s\" at %d,%d", active->getName().c_str(), m_primaryClient->getName().c_str(), m_x, m_y)); LOG((CLOG_INFO "jump from \"%s\" to \"%s\" at %d,%d", active->getName().c_str(), m_primaryClient->getName().c_str(), m_x, m_y));

View File

@ -141,6 +141,7 @@ public:
// IPrimaryScreenReceiver overrides // IPrimaryScreenReceiver overrides
virtual void onScreensaver(bool activated); virtual void onScreensaver(bool activated);
virtual void onOneShotTimerExpired(UInt32 id);
virtual void onKeyDown(KeyID, KeyModifierMask); virtual void onKeyDown(KeyID, KeyModifierMask);
virtual void onKeyUp(KeyID, KeyModifierMask); virtual void onKeyUp(KeyID, KeyModifierMask);
virtual void onKeyRepeat(KeyID, KeyModifierMask, SInt32 count); virtual void onKeyRepeat(KeyID, KeyModifierMask, SInt32 count);
@ -197,6 +198,9 @@ private:
IClient* getNeighbor(IClient*, EDirection, IClient* getNeighbor(IClient*, EDirection,
SInt32& x, SInt32& y) const; SInt32& x, SInt32& y) const;
// reset switch wait state
void clearSwitchWait();
// send screen options to \c client // send screen options to \c client
void sendOptions(IClient* client) const; void sendOptions(IClient* client) const;
@ -320,6 +324,12 @@ private:
CHTTPServer* m_httpServer; CHTTPServer* m_httpServer;
CCondVar<SInt32> m_httpAvailable; CCondVar<SInt32> m_httpAvailable;
static const SInt32 s_httpMaxSimultaneousRequests; static const SInt32 s_httpMaxSimultaneousRequests;
double m_switchWaitDelay;
EDirection m_switchWaitDir;
UInt32 m_switchWaitTimer;
IClient* m_switchWaitScreen;
SInt32 m_switchWaitX, m_switchWaitY;
}; };
#endif #endif

View File

@ -129,6 +129,13 @@ public:
*/ */
virtual void setOptions(const COptionsList& options) = 0; virtual void setOptions(const COptionsList& options) = 0;
//! Install a one-shot timer
/*!
Installs a one-shot timer for \c timeout seconds and returns the
id of the timer.
*/
virtual UInt32 addOneShotTimer(double timeout) = 0;
//@} //@}
//! @name accessors //! @name accessors
//@{ //@{

View File

@ -34,6 +34,12 @@ public:
*/ */
virtual void onScreensaver(bool activated) = 0; virtual void onScreensaver(bool activated) = 0;
//! Notify of one-shot timer expiration
/*!
Called when a one-shot timer expires.
*/
virtual void onOneShotTimerExpired(UInt32 id) = 0;
// call to notify of events. onMouseMovePrimary() returns // call to notify of events. onMouseMovePrimary() returns
// true iff the mouse enters a jump zone and jumps. // true iff the mouse enters a jump zone and jumps.
//! Notify of key press //! Notify of key press

View File

@ -57,6 +57,12 @@ public:
*/ */
virtual bool onEvent(CEvent* event) = 0; virtual bool onEvent(CEvent* event) = 0;
//! Notify of one-shot timer expiration
/*!
Called when a one-shot timer expires.
*/
virtual void onOneShotTimerExpired(UInt32 id) = 0;
//@} //@}
//! @name accessors //! @name accessors
//@{ //@{

View File

@ -51,6 +51,7 @@ static const OptionID kOptionModifierMapForAlt = OPTION_CODE("MMFA");
static const OptionID kOptionModifierMapForMeta = OPTION_CODE("MMFM"); static const OptionID kOptionModifierMapForMeta = OPTION_CODE("MMFM");
static const OptionID kOptionModifierMapForSuper = OPTION_CODE("MMFR"); static const OptionID kOptionModifierMapForSuper = OPTION_CODE("MMFR");
static const OptionID kOptionHeartbeat = OPTION_CODE("HART"); static const OptionID kOptionHeartbeat = OPTION_CODE("HART");
static const OptionID kOptionScreenSwitchDelay = OPTION_CODE("SSWT");
//@} //@}
#undef OPTION_CODE #undef OPTION_CODE