2001-10-06 14:13:28 +00:00
|
|
|
#include "CServer.h"
|
2002-05-30 16:13:16 +00:00
|
|
|
#include "CHTTPServer.h"
|
2001-10-06 14:13:28 +00:00
|
|
|
#include "CInputPacketStream.h"
|
|
|
|
#include "COutputPacketStream.h"
|
|
|
|
#include "CProtocolUtil.h"
|
2002-06-10 22:06:45 +00:00
|
|
|
#include "CServerProtocol.h"
|
2001-10-06 14:13:28 +00:00
|
|
|
#include "IPrimaryScreen.h"
|
|
|
|
#include "ProtocolTypes.h"
|
2002-06-10 22:06:45 +00:00
|
|
|
#include "XScreen.h"
|
|
|
|
#include "XSynergy.h"
|
2001-10-06 14:13:28 +00:00
|
|
|
#include "CNetworkAddress.h"
|
2002-06-17 12:02:26 +00:00
|
|
|
#include "IDataSocket.h"
|
2001-10-06 14:13:28 +00:00
|
|
|
#include "IListenSocket.h"
|
2002-06-10 22:06:45 +00:00
|
|
|
#include "ISocketFactory.h"
|
|
|
|
#include "XSocket.h"
|
2001-10-06 14:13:28 +00:00
|
|
|
#include "CLock.h"
|
|
|
|
#include "CThread.h"
|
|
|
|
#include "CTimerThread.h"
|
2002-06-10 22:06:45 +00:00
|
|
|
#include "XThread.h"
|
2002-05-30 16:13:16 +00:00
|
|
|
#include "CFunctionJob.h"
|
2002-06-10 22:06:45 +00:00
|
|
|
#include "CLog.h"
|
|
|
|
#include "CStopwatch.h"
|
2001-10-06 14:13:28 +00:00
|
|
|
#include "TMethodJob.h"
|
|
|
|
#include <memory>
|
|
|
|
|
2001-11-19 00:33:36 +00:00
|
|
|
// hack to work around operator=() bug in STL in g++ prior to v3
|
|
|
|
#if defined(__GNUC__) && (__GNUC__ < 3)
|
|
|
|
#define assign(_dst, _src, _type) _dst.reset(_src)
|
|
|
|
#else
|
|
|
|
#define assign(_dst, _src, _type) _dst = std::auto_ptr<_type >(_src)
|
|
|
|
#endif
|
|
|
|
|
2001-10-06 14:13:28 +00:00
|
|
|
//
|
|
|
|
// CServer
|
|
|
|
//
|
|
|
|
|
2002-06-02 11:49:46 +00:00
|
|
|
const SInt32 CServer::s_httpMaxSimultaneousRequests = 3;
|
|
|
|
|
2002-06-17 13:31:21 +00:00
|
|
|
CServer::CServer(const CString& serverName) :
|
2002-06-10 22:06:45 +00:00
|
|
|
m_name(serverName),
|
|
|
|
m_primary(NULL),
|
|
|
|
m_active(NULL),
|
|
|
|
m_primaryInfo(NULL),
|
|
|
|
m_seqNum(0),
|
2002-06-26 16:31:48 +00:00
|
|
|
m_activeSaver(NULL),
|
2002-06-10 22:06:45 +00:00
|
|
|
m_httpServer(NULL),
|
|
|
|
m_httpAvailable(&m_mutex, s_httpMaxSimultaneousRequests)
|
2001-10-06 14:13:28 +00:00
|
|
|
{
|
|
|
|
m_socketFactory = NULL;
|
|
|
|
m_securityFactory = NULL;
|
|
|
|
m_bindTimeout = 5.0 * 60.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
CServer::~CServer()
|
|
|
|
{
|
2002-06-03 18:53:18 +00:00
|
|
|
// do nothing
|
2001-10-06 14:13:28 +00:00
|
|
|
}
|
|
|
|
|
2002-06-21 17:55:47 +00:00
|
|
|
bool
|
|
|
|
CServer::open()
|
|
|
|
{
|
|
|
|
// open the screen
|
|
|
|
try {
|
|
|
|
log((CLOG_INFO "opening screen"));
|
|
|
|
openPrimaryScreen();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
catch (XScreenOpenFailure&) {
|
|
|
|
// can't open screen yet. wait a few seconds to retry.
|
|
|
|
CThread::sleep(3.0);
|
|
|
|
log((CLOG_INFO "failed to open screen"));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
catch (XUnknownClient& e) {
|
|
|
|
// can't open screen yet. wait a few seconds to retry.
|
|
|
|
CThread::sleep(3.0);
|
|
|
|
log((CLOG_CRIT "unknown screen name `%s'", e.getName().c_str()));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-06-10 22:06:45 +00:00
|
|
|
void
|
|
|
|
CServer::run()
|
2001-10-06 14:13:28 +00:00
|
|
|
{
|
2002-06-21 17:55:47 +00:00
|
|
|
// check preconditions
|
|
|
|
{
|
|
|
|
CLock lock(&m_mutex);
|
|
|
|
assert(m_primary != NULL);
|
|
|
|
}
|
|
|
|
|
2001-10-06 14:13:28 +00:00
|
|
|
try {
|
2001-10-14 14:37:41 +00:00
|
|
|
log((CLOG_NOTE "starting server"));
|
|
|
|
|
2001-10-06 14:13:28 +00:00
|
|
|
// start listening for new clients
|
2002-06-21 15:18:01 +00:00
|
|
|
startThread(new TMethodJob<CServer>(this, &CServer::acceptClients));
|
2001-10-06 14:13:28 +00:00
|
|
|
|
2002-06-09 16:53:25 +00:00
|
|
|
// start listening for HTTP requests
|
|
|
|
if (m_config.getHTTPAddress().isValid()) {
|
|
|
|
m_httpServer = new CHTTPServer(this);
|
2002-06-21 15:18:01 +00:00
|
|
|
startThread(new TMethodJob<CServer>(this,
|
|
|
|
&CServer::acceptHTTPClients));
|
2002-06-09 16:53:25 +00:00
|
|
|
}
|
|
|
|
|
2001-11-19 00:33:36 +00:00
|
|
|
// handle events
|
|
|
|
log((CLOG_DEBUG "starting event handling"));
|
|
|
|
m_primary->run();
|
2001-10-06 14:13:28 +00:00
|
|
|
|
|
|
|
// clean up
|
2002-04-27 18:49:03 +00:00
|
|
|
log((CLOG_NOTE "stopping server"));
|
2002-06-21 15:18:01 +00:00
|
|
|
stopThreads();
|
2002-05-30 16:13:16 +00:00
|
|
|
delete m_httpServer;
|
|
|
|
m_httpServer = NULL;
|
2001-11-19 00:33:36 +00:00
|
|
|
closePrimaryScreen();
|
2001-10-06 14:13:28 +00:00
|
|
|
}
|
|
|
|
catch (XBase& e) {
|
2001-11-25 18:32:41 +00:00
|
|
|
log((CLOG_ERR "server error: %s", e.what()));
|
2001-10-06 14:13:28 +00:00
|
|
|
|
|
|
|
// clean up
|
2002-06-02 18:49:35 +00:00
|
|
|
log((CLOG_NOTE "stopping server"));
|
2002-06-21 15:18:01 +00:00
|
|
|
stopThreads();
|
2002-06-02 18:49:35 +00:00
|
|
|
delete m_httpServer;
|
|
|
|
m_httpServer = NULL;
|
2002-06-03 18:53:18 +00:00
|
|
|
if (m_primary != NULL) {
|
|
|
|
closePrimaryScreen();
|
|
|
|
}
|
2002-06-02 18:49:35 +00:00
|
|
|
}
|
|
|
|
catch (XThread&) {
|
|
|
|
// clean up
|
|
|
|
log((CLOG_NOTE "stopping server"));
|
2002-06-21 15:18:01 +00:00
|
|
|
stopThreads();
|
2002-05-30 16:13:16 +00:00
|
|
|
delete m_httpServer;
|
|
|
|
m_httpServer = NULL;
|
2002-06-03 13:45:30 +00:00
|
|
|
if (m_primary != NULL) {
|
|
|
|
closePrimaryScreen();
|
|
|
|
}
|
2002-06-02 18:49:35 +00:00
|
|
|
throw;
|
2001-10-06 14:13:28 +00:00
|
|
|
}
|
|
|
|
catch (...) {
|
2001-11-19 00:33:36 +00:00
|
|
|
log((CLOG_DEBUG "unknown server error"));
|
2001-10-14 14:37:41 +00:00
|
|
|
|
2001-10-06 14:13:28 +00:00
|
|
|
// clean up
|
2002-06-02 18:49:35 +00:00
|
|
|
log((CLOG_NOTE "stopping server"));
|
2002-06-21 15:18:01 +00:00
|
|
|
stopThreads();
|
2002-05-30 16:13:16 +00:00
|
|
|
delete m_httpServer;
|
|
|
|
m_httpServer = NULL;
|
2002-06-03 13:45:30 +00:00
|
|
|
if (m_primary != NULL) {
|
|
|
|
closePrimaryScreen();
|
|
|
|
}
|
2001-10-06 14:13:28 +00:00
|
|
|
throw;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-06-10 22:06:45 +00:00
|
|
|
void
|
|
|
|
CServer::quit()
|
2002-04-29 13:31:44 +00:00
|
|
|
{
|
|
|
|
m_primary->stop();
|
|
|
|
}
|
|
|
|
|
2002-06-10 22:06:45 +00:00
|
|
|
void
|
|
|
|
CServer::shutdown()
|
2002-06-03 13:45:30 +00:00
|
|
|
{
|
|
|
|
// stop all running threads but don't wait too long since some
|
|
|
|
// threads may be unable to proceed until this thread returns.
|
2002-06-21 15:18:01 +00:00
|
|
|
stopThreads(3.0);
|
2002-06-03 13:45:30 +00:00
|
|
|
|
|
|
|
// done with the HTTP server
|
|
|
|
delete m_httpServer;
|
|
|
|
m_httpServer = NULL;
|
|
|
|
|
|
|
|
// note -- we do not attempt to close down the primary screen
|
|
|
|
}
|
|
|
|
|
2002-06-10 22:06:45 +00:00
|
|
|
bool
|
2002-06-17 13:31:21 +00:00
|
|
|
CServer::setConfig(const CConfig& config)
|
2001-10-06 14:13:28 +00:00
|
|
|
{
|
2002-05-31 18:09:43 +00:00
|
|
|
typedef std::vector<CThread> CThreads;
|
|
|
|
CThreads threads;
|
|
|
|
{
|
|
|
|
CLock lock(&m_mutex);
|
|
|
|
|
|
|
|
// refuse configuration if it doesn't include the primary screen
|
|
|
|
if (m_primaryInfo != NULL &&
|
|
|
|
!config.isScreen(m_primaryInfo->m_name)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// get the set of screens that are connected but are being
|
2002-06-08 23:24:40 +00:00
|
|
|
// dropped from the configuration (or who's canonical name
|
|
|
|
// is changing). don't add the primary screen. also tell
|
|
|
|
// the secondary screen to disconnect.
|
2002-05-31 18:09:43 +00:00
|
|
|
for (CScreenList::const_iterator index = m_screens.begin();
|
|
|
|
index != m_screens.end(); ++index) {
|
2002-06-08 23:24:40 +00:00
|
|
|
if (index->second != m_primaryInfo &&
|
|
|
|
!config.isCanonicalName(index->first)) {
|
2002-06-01 10:52:02 +00:00
|
|
|
assert(index->second->m_protocol != NULL);
|
|
|
|
index->second->m_protocol->sendClose();
|
2002-05-31 18:09:43 +00:00
|
|
|
threads.push_back(index->second->m_thread);
|
|
|
|
}
|
|
|
|
}
|
2002-06-08 23:24:40 +00:00
|
|
|
}
|
2002-05-31 18:09:43 +00:00
|
|
|
|
2002-06-08 23:24:40 +00:00
|
|
|
// wait a moment to allow each secondary screen to close
|
|
|
|
// its connection before we close it (to avoid having our
|
|
|
|
// socket enter TIME_WAIT).
|
|
|
|
if (threads.size() > 0) {
|
|
|
|
CThread::sleep(1.0);
|
|
|
|
}
|
2002-06-01 10:52:02 +00:00
|
|
|
|
2002-06-08 23:24:40 +00:00
|
|
|
// cancel the old secondary screen threads
|
|
|
|
for (CThreads::iterator index = threads.begin();
|
2002-05-31 18:09:43 +00:00
|
|
|
index != threads.end(); ++index) {
|
2002-06-08 23:24:40 +00:00
|
|
|
index->cancel();
|
2002-05-31 18:09:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// wait for old secondary screen threads to disconnect. must
|
|
|
|
// not hold lock while we do this so those threads can finish
|
|
|
|
// any calls to this object.
|
|
|
|
for (CThreads::iterator index = threads.begin();
|
|
|
|
index != threads.end(); ++index) {
|
|
|
|
index->wait();
|
|
|
|
}
|
|
|
|
|
2002-06-21 15:18:01 +00:00
|
|
|
// clean up thread list
|
|
|
|
reapThreads();
|
|
|
|
|
2002-06-08 23:24:40 +00:00
|
|
|
// cut over
|
|
|
|
CLock lock(&m_mutex);
|
|
|
|
m_config = config;
|
|
|
|
|
|
|
|
// tell primary screen about reconfiguration
|
|
|
|
if (m_primary != NULL) {
|
|
|
|
m_primary->onConfigure();
|
|
|
|
}
|
|
|
|
|
2002-05-31 18:09:43 +00:00
|
|
|
return true;
|
2001-10-06 14:13:28 +00:00
|
|
|
}
|
|
|
|
|
2002-06-10 22:06:45 +00:00
|
|
|
CString
|
|
|
|
CServer::getPrimaryScreenName() const
|
2002-05-30 16:13:16 +00:00
|
|
|
{
|
2002-06-09 17:59:32 +00:00
|
|
|
return m_name;
|
2002-05-30 16:13:16 +00:00
|
|
|
}
|
|
|
|
|
2002-06-10 22:06:45 +00:00
|
|
|
void
|
2002-06-17 13:31:21 +00:00
|
|
|
CServer::getConfig(CConfig* config) const
|
2001-10-06 14:13:28 +00:00
|
|
|
{
|
2002-05-31 14:43:23 +00:00
|
|
|
assert(config != NULL);
|
2001-10-06 14:13:28 +00:00
|
|
|
|
|
|
|
CLock lock(&m_mutex);
|
2002-05-31 14:43:23 +00:00
|
|
|
*config = m_config;
|
2001-10-06 14:13:28 +00:00
|
|
|
}
|
|
|
|
|
2002-06-10 22:06:45 +00:00
|
|
|
UInt32
|
|
|
|
CServer::getActivePrimarySides() const
|
2001-11-19 00:33:36 +00:00
|
|
|
{
|
|
|
|
UInt32 sides = 0;
|
|
|
|
CLock lock(&m_mutex);
|
2002-05-31 18:09:43 +00:00
|
|
|
if (!m_config.getNeighbor(getPrimaryScreenName(),
|
|
|
|
CConfig::kLeft).empty()) {
|
2002-05-31 14:43:23 +00:00
|
|
|
sides |= CConfig::kLeftMask;
|
2002-05-31 18:09:43 +00:00
|
|
|
}
|
|
|
|
if (!m_config.getNeighbor(getPrimaryScreenName(),
|
|
|
|
CConfig::kRight).empty()) {
|
2002-05-31 14:43:23 +00:00
|
|
|
sides |= CConfig::kRightMask;
|
2002-05-31 18:09:43 +00:00
|
|
|
}
|
|
|
|
if (!m_config.getNeighbor(getPrimaryScreenName(),
|
|
|
|
CConfig::kTop).empty()) {
|
2002-05-31 14:43:23 +00:00
|
|
|
sides |= CConfig::kTopMask;
|
2002-05-31 18:09:43 +00:00
|
|
|
}
|
|
|
|
if (!m_config.getNeighbor(getPrimaryScreenName(),
|
|
|
|
CConfig::kBottom).empty()) {
|
2002-05-31 14:43:23 +00:00
|
|
|
sides |= CConfig::kBottomMask;
|
2002-05-31 18:09:43 +00:00
|
|
|
}
|
2001-11-19 00:33:36 +00:00
|
|
|
return sides;
|
|
|
|
}
|
|
|
|
|
2002-06-10 22:06:45 +00:00
|
|
|
void
|
2002-06-19 17:03:29 +00:00
|
|
|
CServer::setInfo(SInt32 x, SInt32 y, SInt32 w, SInt32 h,
|
|
|
|
SInt32 zoneSize, SInt32 mx, SInt32 my)
|
2002-05-24 17:54:28 +00:00
|
|
|
{
|
2002-06-01 10:52:02 +00:00
|
|
|
CLock lock(&m_mutex);
|
|
|
|
assert(m_primaryInfo != NULL);
|
2002-06-19 17:03:29 +00:00
|
|
|
setInfoNoLock(m_primaryInfo->m_name, x, y, w, h, zoneSize, mx, my);
|
2002-05-24 17:54:28 +00:00
|
|
|
}
|
|
|
|
|
2002-06-10 22:06:45 +00:00
|
|
|
void
|
2002-06-17 13:31:21 +00:00
|
|
|
CServer::setInfo(const CString& client,
|
2002-06-19 17:03:29 +00:00
|
|
|
SInt32 x, SInt32 y, SInt32 w, SInt32 h,
|
|
|
|
SInt32 zoneSize, SInt32 mx, SInt32 my)
|
2001-10-06 14:13:28 +00:00
|
|
|
{
|
2002-06-01 10:52:02 +00:00
|
|
|
CLock lock(&m_mutex);
|
2002-06-19 17:03:29 +00:00
|
|
|
setInfoNoLock(client, x, y, w, h, zoneSize, mx, my);
|
2002-06-01 10:52:02 +00:00
|
|
|
}
|
|
|
|
|
2002-06-10 22:06:45 +00:00
|
|
|
void
|
2002-06-17 13:31:21 +00:00
|
|
|
CServer::setInfoNoLock(const CString& screen,
|
2002-06-19 17:03:29 +00:00
|
|
|
SInt32 x, SInt32 y, SInt32 w, SInt32 h,
|
|
|
|
SInt32 zoneSize, SInt32 mx, SInt32 my)
|
2002-06-01 10:52:02 +00:00
|
|
|
{
|
|
|
|
assert(!screen.empty());
|
2002-04-29 14:25:24 +00:00
|
|
|
assert(w > 0);
|
|
|
|
assert(h > 0);
|
|
|
|
assert(zoneSize >= 0);
|
|
|
|
|
2002-06-01 10:52:02 +00:00
|
|
|
// screen must be connected
|
2002-06-09 17:21:33 +00:00
|
|
|
CScreenList::iterator index = m_screens.find(screen);
|
2001-10-06 14:13:28 +00:00
|
|
|
if (index == m_screens.end()) {
|
|
|
|
throw XBadClient();
|
|
|
|
}
|
|
|
|
|
2002-06-01 10:52:02 +00:00
|
|
|
// screen is now ready (i.e. available to user)
|
2001-10-06 14:13:28 +00:00
|
|
|
CScreenInfo* info = index->second;
|
2002-06-01 10:52:02 +00:00
|
|
|
info->m_ready = true;
|
|
|
|
|
|
|
|
// update screen info
|
2001-10-06 14:13:28 +00:00
|
|
|
if (info == m_active) {
|
2002-05-24 17:54:28 +00:00
|
|
|
// update the remote mouse coordinates
|
2002-06-19 17:03:29 +00:00
|
|
|
m_x = mx;
|
|
|
|
m_y = my;
|
2001-10-06 14:13:28 +00:00
|
|
|
}
|
2002-06-19 17:03:29 +00:00
|
|
|
info->m_x = x;
|
|
|
|
info->m_y = y;
|
|
|
|
info->m_w = w;
|
|
|
|
info->m_h = h;
|
2001-10-06 14:13:28 +00:00
|
|
|
info->m_zoneSize = zoneSize;
|
2002-06-19 17:03:29 +00:00
|
|
|
log((CLOG_INFO "screen \"%s\" shape=%d,%d %dx%d zone=%d pos=%d,%d", screen.c_str(), x, y, w, h, zoneSize, mx, my));
|
2002-05-24 17:54:28 +00:00
|
|
|
|
2002-06-01 10:52:02 +00:00
|
|
|
// send acknowledgement (if screen isn't the primary)
|
2002-05-24 17:54:28 +00:00
|
|
|
if (info->m_protocol != NULL) {
|
|
|
|
info->m_protocol->sendInfoAcknowledgment();
|
|
|
|
}
|
|
|
|
|
|
|
|
// handle resolution change to primary screen
|
|
|
|
else {
|
|
|
|
if (info == m_active) {
|
2002-06-19 17:03:29 +00:00
|
|
|
onMouseMovePrimaryNoLock(mx, my);
|
2002-05-24 17:54:28 +00:00
|
|
|
}
|
|
|
|
else {
|
2002-06-01 10:52:02 +00:00
|
|
|
onMouseMoveSecondaryNoLock(0, 0);
|
2002-05-24 17:54:28 +00:00
|
|
|
}
|
|
|
|
}
|
2001-10-06 14:13:28 +00:00
|
|
|
}
|
|
|
|
|
2002-06-10 22:06:45 +00:00
|
|
|
void
|
2002-06-17 13:31:21 +00:00
|
|
|
CServer::grabClipboard(ClipboardID id)
|
2001-11-25 18:32:41 +00:00
|
|
|
{
|
2002-06-01 10:52:02 +00:00
|
|
|
CLock lock(&m_mutex);
|
|
|
|
assert(m_primaryInfo != NULL);
|
|
|
|
grabClipboardNoLock(id, 0, m_primaryInfo->m_name);
|
2001-11-25 18:32:41 +00:00
|
|
|
}
|
|
|
|
|
2002-06-10 22:06:45 +00:00
|
|
|
void
|
2002-06-17 13:31:21 +00:00
|
|
|
CServer::grabClipboard(ClipboardID id, UInt32 seqNum, const CString& client)
|
2001-11-25 18:32:41 +00:00
|
|
|
{
|
|
|
|
CLock lock(&m_mutex);
|
2002-06-01 10:52:02 +00:00
|
|
|
grabClipboardNoLock(id, seqNum, client);
|
|
|
|
}
|
|
|
|
|
2002-06-10 22:06:45 +00:00
|
|
|
void
|
2002-06-17 13:31:21 +00:00
|
|
|
CServer::grabClipboardNoLock(ClipboardID id,
|
|
|
|
UInt32 seqNum, const CString& screen)
|
2002-06-01 10:52:02 +00:00
|
|
|
{
|
|
|
|
// note -- must be locked on entry
|
2002-04-29 13:31:44 +00:00
|
|
|
CClipboardInfo& clipboard = m_clipboards[id];
|
2001-11-25 18:32:41 +00:00
|
|
|
|
2002-04-29 13:31:44 +00:00
|
|
|
// screen must be connected
|
2002-06-09 17:21:33 +00:00
|
|
|
CScreenList::iterator index = m_screens.find(screen);
|
2001-11-25 18:32:41 +00:00
|
|
|
if (index == m_screens.end()) {
|
|
|
|
throw XBadClient();
|
|
|
|
}
|
|
|
|
|
2002-04-29 13:31:44 +00:00
|
|
|
// ignore grab if sequence number is old. always allow primary
|
|
|
|
// screen to grab.
|
2002-06-09 17:21:33 +00:00
|
|
|
if (screen != m_primaryInfo->m_name &&
|
2002-04-29 13:31:44 +00:00
|
|
|
seqNum < clipboard.m_clipboardSeqNum) {
|
2002-06-01 10:52:02 +00:00
|
|
|
log((CLOG_INFO "ignored screen \"%s\" grab of clipboard %d", screen.c_str(), id));
|
2002-04-29 13:31:44 +00:00
|
|
|
return;
|
|
|
|
}
|
2001-11-25 18:32:41 +00:00
|
|
|
|
2002-04-29 13:31:44 +00:00
|
|
|
// mark screen as owning clipboard
|
2002-06-08 21:48:00 +00:00
|
|
|
log((CLOG_INFO "screen \"%s\" grabbed clipboard %d from \"%s\"", screen.c_str(), id, clipboard.m_clipboardOwner.c_str()));
|
2002-06-09 17:21:33 +00:00
|
|
|
clipboard.m_clipboardOwner = screen;
|
2002-04-29 13:31:44 +00:00
|
|
|
clipboard.m_clipboardSeqNum = seqNum;
|
2001-11-25 18:32:41 +00:00
|
|
|
|
2002-04-29 13:31:44 +00:00
|
|
|
// no screens have the new clipboard except the sender
|
|
|
|
clearGotClipboard(id);
|
2002-04-27 14:19:53 +00:00
|
|
|
index->second->m_gotClipboard[id] = true;
|
2001-11-25 18:32:41 +00:00
|
|
|
|
2002-04-29 13:31:44 +00:00
|
|
|
// tell all other screens to take ownership of clipboard
|
2001-11-25 18:32:41 +00:00
|
|
|
for (index = m_screens.begin(); index != m_screens.end(); ++index) {
|
2002-06-09 17:21:33 +00:00
|
|
|
if (index->first != screen) {
|
2001-11-25 18:32:41 +00:00
|
|
|
CScreenInfo* info = index->second;
|
|
|
|
if (info->m_protocol == NULL) {
|
2002-04-27 14:19:53 +00:00
|
|
|
m_primary->grabClipboard(id);
|
2001-11-25 18:32:41 +00:00
|
|
|
}
|
|
|
|
else {
|
2002-04-27 14:19:53 +00:00
|
|
|
info->m_protocol->sendGrabClipboard(id);
|
2001-11-25 18:32:41 +00:00
|
|
|
}
|
|
|
|
}
|
2002-04-29 13:31:44 +00:00
|
|
|
}
|
2001-11-25 18:32:41 +00:00
|
|
|
|
2002-04-29 13:31:44 +00:00
|
|
|
// get the clipboard data if primary has it, otherwise mark the
|
|
|
|
// clipboard data as unknown.
|
2001-11-25 18:32:41 +00:00
|
|
|
if (m_active->m_protocol == NULL) {
|
|
|
|
// get clipboard immediately from primary screen
|
2002-04-27 14:19:53 +00:00
|
|
|
m_primary->getClipboard(id, &clipboard.m_clipboard);
|
|
|
|
clipboard.m_clipboardData = clipboard.m_clipboard.marshall();
|
|
|
|
clipboard.m_clipboardReady = true;
|
2001-11-25 18:32:41 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
// clear out the clipboard since existing data is now out of date.
|
2002-04-29 13:31:44 +00:00
|
|
|
if (clipboard.m_clipboard.open(0)) {
|
2002-04-27 14:19:53 +00:00
|
|
|
clipboard.m_clipboard.close();
|
2001-11-25 18:32:41 +00:00
|
|
|
}
|
2002-04-27 14:19:53 +00:00
|
|
|
clipboard.m_clipboardReady = false;
|
2001-11-25 18:32:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-06-10 22:06:45 +00:00
|
|
|
void
|
2002-06-17 13:31:21 +00:00
|
|
|
CServer::setClipboard(ClipboardID id, UInt32 seqNum, const CString& data)
|
2001-11-25 18:32:41 +00:00
|
|
|
{
|
|
|
|
CLock lock(&m_mutex);
|
2002-04-29 13:31:44 +00:00
|
|
|
CClipboardInfo& clipboard = m_clipboards[id];
|
2001-11-25 18:32:41 +00:00
|
|
|
|
2002-04-29 13:31:44 +00:00
|
|
|
// ignore update if sequence number is old
|
|
|
|
if (seqNum < clipboard.m_clipboardSeqNum) {
|
2002-06-01 10:52:02 +00:00
|
|
|
log((CLOG_INFO "ignored screen \"%s\" update of clipboard %d", clipboard.m_clipboardOwner.c_str(), id));
|
2002-04-29 13:31:44 +00:00
|
|
|
return;
|
2001-11-25 18:32:41 +00:00
|
|
|
}
|
2002-04-29 13:31:44 +00:00
|
|
|
|
|
|
|
// unmarshall into our clipboard buffer
|
2002-06-08 21:48:00 +00:00
|
|
|
log((CLOG_INFO "screen \"%s\" updated clipboard %d", clipboard.m_clipboardOwner.c_str(), id));
|
2002-04-29 13:31:44 +00:00
|
|
|
clipboard.m_clipboardReady = true;
|
|
|
|
clipboard.m_clipboardData = data;
|
|
|
|
clipboard.m_clipboard.unmarshall(clipboard.m_clipboardData, 0);
|
|
|
|
|
|
|
|
// all screens have an out-of-date clipboard except the sender
|
|
|
|
clearGotClipboard(id);
|
|
|
|
CScreenList::const_iterator index =
|
|
|
|
m_screens.find(clipboard.m_clipboardOwner);
|
|
|
|
if (index != m_screens.end()) {
|
|
|
|
index->second->m_gotClipboard[id] = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// send the new clipboard to the active screen (will do nothing if
|
|
|
|
// the active screen is the one sending the new clipboard)
|
|
|
|
sendClipboard(id);
|
2001-11-25 18:32:41 +00:00
|
|
|
}
|
|
|
|
|
2002-06-10 22:06:45 +00:00
|
|
|
bool
|
2002-06-17 13:31:21 +00:00
|
|
|
CServer::onCommandKey(KeyID /*id*/, KeyModifierMask /*mask*/, bool /*down*/)
|
2001-10-06 14:13:28 +00:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2002-06-10 22:06:45 +00:00
|
|
|
void
|
2002-06-17 13:31:21 +00:00
|
|
|
CServer::onKeyDown(KeyID id, KeyModifierMask mask)
|
2001-10-06 14:13:28 +00:00
|
|
|
{
|
2002-04-27 18:49:03 +00:00
|
|
|
log((CLOG_DEBUG1 "onKeyDown id=%d mask=0x%04x", id, mask));
|
2002-06-01 10:52:02 +00:00
|
|
|
CLock lock(&m_mutex);
|
2001-10-06 14:13:28 +00:00
|
|
|
assert(m_active != NULL);
|
|
|
|
|
|
|
|
// handle command keys
|
|
|
|
if (onCommandKey(id, mask, true)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// relay
|
|
|
|
if (m_active->m_protocol != NULL) {
|
|
|
|
m_active->m_protocol->sendKeyDown(id, mask);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-06-10 22:06:45 +00:00
|
|
|
void
|
2002-06-17 13:31:21 +00:00
|
|
|
CServer::onKeyUp(KeyID id, KeyModifierMask mask)
|
2001-10-06 14:13:28 +00:00
|
|
|
{
|
2002-04-27 18:49:03 +00:00
|
|
|
log((CLOG_DEBUG1 "onKeyUp id=%d mask=0x%04x", id, mask));
|
2002-06-01 10:52:02 +00:00
|
|
|
CLock lock(&m_mutex);
|
2001-10-06 14:13:28 +00:00
|
|
|
assert(m_active != NULL);
|
|
|
|
|
|
|
|
// handle command keys
|
|
|
|
if (onCommandKey(id, mask, false)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// relay
|
|
|
|
if (m_active->m_protocol != NULL) {
|
|
|
|
m_active->m_protocol->sendKeyUp(id, mask);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-06-10 22:06:45 +00:00
|
|
|
void
|
2002-06-17 13:31:21 +00:00
|
|
|
CServer::onKeyRepeat(KeyID id, KeyModifierMask mask, SInt32 count)
|
2001-10-06 14:13:28 +00:00
|
|
|
{
|
2002-04-27 18:49:03 +00:00
|
|
|
log((CLOG_DEBUG1 "onKeyRepeat id=%d mask=0x%04x count=%d", id, mask, count));
|
2002-06-01 10:52:02 +00:00
|
|
|
CLock lock(&m_mutex);
|
2001-10-06 14:13:28 +00:00
|
|
|
assert(m_active != NULL);
|
|
|
|
|
|
|
|
// handle command keys
|
|
|
|
if (onCommandKey(id, mask, false)) {
|
|
|
|
onCommandKey(id, mask, true);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// relay
|
|
|
|
if (m_active->m_protocol != NULL) {
|
2001-11-25 18:32:41 +00:00
|
|
|
m_active->m_protocol->sendKeyRepeat(id, mask, count);
|
2001-10-06 14:13:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-06-10 22:06:45 +00:00
|
|
|
void
|
2002-06-17 13:31:21 +00:00
|
|
|
CServer::onMouseDown(ButtonID id)
|
2001-10-06 14:13:28 +00:00
|
|
|
{
|
2002-04-27 18:49:03 +00:00
|
|
|
log((CLOG_DEBUG1 "onMouseDown id=%d", id));
|
2002-06-01 10:52:02 +00:00
|
|
|
CLock lock(&m_mutex);
|
2001-10-06 14:13:28 +00:00
|
|
|
assert(m_active != NULL);
|
|
|
|
|
|
|
|
// relay
|
|
|
|
if (m_active->m_protocol != NULL) {
|
|
|
|
m_active->m_protocol->sendMouseDown(id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-06-10 22:06:45 +00:00
|
|
|
void
|
2002-06-17 13:31:21 +00:00
|
|
|
CServer::onMouseUp(ButtonID id)
|
2001-10-06 14:13:28 +00:00
|
|
|
{
|
2002-04-27 18:49:03 +00:00
|
|
|
log((CLOG_DEBUG1 "onMouseUp id=%d", id));
|
2002-06-01 10:52:02 +00:00
|
|
|
CLock lock(&m_mutex);
|
2001-10-06 14:13:28 +00:00
|
|
|
assert(m_active != NULL);
|
|
|
|
|
|
|
|
// relay
|
|
|
|
if (m_active->m_protocol != NULL) {
|
|
|
|
m_active->m_protocol->sendMouseUp(id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-06-10 22:06:45 +00:00
|
|
|
bool
|
2002-06-17 13:31:21 +00:00
|
|
|
CServer::onMouseMovePrimary(SInt32 x, SInt32 y)
|
2001-10-06 14:13:28 +00:00
|
|
|
{
|
2002-04-27 18:49:03 +00:00
|
|
|
log((CLOG_DEBUG2 "onMouseMovePrimary %d,%d", x, y));
|
2002-06-01 10:52:02 +00:00
|
|
|
CLock lock(&m_mutex);
|
|
|
|
return onMouseMovePrimaryNoLock(x, y);
|
|
|
|
}
|
2001-10-14 14:37:41 +00:00
|
|
|
|
2002-06-10 22:06:45 +00:00
|
|
|
bool
|
2002-06-17 13:31:21 +00:00
|
|
|
CServer::onMouseMovePrimaryNoLock(SInt32 x, SInt32 y)
|
2002-06-01 10:52:02 +00:00
|
|
|
{
|
2001-10-06 14:13:28 +00:00
|
|
|
// mouse move on primary (server's) screen
|
|
|
|
assert(m_active != NULL);
|
|
|
|
assert(m_active->m_protocol == NULL);
|
|
|
|
|
|
|
|
// ignore if mouse is locked to screen
|
2002-06-01 10:52:02 +00:00
|
|
|
if (isLockedToScreenNoLock()) {
|
2001-11-19 00:33:36 +00:00
|
|
|
return false;
|
2001-10-06 14:13:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// see if we should change screens
|
2002-05-31 14:43:23 +00:00
|
|
|
CConfig::EDirection dir;
|
2002-06-19 17:03:29 +00:00
|
|
|
if (x < m_active->m_x + m_active->m_zoneSize) {
|
2001-10-06 14:13:28 +00:00
|
|
|
x -= m_active->m_zoneSize;
|
2002-05-31 14:43:23 +00:00
|
|
|
dir = CConfig::kLeft;
|
2002-04-27 18:49:03 +00:00
|
|
|
log((CLOG_DEBUG1 "switch to left"));
|
2001-10-06 14:13:28 +00:00
|
|
|
}
|
2002-06-19 17:03:29 +00:00
|
|
|
else if (x >= m_active->m_x + m_active->m_w - m_active->m_zoneSize) {
|
2001-10-06 14:13:28 +00:00
|
|
|
x += m_active->m_zoneSize;
|
2002-05-31 14:43:23 +00:00
|
|
|
dir = CConfig::kRight;
|
2002-04-27 18:49:03 +00:00
|
|
|
log((CLOG_DEBUG1 "switch to right"));
|
2001-10-06 14:13:28 +00:00
|
|
|
}
|
2002-06-19 17:03:29 +00:00
|
|
|
else if (y < m_active->m_y + m_active->m_zoneSize) {
|
2001-10-06 14:13:28 +00:00
|
|
|
y -= m_active->m_zoneSize;
|
2002-05-31 14:43:23 +00:00
|
|
|
dir = CConfig::kTop;
|
2002-04-27 18:49:03 +00:00
|
|
|
log((CLOG_DEBUG1 "switch to top"));
|
2001-10-06 14:13:28 +00:00
|
|
|
}
|
2002-06-19 17:03:29 +00:00
|
|
|
else if (y >= m_active->m_y + m_active->m_h - m_active->m_zoneSize) {
|
2001-10-06 14:13:28 +00:00
|
|
|
y += m_active->m_zoneSize;
|
2002-05-31 14:43:23 +00:00
|
|
|
dir = CConfig::kBottom;
|
2002-04-27 18:49:03 +00:00
|
|
|
log((CLOG_DEBUG1 "switch to bottom"));
|
2001-10-06 14:13:28 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
// still on local screen
|
2001-11-19 00:33:36 +00:00
|
|
|
return false;
|
2001-10-06 14:13:28 +00:00
|
|
|
}
|
|
|
|
|
2002-06-19 17:03:29 +00:00
|
|
|
// get jump destination and, if no screen in jump direction,
|
|
|
|
// then ignore the move.
|
2001-10-06 14:13:28 +00:00
|
|
|
CScreenInfo* newScreen = getNeighbor(m_active, dir, x, y);
|
|
|
|
if (newScreen == NULL) {
|
2001-11-19 00:33:36 +00:00
|
|
|
return false;
|
2001-10-06 14:13:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// switch screen
|
2002-06-23 23:24:22 +00:00
|
|
|
switchScreen(newScreen, x, y, false);
|
2001-11-19 00:33:36 +00:00
|
|
|
return true;
|
2001-10-06 14:13:28 +00:00
|
|
|
}
|
|
|
|
|
2002-06-10 22:06:45 +00:00
|
|
|
void
|
2002-06-17 13:31:21 +00:00
|
|
|
CServer::onMouseMoveSecondary(SInt32 dx, SInt32 dy)
|
2001-10-06 14:13:28 +00:00
|
|
|
{
|
2002-05-01 14:36:52 +00:00
|
|
|
log((CLOG_DEBUG2 "onMouseMoveSecondary %+d,%+d", dx, dy));
|
2002-06-01 10:52:02 +00:00
|
|
|
CLock lock(&m_mutex);
|
|
|
|
onMouseMoveSecondaryNoLock(dx, dy);
|
|
|
|
}
|
2001-10-14 14:37:41 +00:00
|
|
|
|
2002-06-10 22:06:45 +00:00
|
|
|
void
|
2002-06-17 13:31:21 +00:00
|
|
|
CServer::onMouseMoveSecondaryNoLock(SInt32 dx, SInt32 dy)
|
2002-06-01 10:52:02 +00:00
|
|
|
{
|
2001-10-06 14:13:28 +00:00
|
|
|
// mouse move on secondary (client's) screen
|
|
|
|
assert(m_active != NULL);
|
2002-06-01 10:52:02 +00:00
|
|
|
if (m_active->m_protocol == NULL) {
|
|
|
|
// we're actually on the primary screen. this can happen
|
|
|
|
// when the primary screen begins processing a mouse move
|
|
|
|
// for a secondary screen, then the active (secondary)
|
|
|
|
// screen disconnects causing us to jump to the primary
|
|
|
|
// screen, and finally the primary screen finishes
|
|
|
|
// processing the mouse move, still thinking it's for
|
|
|
|
// a secondary screen. we just ignore the motion.
|
|
|
|
return;
|
|
|
|
}
|
2001-10-06 14:13:28 +00:00
|
|
|
|
|
|
|
// save old position
|
|
|
|
const SInt32 xOld = m_x;
|
|
|
|
const SInt32 yOld = m_y;
|
|
|
|
|
|
|
|
// accumulate motion
|
|
|
|
m_x += dx;
|
|
|
|
m_y += dy;
|
|
|
|
|
|
|
|
// switch screens if the mouse is outside the screen and not
|
|
|
|
// locked to the screen
|
|
|
|
CScreenInfo* newScreen = NULL;
|
2002-06-01 10:52:02 +00:00
|
|
|
if (!isLockedToScreenNoLock()) {
|
2001-10-06 14:13:28 +00:00
|
|
|
// find direction of neighbor
|
2002-05-31 14:43:23 +00:00
|
|
|
CConfig::EDirection dir;
|
2002-06-19 17:03:29 +00:00
|
|
|
if (m_x < m_active->m_x) {
|
2002-05-31 14:43:23 +00:00
|
|
|
dir = CConfig::kLeft;
|
2002-06-08 21:48:00 +00:00
|
|
|
}
|
2002-06-19 17:03:29 +00:00
|
|
|
else if (m_x > m_active->m_x + m_active->m_w - 1) {
|
2002-05-31 14:43:23 +00:00
|
|
|
dir = CConfig::kRight;
|
2002-06-08 21:48:00 +00:00
|
|
|
}
|
2002-06-19 17:03:29 +00:00
|
|
|
else if (m_y < m_active->m_y) {
|
2002-05-31 14:43:23 +00:00
|
|
|
dir = CConfig::kTop;
|
2002-06-08 21:48:00 +00:00
|
|
|
}
|
2002-06-19 17:03:29 +00:00
|
|
|
else if (m_y > m_active->m_y + m_active->m_h - 1) {
|
2002-05-31 14:43:23 +00:00
|
|
|
dir = CConfig::kBottom;
|
2002-06-08 21:48:00 +00:00
|
|
|
}
|
|
|
|
else {
|
2001-10-06 14:13:28 +00:00
|
|
|
newScreen = m_active;
|
|
|
|
|
2002-06-08 21:48:00 +00:00
|
|
|
// keep compiler quiet about unset variable
|
|
|
|
dir = CConfig::kLeft;
|
|
|
|
}
|
|
|
|
|
2001-10-06 14:13:28 +00:00
|
|
|
// get neighbor if we should switch
|
|
|
|
if (newScreen == NULL) {
|
2002-05-31 14:43:23 +00:00
|
|
|
log((CLOG_DEBUG1 "leave \"%s\" on %s", m_active->m_name.c_str(), CConfig::dirName(dir)));
|
2001-10-06 14:13:28 +00:00
|
|
|
|
2002-06-19 17:03:29 +00:00
|
|
|
// get new position or clamp to current screen
|
|
|
|
newScreen = getNeighbor(m_active, dir, m_x, m_y);
|
|
|
|
if (newScreen == NULL) {
|
2002-04-27 18:49:03 +00:00
|
|
|
log((CLOG_DEBUG1 "no neighbor; clamping"));
|
2002-06-19 17:03:29 +00:00
|
|
|
if (m_x < m_active->m_x)
|
|
|
|
m_x = m_active->m_x;
|
|
|
|
else if (m_x > m_active->m_x + m_active->m_w - 1)
|
|
|
|
m_x = m_active->m_x + m_active->m_w - 1;
|
|
|
|
if (m_y < m_active->m_y)
|
|
|
|
m_y = m_active->m_y;
|
|
|
|
else if (m_y > m_active->m_y + m_active->m_h - 1)
|
|
|
|
m_y = m_active->m_y + m_active->m_h - 1;
|
2001-10-06 14:13:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// clamp to edge when locked
|
2002-04-27 18:49:03 +00:00
|
|
|
log((CLOG_DEBUG1 "clamp to \"%s\"", m_active->m_name.c_str()));
|
2002-06-19 17:03:29 +00:00
|
|
|
if (m_x < m_active->m_x)
|
|
|
|
m_x = m_active->m_x;
|
|
|
|
else if (m_x > m_active->m_x + m_active->m_w - 1)
|
|
|
|
m_x = m_active->m_x + m_active->m_w - 1;
|
|
|
|
if (m_y < m_active->m_y)
|
|
|
|
m_y = m_active->m_y;
|
|
|
|
else if (m_y > m_active->m_y + m_active->m_h - 1)
|
|
|
|
m_y = m_active->m_y + m_active->m_h - 1;
|
2001-10-06 14:13:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// warp cursor if on same screen
|
|
|
|
if (newScreen == NULL || newScreen == m_active) {
|
|
|
|
// do nothing if mouse didn't move
|
|
|
|
if (m_x != xOld || m_y != yOld) {
|
2002-05-01 14:36:52 +00:00
|
|
|
log((CLOG_DEBUG2 "move on %s to %d,%d", m_active->m_name.c_str(), m_x, m_y));
|
2001-10-06 14:13:28 +00:00
|
|
|
m_active->m_protocol->sendMouseMove(m_x, m_y);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// otherwise screen screens
|
|
|
|
else {
|
2002-06-23 23:24:22 +00:00
|
|
|
switchScreen(newScreen, m_x, m_y, false);
|
2001-10-06 14:13:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-06-10 22:06:45 +00:00
|
|
|
void
|
2002-06-17 13:31:21 +00:00
|
|
|
CServer::onMouseWheel(SInt32 delta)
|
2001-10-06 14:13:28 +00:00
|
|
|
{
|
2002-04-27 18:49:03 +00:00
|
|
|
log((CLOG_DEBUG1 "onMouseWheel %+d", delta));
|
2002-06-01 10:52:02 +00:00
|
|
|
CLock lock(&m_mutex);
|
2001-10-06 14:13:28 +00:00
|
|
|
assert(m_active != NULL);
|
|
|
|
|
|
|
|
// relay
|
|
|
|
if (m_active->m_protocol != NULL) {
|
|
|
|
m_active->m_protocol->sendMouseWheel(delta);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-06-22 19:20:21 +00:00
|
|
|
void
|
|
|
|
CServer::onScreenSaver(bool activated)
|
|
|
|
{
|
|
|
|
log((CLOG_DEBUG "onScreenSaver %s", activated ? "activated" : "deactivated"));
|
|
|
|
CLock lock(&m_mutex);
|
|
|
|
|
|
|
|
if (activated) {
|
|
|
|
// save current screen and position
|
|
|
|
m_activeSaver = m_active;
|
|
|
|
m_xSaver = m_x;
|
|
|
|
m_ySaver = m_y;
|
|
|
|
|
|
|
|
// jump to primary screen
|
|
|
|
if (m_active != m_primaryInfo) {
|
2002-06-23 23:24:22 +00:00
|
|
|
switchScreen(m_primaryInfo, 0, 0, true);
|
2002-06-22 19:20:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// jump back to previous screen and position. we must check
|
|
|
|
// that the position is still valid since the screen may have
|
|
|
|
// changed resolutions while the screen saver was running.
|
|
|
|
if (m_activeSaver != NULL && m_activeSaver != m_primaryInfo) {
|
|
|
|
// check position
|
|
|
|
CScreenInfo* screen = m_activeSaver;
|
|
|
|
if (m_xSaver < screen->m_x + screen->m_zoneSize) {
|
|
|
|
m_xSaver = screen->m_x + screen->m_zoneSize;
|
|
|
|
}
|
|
|
|
else if (m_xSaver >= screen->m_x +
|
|
|
|
screen->m_w - screen->m_zoneSize) {
|
|
|
|
m_xSaver = screen->m_x + screen->m_w - screen->m_zoneSize - 1;
|
|
|
|
}
|
|
|
|
if (m_ySaver < screen->m_y + screen->m_zoneSize) {
|
|
|
|
m_ySaver = screen->m_y + screen->m_zoneSize;
|
|
|
|
}
|
|
|
|
else if (m_ySaver >= screen->m_y +
|
|
|
|
screen->m_h - screen->m_zoneSize) {
|
|
|
|
m_ySaver = screen->m_y + screen->m_h - screen->m_zoneSize - 1;
|
|
|
|
}
|
|
|
|
|
2002-06-23 23:24:22 +00:00
|
|
|
// jump
|
|
|
|
switchScreen(screen, m_xSaver, m_ySaver, false);
|
2002-06-22 19:20:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// reset state
|
|
|
|
m_activeSaver = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// send message to all secondary screens
|
|
|
|
for (CScreenList::const_iterator index = m_screens.begin();
|
|
|
|
index != m_screens.end(); ++index) {
|
|
|
|
if (index->second->m_protocol != NULL) {
|
|
|
|
index->second->m_protocol->sendScreenSaver(activated);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-06-10 22:06:45 +00:00
|
|
|
bool
|
|
|
|
CServer::isLockedToScreen() const
|
2002-06-01 10:52:02 +00:00
|
|
|
{
|
|
|
|
CLock lock(&m_mutex);
|
|
|
|
return isLockedToScreenNoLock();
|
|
|
|
}
|
|
|
|
|
2002-06-10 22:06:45 +00:00
|
|
|
bool
|
|
|
|
CServer::isLockedToScreenNoLock() const
|
2001-10-06 14:13:28 +00:00
|
|
|
{
|
2002-05-24 14:37:12 +00:00
|
|
|
// locked if primary says we're locked
|
|
|
|
if (m_primary->isLockedToScreen()) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// locked if scroll-lock is toggled on
|
|
|
|
if ((m_primary->getToggleMask() & KeyModifierScrollLock) != 0) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// not locked
|
2001-10-06 14:13:28 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2002-06-10 22:06:45 +00:00
|
|
|
void
|
2002-06-23 23:24:22 +00:00
|
|
|
CServer::switchScreen(CScreenInfo* dst, SInt32 x, SInt32 y, bool screenSaver)
|
2001-10-06 14:13:28 +00:00
|
|
|
{
|
|
|
|
assert(dst != NULL);
|
2002-06-19 17:03:29 +00:00
|
|
|
assert(x >= dst->m_x && y >= dst->m_y);
|
|
|
|
assert(x < dst->m_x + dst->m_w && y < dst->m_y + dst->m_h);
|
2001-10-06 14:13:28 +00:00
|
|
|
assert(m_active != NULL);
|
|
|
|
|
2002-06-08 21:48:00 +00:00
|
|
|
log((CLOG_INFO "switch from \"%s\" to \"%s\" at %d,%d", m_active->m_name.c_str(), dst->m_name.c_str(), x, y));
|
2001-11-25 18:32:41 +00:00
|
|
|
// FIXME -- we're not locked here but we probably should be
|
2001-10-06 14:13:28 +00:00
|
|
|
|
2002-06-03 18:53:18 +00:00
|
|
|
// record new position
|
|
|
|
m_x = x;
|
|
|
|
m_y = y;
|
|
|
|
|
2001-10-06 14:13:28 +00:00
|
|
|
// wrapping means leaving the active screen and entering it again.
|
|
|
|
// since that's a waste of time we skip that and just warp the
|
|
|
|
// mouse.
|
|
|
|
if (m_active != dst) {
|
2002-04-29 13:31:44 +00:00
|
|
|
// note if we're leaving the primary screen
|
|
|
|
const bool leavingPrimary = (m_active->m_protocol == NULL);
|
|
|
|
|
2002-06-03 18:53:18 +00:00
|
|
|
// leave active screen
|
2002-04-29 13:31:44 +00:00
|
|
|
if (leavingPrimary) {
|
2002-06-03 18:53:18 +00:00
|
|
|
if (!m_primary->leave()) {
|
|
|
|
// cannot leave primary screen
|
|
|
|
log((CLOG_WARN "can't leave primary screen"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// update the clipboards that the primary screen owns
|
2002-04-29 13:31:44 +00:00
|
|
|
for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
|
|
|
|
updatePrimaryClipboard(id);
|
|
|
|
}
|
|
|
|
}
|
2001-10-06 14:13:28 +00:00
|
|
|
else {
|
|
|
|
m_active->m_protocol->sendLeave();
|
|
|
|
}
|
|
|
|
|
|
|
|
// cut over
|
|
|
|
m_active = dst;
|
|
|
|
|
2002-04-29 13:31:44 +00:00
|
|
|
// increment enter sequence number
|
|
|
|
++m_seqNum;
|
|
|
|
|
2001-10-06 14:13:28 +00:00
|
|
|
// enter new screen
|
|
|
|
if (m_active->m_protocol == NULL) {
|
2002-06-23 23:24:22 +00:00
|
|
|
m_primary->enter(x, y, screenSaver);
|
2001-10-06 14:13:28 +00:00
|
|
|
}
|
|
|
|
else {
|
2002-04-30 17:48:11 +00:00
|
|
|
m_active->m_protocol->sendEnter(x, y, m_seqNum,
|
|
|
|
m_primary->getToggleMask());
|
2001-10-06 14:13:28 +00:00
|
|
|
}
|
2001-11-25 18:32:41 +00:00
|
|
|
|
2002-04-29 13:31:44 +00:00
|
|
|
// send the clipboard data to new active screen
|
2002-04-27 14:19:53 +00:00
|
|
|
for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
|
2002-04-29 13:31:44 +00:00
|
|
|
sendClipboard(id);
|
2001-11-25 18:32:41 +00:00
|
|
|
}
|
2001-10-06 14:13:28 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (m_active->m_protocol == NULL) {
|
|
|
|
m_primary->warpCursor(x, y);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
m_active->m_protocol->sendMouseMove(x, y);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-06-10 22:06:45 +00:00
|
|
|
CServer::CScreenInfo*
|
2002-06-17 13:31:21 +00:00
|
|
|
CServer::getNeighbor(CScreenInfo* src, CConfig::EDirection dir) const
|
2001-10-06 14:13:28 +00:00
|
|
|
{
|
|
|
|
assert(src != NULL);
|
|
|
|
|
|
|
|
CString srcName = src->m_name;
|
|
|
|
assert(!srcName.empty());
|
2002-05-31 14:43:23 +00:00
|
|
|
log((CLOG_DEBUG2 "find neighbor on %s of \"%s\"", CConfig::dirName(dir), srcName.c_str()));
|
2001-10-06 14:13:28 +00:00
|
|
|
for (;;) {
|
|
|
|
// look up name of neighbor
|
2002-05-31 14:43:23 +00:00
|
|
|
const CString dstName(m_config.getNeighbor(srcName, dir));
|
2001-10-06 14:13:28 +00:00
|
|
|
|
|
|
|
// if nothing in that direction then return NULL
|
2001-10-14 14:37:41 +00:00
|
|
|
if (dstName.empty()) {
|
2002-05-31 14:43:23 +00:00
|
|
|
log((CLOG_DEBUG2 "no neighbor on %s of \"%s\"", CConfig::dirName(dir), srcName.c_str()));
|
2001-10-06 14:13:28 +00:00
|
|
|
return NULL;
|
2001-10-14 14:37:41 +00:00
|
|
|
}
|
2001-10-06 14:13:28 +00:00
|
|
|
|
2002-06-01 10:52:02 +00:00
|
|
|
// look up neighbor cell. if the screen is connected and
|
|
|
|
// ready then we can stop. otherwise we skip over an
|
|
|
|
// unconnected screen.
|
2001-10-06 14:13:28 +00:00
|
|
|
CScreenList::const_iterator index = m_screens.find(dstName);
|
2002-06-01 10:52:02 +00:00
|
|
|
if (index != m_screens.end() && index->second->m_ready) {
|
2002-05-31 14:43:23 +00:00
|
|
|
log((CLOG_DEBUG2 "\"%s\" is on %s of \"%s\"", dstName.c_str(), CConfig::dirName(dir), srcName.c_str()));
|
2001-10-06 14:13:28 +00:00
|
|
|
return index->second;
|
|
|
|
}
|
|
|
|
|
2002-05-31 14:43:23 +00:00
|
|
|
log((CLOG_DEBUG2 "ignored \"%s\" on %s of \"%s\"", dstName.c_str(), CConfig::dirName(dir), srcName.c_str()));
|
2001-10-06 14:13:28 +00:00
|
|
|
srcName = dstName;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-06-10 22:06:45 +00:00
|
|
|
CServer::CScreenInfo*
|
2002-06-17 13:31:21 +00:00
|
|
|
CServer::getNeighbor(CScreenInfo* src,
|
|
|
|
CConfig::EDirection srcSide, SInt32& x, SInt32& y) const
|
2001-10-06 14:13:28 +00:00
|
|
|
{
|
|
|
|
assert(src != NULL);
|
|
|
|
|
|
|
|
// get the first neighbor
|
|
|
|
CScreenInfo* dst = getNeighbor(src, srcSide);
|
2002-06-11 18:31:06 +00:00
|
|
|
if (dst == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2001-10-06 14:13:28 +00:00
|
|
|
|
|
|
|
// get the source screen's size (needed for kRight and kBottom)
|
2002-06-19 17:03:29 +00:00
|
|
|
SInt32 w = src->m_w, h = src->m_h;
|
2001-10-06 14:13:28 +00:00
|
|
|
|
2002-06-19 17:03:29 +00:00
|
|
|
// find destination screen, adjusting x or y (but not both). the
|
|
|
|
// searches are done in a sort of canonical screen space where
|
|
|
|
// the upper-left corner is 0,0 for each screen. we adjust from
|
|
|
|
// actual to canonical position on entry to and from canonical to
|
|
|
|
// actual on exit from the search.
|
|
|
|
CScreenInfo* lastGoodScreen = src;
|
2001-10-06 14:13:28 +00:00
|
|
|
switch (srcSide) {
|
2002-05-31 14:43:23 +00:00
|
|
|
case CConfig::kLeft:
|
2002-06-19 17:03:29 +00:00
|
|
|
x -= src->m_x;
|
2002-06-11 18:31:06 +00:00
|
|
|
while (dst != NULL && dst != lastGoodScreen) {
|
2001-10-06 14:13:28 +00:00
|
|
|
lastGoodScreen = dst;
|
2002-06-19 17:03:29 +00:00
|
|
|
w = lastGoodScreen->m_w;
|
|
|
|
h = lastGoodScreen->m_h;
|
2001-10-06 14:13:28 +00:00
|
|
|
x += w;
|
|
|
|
if (x >= 0) {
|
|
|
|
break;
|
|
|
|
}
|
2002-04-27 18:49:03 +00:00
|
|
|
log((CLOG_DEBUG2 "skipping over screen %s", dst->m_name.c_str()));
|
2001-10-06 14:13:28 +00:00
|
|
|
dst = getNeighbor(lastGoodScreen, srcSide);
|
|
|
|
}
|
2002-06-19 17:03:29 +00:00
|
|
|
assert(lastGoodScreen != NULL);
|
|
|
|
x += lastGoodScreen->m_x;
|
2001-10-06 14:13:28 +00:00
|
|
|
break;
|
|
|
|
|
2002-05-31 14:43:23 +00:00
|
|
|
case CConfig::kRight:
|
2002-06-19 17:03:29 +00:00
|
|
|
x -= src->m_x;
|
2001-10-06 14:13:28 +00:00
|
|
|
while (dst != NULL) {
|
|
|
|
lastGoodScreen = dst;
|
|
|
|
x -= w;
|
2002-06-19 17:03:29 +00:00
|
|
|
w = lastGoodScreen->m_w;
|
|
|
|
h = lastGoodScreen->m_h;
|
2001-10-06 14:13:28 +00:00
|
|
|
if (x < w) {
|
|
|
|
break;
|
|
|
|
}
|
2002-04-27 18:49:03 +00:00
|
|
|
log((CLOG_DEBUG2 "skipping over screen %s", dst->m_name.c_str()));
|
2001-10-06 14:13:28 +00:00
|
|
|
dst = getNeighbor(lastGoodScreen, srcSide);
|
|
|
|
}
|
2002-06-19 17:03:29 +00:00
|
|
|
assert(lastGoodScreen != NULL);
|
|
|
|
x += lastGoodScreen->m_x;
|
2001-10-06 14:13:28 +00:00
|
|
|
break;
|
|
|
|
|
2002-05-31 14:43:23 +00:00
|
|
|
case CConfig::kTop:
|
2002-06-19 17:03:29 +00:00
|
|
|
y -= src->m_y;
|
2001-10-06 14:13:28 +00:00
|
|
|
while (dst != NULL) {
|
|
|
|
lastGoodScreen = dst;
|
2002-06-19 17:03:29 +00:00
|
|
|
w = lastGoodScreen->m_w;
|
|
|
|
h = lastGoodScreen->m_h;
|
2001-10-06 14:13:28 +00:00
|
|
|
y += h;
|
|
|
|
if (y >= 0) {
|
|
|
|
break;
|
|
|
|
}
|
2002-04-27 18:49:03 +00:00
|
|
|
log((CLOG_DEBUG2 "skipping over screen %s", dst->m_name.c_str()));
|
2001-10-06 14:13:28 +00:00
|
|
|
dst = getNeighbor(lastGoodScreen, srcSide);
|
|
|
|
}
|
2002-06-19 17:03:29 +00:00
|
|
|
assert(lastGoodScreen != NULL);
|
|
|
|
y += lastGoodScreen->m_y;
|
2001-10-06 14:13:28 +00:00
|
|
|
break;
|
|
|
|
|
2002-05-31 14:43:23 +00:00
|
|
|
case CConfig::kBottom:
|
2002-06-19 17:03:29 +00:00
|
|
|
y -= src->m_y;
|
2001-10-06 14:13:28 +00:00
|
|
|
while (dst != NULL) {
|
|
|
|
lastGoodScreen = dst;
|
|
|
|
y -= h;
|
2002-06-19 17:03:29 +00:00
|
|
|
w = lastGoodScreen->m_w;
|
|
|
|
h = lastGoodScreen->m_h;
|
2001-10-06 14:13:28 +00:00
|
|
|
if (y < h) {
|
|
|
|
break;
|
|
|
|
}
|
2002-04-27 18:49:03 +00:00
|
|
|
log((CLOG_DEBUG2 "skipping over screen %s", dst->m_name.c_str()));
|
2001-10-06 14:13:28 +00:00
|
|
|
dst = getNeighbor(lastGoodScreen, srcSide);
|
|
|
|
}
|
2002-06-19 17:03:29 +00:00
|
|
|
assert(lastGoodScreen != NULL);
|
|
|
|
y += lastGoodScreen->m_y;
|
2001-10-06 14:13:28 +00:00
|
|
|
break;
|
|
|
|
}
|
2001-10-23 21:13:08 +00:00
|
|
|
|
2002-06-19 17:03:29 +00:00
|
|
|
// save destination screen
|
|
|
|
assert(lastGoodScreen != NULL);
|
|
|
|
dst = lastGoodScreen;
|
2001-10-06 14:13:28 +00:00
|
|
|
|
|
|
|
// if entering primary screen then be sure to move in far enough
|
|
|
|
// to avoid the jump zone. if entering a side that doesn't have
|
|
|
|
// a neighbor (i.e. an asymmetrical side) then we don't need to
|
|
|
|
// move inwards because that side can't provoke a jump.
|
2002-06-19 17:03:29 +00:00
|
|
|
if (dst->m_protocol == NULL) {
|
|
|
|
const CString dstName(dst->m_name);
|
2001-10-06 14:13:28 +00:00
|
|
|
switch (srcSide) {
|
2002-05-31 14:43:23 +00:00
|
|
|
case CConfig::kLeft:
|
|
|
|
if (!m_config.getNeighbor(dstName, CConfig::kRight).empty() &&
|
2002-06-19 17:03:29 +00:00
|
|
|
x > dst->m_x + w - 1 - dst->m_zoneSize)
|
|
|
|
x = dst->m_x + w - 1 - dst->m_zoneSize;
|
2001-10-06 14:13:28 +00:00
|
|
|
break;
|
|
|
|
|
2002-05-31 14:43:23 +00:00
|
|
|
case CConfig::kRight:
|
|
|
|
if (!m_config.getNeighbor(dstName, CConfig::kLeft).empty() &&
|
2002-06-19 17:03:29 +00:00
|
|
|
x < dst->m_x + dst->m_zoneSize)
|
|
|
|
x = dst->m_x + dst->m_zoneSize;
|
2001-10-06 14:13:28 +00:00
|
|
|
break;
|
|
|
|
|
2002-05-31 14:43:23 +00:00
|
|
|
case CConfig::kTop:
|
|
|
|
if (!m_config.getNeighbor(dstName, CConfig::kBottom).empty() &&
|
2002-06-19 17:03:29 +00:00
|
|
|
y > dst->m_y + h - 1 - dst->m_zoneSize)
|
|
|
|
y = dst->m_y + h - 1 - dst->m_zoneSize;
|
2001-10-06 14:13:28 +00:00
|
|
|
break;
|
|
|
|
|
2002-05-31 14:43:23 +00:00
|
|
|
case CConfig::kBottom:
|
|
|
|
if (!m_config.getNeighbor(dstName, CConfig::kTop).empty() &&
|
2002-06-19 17:03:29 +00:00
|
|
|
y < dst->m_y + dst->m_zoneSize)
|
|
|
|
y = dst->m_y + dst->m_zoneSize;
|
2001-10-06 14:13:28 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-06-19 17:03:29 +00:00
|
|
|
// adjust the coordinate orthogonal to srcSide to account for
|
|
|
|
// resolution differences. for example, if y is 200 pixels from
|
|
|
|
// the top on a screen 1000 pixels high (20% from the top) when
|
|
|
|
// we cross the left edge onto a screen 600 pixels high then y
|
|
|
|
// should be set 120 pixels from the top (again 20% from the
|
|
|
|
// top).
|
2001-10-06 14:13:28 +00:00
|
|
|
switch (srcSide) {
|
2002-05-31 14:43:23 +00:00
|
|
|
case CConfig::kLeft:
|
|
|
|
case CConfig::kRight:
|
2002-06-19 17:03:29 +00:00
|
|
|
y -= src->m_y;
|
2002-06-10 22:06:45 +00:00
|
|
|
if (y < 0) {
|
2001-10-24 23:29:29 +00:00
|
|
|
y = 0;
|
2002-06-10 22:06:45 +00:00
|
|
|
}
|
2002-06-19 17:03:29 +00:00
|
|
|
else if (y >= src->m_h) {
|
|
|
|
y = dst->m_h - 1;
|
2002-06-10 22:06:45 +00:00
|
|
|
}
|
|
|
|
else {
|
2001-10-24 23:29:29 +00:00
|
|
|
y = static_cast<SInt32>(0.5 + y *
|
2002-06-19 17:03:29 +00:00
|
|
|
static_cast<double>(dst->m_h - 1) /
|
|
|
|
(src->m_h - 1));
|
2002-06-10 22:06:45 +00:00
|
|
|
}
|
2002-06-19 17:03:29 +00:00
|
|
|
y += dst->m_y;
|
2001-10-06 14:13:28 +00:00
|
|
|
break;
|
|
|
|
|
2002-05-31 14:43:23 +00:00
|
|
|
case CConfig::kTop:
|
|
|
|
case CConfig::kBottom:
|
2002-06-19 17:03:29 +00:00
|
|
|
x -= src->m_x;
|
2002-06-10 22:06:45 +00:00
|
|
|
if (x < 0) {
|
2001-10-24 23:29:29 +00:00
|
|
|
x = 0;
|
2002-06-10 22:06:45 +00:00
|
|
|
}
|
2002-06-19 17:03:29 +00:00
|
|
|
else if (x >= src->m_w) {
|
|
|
|
x = dst->m_w - 1;
|
2002-06-10 22:06:45 +00:00
|
|
|
}
|
|
|
|
else {
|
2001-10-24 23:29:29 +00:00
|
|
|
x = static_cast<SInt32>(0.5 + x *
|
2002-06-19 17:03:29 +00:00
|
|
|
static_cast<double>(dst->m_w - 1) /
|
|
|
|
(src->m_w - 1));
|
2002-06-10 22:06:45 +00:00
|
|
|
}
|
2002-06-19 17:03:29 +00:00
|
|
|
x += dst->m_x;
|
2001-10-06 14:13:28 +00:00
|
|
|
break;
|
|
|
|
}
|
2002-06-19 17:03:29 +00:00
|
|
|
|
|
|
|
return dst;
|
2001-10-06 14:13:28 +00:00
|
|
|
}
|
|
|
|
|
2002-06-21 15:18:01 +00:00
|
|
|
void
|
|
|
|
CServer::startThread(IJob* job)
|
|
|
|
{
|
|
|
|
CLock lock(&m_mutex);
|
|
|
|
doReapThreads(m_threads);
|
|
|
|
CThread* thread = new CThread(job);
|
|
|
|
m_threads.push_back(thread);
|
|
|
|
log((CLOG_DEBUG1 "started thread %p", thread));
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
CServer::stopThreads(double timeout)
|
|
|
|
{
|
|
|
|
log((CLOG_DEBUG1 "stopping threads"));
|
|
|
|
|
|
|
|
// swap thread list so nobody can mess with it
|
|
|
|
CThreadList threads;
|
|
|
|
{
|
|
|
|
CLock lock(&m_mutex);
|
|
|
|
threads.swap(m_threads);
|
|
|
|
}
|
|
|
|
|
|
|
|
// cancel every thread
|
|
|
|
for (CThreadList::iterator index = threads.begin();
|
|
|
|
index != threads.end(); ++index) {
|
|
|
|
CThread* thread = *index;
|
|
|
|
thread->cancel();
|
|
|
|
}
|
|
|
|
|
|
|
|
// now wait for the threads
|
|
|
|
CStopwatch timer(true);
|
|
|
|
while (threads.size() > 0 && (timeout < 0.0 || timer.getTime() < timeout)) {
|
|
|
|
doReapThreads(threads);
|
|
|
|
CThread::sleep(0.01);
|
|
|
|
}
|
|
|
|
|
|
|
|
// delete remaining threads
|
|
|
|
for (CThreadList::iterator index = threads.begin();
|
|
|
|
index != threads.end(); ++index) {
|
|
|
|
CThread* thread = *index;
|
|
|
|
log((CLOG_DEBUG1 "reaped running thread %p", thread));
|
|
|
|
delete thread;
|
|
|
|
}
|
|
|
|
|
|
|
|
log((CLOG_DEBUG1 "stopped threads"));
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
CServer::reapThreads()
|
|
|
|
{
|
|
|
|
CLock lock(&m_mutex);
|
|
|
|
doReapThreads(m_threads);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
CServer::doReapThreads(CThreadList& threads)
|
|
|
|
{
|
|
|
|
for (CThreadList::iterator index = threads.begin();
|
|
|
|
index != threads.end(); ) {
|
|
|
|
CThread* thread = *index;
|
|
|
|
if (thread->wait(0.0)) {
|
|
|
|
// thread terminated
|
|
|
|
index = threads.erase(index);
|
|
|
|
log((CLOG_DEBUG1 "reaped thread %p", thread));
|
|
|
|
delete thread;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// thread is running
|
|
|
|
++index;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-10-08 19:24:46 +00:00
|
|
|
#include "CTCPListenSocket.h"
|
2002-06-10 22:06:45 +00:00
|
|
|
void
|
|
|
|
CServer::acceptClients(void*)
|
2001-10-06 14:13:28 +00:00
|
|
|
{
|
2002-04-27 18:49:03 +00:00
|
|
|
log((CLOG_DEBUG1 "starting to wait for clients"));
|
2001-10-14 14:37:41 +00:00
|
|
|
|
2001-10-06 14:13:28 +00:00
|
|
|
std::auto_ptr<IListenSocket> listen;
|
|
|
|
try {
|
|
|
|
// create socket listener
|
2001-11-19 00:33:36 +00:00
|
|
|
// listen = std::auto_ptr<IListenSocket>(m_socketFactory->createListen());
|
|
|
|
assign(listen, new CTCPListenSocket, IListenSocket); // FIXME
|
2001-10-06 14:13:28 +00:00
|
|
|
|
|
|
|
// bind to the desired port. keep retrying if we can't bind
|
|
|
|
// the address immediately.
|
|
|
|
CStopwatch timer;
|
|
|
|
for (;;) {
|
|
|
|
try {
|
2002-04-27 18:49:03 +00:00
|
|
|
log((CLOG_DEBUG1 "binding listen socket"));
|
2002-06-09 16:53:25 +00:00
|
|
|
listen->bind(m_config.getSynergyAddress());
|
2001-10-06 14:13:28 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
catch (XSocketAddressInUse&) {
|
|
|
|
// give up if we've waited too long
|
|
|
|
if (timer.getTime() >= m_bindTimeout) {
|
2002-04-27 18:49:03 +00:00
|
|
|
log((CLOG_DEBUG1 "waited too long to bind, giving up"));
|
2001-10-06 14:13:28 +00:00
|
|
|
throw;
|
|
|
|
}
|
|
|
|
|
|
|
|
// wait a bit before retrying
|
2002-04-27 18:49:03 +00:00
|
|
|
log((CLOG_DEBUG1 "bind failed; waiting to retry"));
|
2001-10-06 14:13:28 +00:00
|
|
|
CThread::sleep(5.0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// accept connections and begin processing them
|
2002-04-27 18:49:03 +00:00
|
|
|
log((CLOG_DEBUG1 "waiting for client connections"));
|
2001-10-06 14:13:28 +00:00
|
|
|
for (;;) {
|
|
|
|
// accept connection
|
|
|
|
CThread::testCancel();
|
2002-06-17 12:02:26 +00:00
|
|
|
IDataSocket* socket = listen->accept();
|
2001-10-14 14:37:41 +00:00
|
|
|
log((CLOG_NOTE "accepted client connection"));
|
2001-10-06 14:13:28 +00:00
|
|
|
CThread::testCancel();
|
|
|
|
|
|
|
|
// start handshake thread
|
2002-06-21 15:18:01 +00:00
|
|
|
startThread(new TMethodJob<CServer>(
|
2001-10-06 14:13:28 +00:00
|
|
|
this, &CServer::handshakeClient, socket));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (XBase& e) {
|
2001-10-14 14:37:41 +00:00
|
|
|
log((CLOG_ERR "cannot listen for clients: %s", e.what()));
|
2001-10-06 14:13:28 +00:00
|
|
|
quit();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-06-10 22:06:45 +00:00
|
|
|
void
|
2002-06-17 13:31:21 +00:00
|
|
|
CServer::handshakeClient(void* vsocket)
|
2001-10-06 14:13:28 +00:00
|
|
|
{
|
2002-04-27 18:49:03 +00:00
|
|
|
log((CLOG_DEBUG1 "negotiating with new client"));
|
2001-10-14 14:37:41 +00:00
|
|
|
|
2001-10-06 14:13:28 +00:00
|
|
|
// get the socket pointer from the argument
|
|
|
|
assert(vsocket != NULL);
|
2002-06-17 12:02:26 +00:00
|
|
|
std::auto_ptr<IDataSocket> socket(reinterpret_cast<IDataSocket*>(vsocket));
|
2001-10-06 14:13:28 +00:00
|
|
|
|
|
|
|
CString name("<unknown>");
|
|
|
|
try {
|
|
|
|
// get the input and output streams
|
|
|
|
IInputStream* srcInput = socket->getInputStream();
|
|
|
|
IOutputStream* srcOutput = socket->getOutputStream();
|
|
|
|
std::auto_ptr<IInputStream> input;
|
|
|
|
std::auto_ptr<IOutputStream> output;
|
|
|
|
|
|
|
|
// attach the encryption layer
|
2001-10-21 00:21:02 +00:00
|
|
|
bool own = false;
|
2001-10-06 14:13:28 +00:00
|
|
|
if (m_securityFactory != NULL) {
|
|
|
|
/* FIXME -- implement ISecurityFactory
|
2001-10-21 00:21:02 +00:00
|
|
|
input.reset(m_securityFactory->createInputFilter(srcInput, own));
|
|
|
|
output.reset(m_securityFactory->createOutputFilter(srcOutput, own));
|
2001-10-06 14:13:28 +00:00
|
|
|
srcInput = input.get();
|
|
|
|
srcOutput = output.get();
|
2001-10-21 00:21:02 +00:00
|
|
|
own = true;
|
2001-10-06 14:13:28 +00:00
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
|
|
// attach the packetizing filters
|
2001-11-19 00:33:36 +00:00
|
|
|
assign(input, new CInputPacketStream(srcInput, own), IInputStream);
|
|
|
|
assign(output, new COutputPacketStream(srcOutput, own), IOutputStream);
|
2001-10-06 14:13:28 +00:00
|
|
|
|
2002-06-21 15:18:01 +00:00
|
|
|
bool connected = false;
|
2001-10-06 14:13:28 +00:00
|
|
|
std::auto_ptr<IServerProtocol> protocol;
|
2002-05-23 14:56:03 +00:00
|
|
|
try {
|
|
|
|
{
|
|
|
|
// give the client a limited time to complete the handshake
|
|
|
|
CTimerThread timer(30.0);
|
2001-10-06 14:13:28 +00:00
|
|
|
|
2002-05-23 14:56:03 +00:00
|
|
|
// limit the maximum length of the hello
|
|
|
|
static const UInt32 maxHelloLen = 1024;
|
2001-10-06 14:13:28 +00:00
|
|
|
|
2002-05-23 14:56:03 +00:00
|
|
|
// say hello
|
|
|
|
log((CLOG_DEBUG1 "saying hello"));
|
|
|
|
CProtocolUtil::writef(output.get(), "Synergy%2i%2i",
|
2002-06-04 11:06:26 +00:00
|
|
|
kProtocolMajorVersion,
|
|
|
|
kProtocolMinorVersion);
|
2002-05-23 14:56:03 +00:00
|
|
|
output->flush();
|
2001-10-06 14:13:28 +00:00
|
|
|
|
2002-05-23 14:56:03 +00:00
|
|
|
// wait for the reply
|
|
|
|
log((CLOG_DEBUG1 "waiting for hello reply"));
|
|
|
|
UInt32 n = input->getSize();
|
|
|
|
if (n > maxHelloLen) {
|
|
|
|
throw XBadClient();
|
|
|
|
}
|
2001-10-06 14:13:28 +00:00
|
|
|
|
2002-05-23 14:56:03 +00:00
|
|
|
// get and parse the reply to hello
|
|
|
|
SInt16 major, minor;
|
|
|
|
try {
|
|
|
|
log((CLOG_DEBUG1 "parsing hello reply"));
|
|
|
|
CProtocolUtil::readf(input.get(), "Synergy%2i%2i%s",
|
2001-10-06 14:13:28 +00:00
|
|
|
&major, &minor, &name);
|
2002-05-23 14:56:03 +00:00
|
|
|
}
|
|
|
|
catch (XIO&) {
|
|
|
|
throw XBadClient();
|
|
|
|
}
|
2001-10-06 14:13:28 +00:00
|
|
|
|
2002-06-09 17:21:33 +00:00
|
|
|
// convert name to canonical form (if any)
|
|
|
|
if (m_config.isScreen(name)) {
|
|
|
|
name = m_config.getCanonicalName(name);
|
|
|
|
}
|
|
|
|
|
2002-05-23 14:56:03 +00:00
|
|
|
// create a protocol interpreter for the version
|
|
|
|
log((CLOG_DEBUG1 "creating interpreter for client \"%s\" version %d.%d", name.c_str(), major, minor));
|
|
|
|
assign(protocol, CServerProtocol::create(major, minor,
|
2001-11-19 00:33:36 +00:00
|
|
|
this, name, input.get(), output.get()),
|
|
|
|
IServerProtocol);
|
2001-10-06 14:13:28 +00:00
|
|
|
|
2002-05-23 14:56:03 +00:00
|
|
|
// client is now pending
|
2002-06-21 15:18:01 +00:00
|
|
|
addConnection(name, protocol.get());
|
|
|
|
connected = true;
|
2001-10-06 14:13:28 +00:00
|
|
|
|
2002-05-23 14:56:03 +00:00
|
|
|
// ask and wait for the client's info
|
|
|
|
log((CLOG_DEBUG1 "waiting for info for client \"%s\"", name.c_str()));
|
|
|
|
protocol->queryInfo();
|
|
|
|
|
|
|
|
// now connected; client no longer subject to timeout.
|
|
|
|
}
|
|
|
|
|
2002-06-23 15:43:40 +00:00
|
|
|
// activate screen saver on new client if active on the
|
|
|
|
// primary screen
|
|
|
|
if (m_primary->isScreenSaverActive()) {
|
|
|
|
protocol->sendScreenSaver(true);
|
|
|
|
}
|
|
|
|
|
2002-05-23 14:56:03 +00:00
|
|
|
// handle messages from client. returns when the client
|
|
|
|
// disconnects.
|
|
|
|
log((CLOG_NOTE "client \"%s\" has connected", name.c_str()));
|
|
|
|
protocol->run();
|
|
|
|
}
|
|
|
|
catch (XDuplicateClient& e) {
|
|
|
|
// client has duplicate name
|
2002-05-23 15:00:13 +00:00
|
|
|
log((CLOG_WARN "a client with name \"%s\" is already connected", e.getName().c_str()));
|
2002-05-23 14:56:03 +00:00
|
|
|
CProtocolUtil::writef(output.get(), kMsgEBusy);
|
|
|
|
}
|
2002-05-31 18:18:29 +00:00
|
|
|
catch (XUnknownClient& e) {
|
|
|
|
// client has unknown name
|
|
|
|
log((CLOG_WARN "a client with name \"%s\" is not in the map", e.getName().c_str()));
|
|
|
|
CProtocolUtil::writef(output.get(), kMsgEUnknown);
|
|
|
|
}
|
2002-05-23 14:56:03 +00:00
|
|
|
catch (XIncompatibleClient& e) {
|
|
|
|
// client is incompatible
|
|
|
|
// FIXME -- could print network address if socket had suitable method
|
|
|
|
log((CLOG_WARN "client \"%s\" has incompatible version %d.%d)", name.c_str(), e.getMajor(), e.getMinor()));
|
|
|
|
CProtocolUtil::writef(output.get(), kMsgEIncompatible,
|
2002-06-04 11:06:26 +00:00
|
|
|
kProtocolMajorVersion, kProtocolMinorVersion);
|
2002-05-23 14:56:03 +00:00
|
|
|
}
|
|
|
|
catch (XBadClient&) {
|
|
|
|
// client not behaving
|
|
|
|
// FIXME -- could print network address if socket had suitable method
|
|
|
|
log((CLOG_WARN "protocol error from client \"%s\"", name.c_str()));
|
|
|
|
CProtocolUtil::writef(output.get(), kMsgEBad);
|
2001-10-06 14:13:28 +00:00
|
|
|
}
|
2002-06-21 15:18:01 +00:00
|
|
|
catch (...) {
|
|
|
|
if (connected) {
|
|
|
|
removeConnection(name);
|
|
|
|
}
|
|
|
|
throw;
|
|
|
|
}
|
2001-10-06 14:13:28 +00:00
|
|
|
|
2002-05-23 14:56:03 +00:00
|
|
|
// flush any pending output
|
|
|
|
output.get()->flush();
|
2002-06-21 15:18:01 +00:00
|
|
|
if (connected) {
|
|
|
|
removeConnection(name);
|
|
|
|
}
|
2001-10-06 14:13:28 +00:00
|
|
|
}
|
|
|
|
catch (XBase& e) {
|
|
|
|
// misc error
|
2001-10-14 14:37:41 +00:00
|
|
|
log((CLOG_WARN "error communicating with client \"%s\": %s", name.c_str(), e.what()));
|
2001-10-06 14:13:28 +00:00
|
|
|
// FIXME -- could print network address if socket had suitable method
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-06-10 22:06:45 +00:00
|
|
|
void
|
|
|
|
CServer::acceptHTTPClients(void*)
|
2002-05-30 16:13:16 +00:00
|
|
|
{
|
|
|
|
log((CLOG_DEBUG1 "starting to wait for HTTP clients"));
|
|
|
|
|
|
|
|
std::auto_ptr<IListenSocket> listen;
|
|
|
|
try {
|
|
|
|
// create socket listener
|
|
|
|
// listen = std::auto_ptr<IListenSocket>(m_socketFactory->createListen());
|
|
|
|
assign(listen, new CTCPListenSocket, IListenSocket); // FIXME
|
|
|
|
|
|
|
|
// bind to the desired port. keep retrying if we can't bind
|
|
|
|
// the address immediately.
|
|
|
|
CStopwatch timer;
|
|
|
|
for (;;) {
|
|
|
|
try {
|
2002-06-09 16:53:25 +00:00
|
|
|
log((CLOG_DEBUG1 "binding HTTP listen socket"));
|
|
|
|
listen->bind(m_config.getHTTPAddress());
|
2002-05-30 16:13:16 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
catch (XSocketAddressInUse&) {
|
|
|
|
// give up if we've waited too long
|
|
|
|
if (timer.getTime() >= m_bindTimeout) {
|
|
|
|
log((CLOG_DEBUG1 "waited too long to bind HTTP, giving up"));
|
|
|
|
throw;
|
|
|
|
}
|
|
|
|
|
|
|
|
// wait a bit before retrying
|
|
|
|
log((CLOG_DEBUG1 "bind HTTP failed; waiting to retry"));
|
|
|
|
CThread::sleep(5.0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// accept connections and begin processing them
|
|
|
|
log((CLOG_DEBUG1 "waiting for HTTP connections"));
|
|
|
|
for (;;) {
|
2002-06-02 11:49:46 +00:00
|
|
|
// limit the number of HTTP requests being handled at once
|
|
|
|
{
|
|
|
|
CLock lock(&m_httpAvailable);
|
|
|
|
while (m_httpAvailable == 0) {
|
|
|
|
m_httpAvailable.wait();
|
|
|
|
}
|
|
|
|
assert(m_httpAvailable > 0);
|
|
|
|
m_httpAvailable = m_httpAvailable - 1;
|
|
|
|
}
|
|
|
|
|
2002-05-30 16:13:16 +00:00
|
|
|
// accept connection
|
|
|
|
CThread::testCancel();
|
2002-06-17 12:02:26 +00:00
|
|
|
IDataSocket* socket = listen->accept();
|
2002-05-30 16:13:16 +00:00
|
|
|
log((CLOG_NOTE "accepted HTTP connection"));
|
|
|
|
CThread::testCancel();
|
|
|
|
|
|
|
|
// handle HTTP request
|
2002-06-21 15:18:01 +00:00
|
|
|
startThread(new TMethodJob<CServer>(
|
2002-05-30 16:13:16 +00:00
|
|
|
this, &CServer::processHTTPRequest, socket));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (XBase& e) {
|
|
|
|
log((CLOG_ERR "cannot listen for HTTP clients: %s", e.what()));
|
2002-06-02 11:49:46 +00:00
|
|
|
// FIXME -- quit?
|
2002-05-30 16:13:16 +00:00
|
|
|
quit();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-06-10 22:06:45 +00:00
|
|
|
void
|
2002-06-17 13:31:21 +00:00
|
|
|
CServer::processHTTPRequest(void* vsocket)
|
2002-05-30 16:13:16 +00:00
|
|
|
{
|
2002-06-17 12:02:26 +00:00
|
|
|
IDataSocket* socket = reinterpret_cast<IDataSocket*>(vsocket);
|
2002-05-30 16:13:16 +00:00
|
|
|
try {
|
|
|
|
// process the request and force delivery
|
|
|
|
m_httpServer->processRequest(socket);
|
|
|
|
socket->getOutputStream()->flush();
|
|
|
|
|
|
|
|
// wait a moment to give the client a chance to hangup first
|
|
|
|
CThread::sleep(3.0);
|
|
|
|
|
|
|
|
// clean up
|
|
|
|
socket->close();
|
|
|
|
delete socket;
|
2002-06-02 11:49:46 +00:00
|
|
|
|
|
|
|
// increment available HTTP handlers
|
|
|
|
{
|
|
|
|
CLock lock(&m_httpAvailable);
|
|
|
|
m_httpAvailable = m_httpAvailable + 1;
|
|
|
|
m_httpAvailable.signal();
|
|
|
|
}
|
2002-05-30 16:13:16 +00:00
|
|
|
}
|
|
|
|
catch (...) {
|
|
|
|
delete socket;
|
2002-06-02 11:49:46 +00:00
|
|
|
{
|
|
|
|
CLock lock(&m_httpAvailable);
|
|
|
|
m_httpAvailable = m_httpAvailable + 1;
|
|
|
|
m_httpAvailable.signal();
|
|
|
|
}
|
2002-05-30 16:13:16 +00:00
|
|
|
throw;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-06-10 22:06:45 +00:00
|
|
|
void
|
2002-06-17 13:31:21 +00:00
|
|
|
CServer::clearGotClipboard(ClipboardID id)
|
2001-10-06 14:13:28 +00:00
|
|
|
{
|
2002-04-29 13:31:44 +00:00
|
|
|
for (CScreenList::const_iterator index = m_screens.begin();
|
|
|
|
index != m_screens.end(); ++index) {
|
|
|
|
index->second->m_gotClipboard[id] = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-06-10 22:06:45 +00:00
|
|
|
void
|
2002-06-17 13:31:21 +00:00
|
|
|
CServer::sendClipboard(ClipboardID id)
|
2002-04-29 13:31:44 +00:00
|
|
|
{
|
|
|
|
// do nothing if clipboard was already sent
|
|
|
|
if (!m_active->m_gotClipboard[id]) {
|
|
|
|
CClipboardInfo& clipboard = m_clipboards[id];
|
|
|
|
if (clipboard.m_clipboardReady) {
|
|
|
|
// send it
|
|
|
|
if (m_active->m_protocol == NULL) {
|
|
|
|
m_primary->setClipboard(id, &clipboard.m_clipboard);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
m_active->m_protocol->sendClipboard(id,
|
|
|
|
clipboard.m_clipboardData);
|
|
|
|
}
|
|
|
|
|
|
|
|
// clipboard has been sent
|
|
|
|
m_active->m_gotClipboard[id] = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-06-10 22:06:45 +00:00
|
|
|
void
|
2002-06-17 13:31:21 +00:00
|
|
|
CServer::updatePrimaryClipboard(ClipboardID id)
|
2002-04-29 13:31:44 +00:00
|
|
|
{
|
|
|
|
CClipboardInfo& clipboard = m_clipboards[id];
|
|
|
|
|
|
|
|
// if leaving primary and the primary owns the clipboard
|
|
|
|
// then update it.
|
|
|
|
if (clipboard.m_clipboardOwner == m_primaryInfo->m_name) {
|
|
|
|
assert(clipboard.m_clipboardReady == true);
|
|
|
|
|
|
|
|
// save clipboard time
|
|
|
|
IClipboard::Time time = clipboard.m_clipboard.getTime();
|
|
|
|
|
|
|
|
// update
|
|
|
|
m_primary->getClipboard(id, &clipboard.m_clipboard);
|
|
|
|
|
|
|
|
// if clipboard changed then other screens have an
|
|
|
|
// out-of-date clipboard.
|
|
|
|
if (time != clipboard.m_clipboard.getTime()) {
|
2002-05-01 16:17:57 +00:00
|
|
|
log((CLOG_DEBUG "clipboard %d time changed (%08x to %08x)", id, time, clipboard.m_clipboard.getTime()));
|
|
|
|
|
|
|
|
// marshall data
|
|
|
|
CString newData = clipboard.m_clipboard.marshall();
|
|
|
|
|
|
|
|
// compare old and new data. if identical then the clipboard
|
|
|
|
// hasn't really changed.
|
|
|
|
if (newData != clipboard.m_clipboardData) {
|
|
|
|
log((CLOG_DEBUG "clipboard %d changed", id));
|
|
|
|
clipboard.m_clipboardData = newData;
|
|
|
|
clearGotClipboard(id);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
log((CLOG_DEBUG "clipboard %d unchanged", id));
|
|
|
|
}
|
2002-04-29 13:31:44 +00:00
|
|
|
m_primaryInfo->m_gotClipboard[id] = true;
|
|
|
|
}
|
|
|
|
}
|
2001-10-06 14:13:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME -- use factory to create screen
|
2002-06-19 11:23:49 +00:00
|
|
|
#if WINDOWS_LIKE
|
2001-11-19 00:33:36 +00:00
|
|
|
#include "CMSWindowsPrimaryScreen.h"
|
2002-06-19 11:23:49 +00:00
|
|
|
#elif UNIX_LIKE
|
2001-10-06 14:13:28 +00:00
|
|
|
#include "CXWindowsPrimaryScreen.h"
|
2001-11-19 00:33:36 +00:00
|
|
|
#endif
|
2002-06-10 22:06:45 +00:00
|
|
|
void
|
|
|
|
CServer::openPrimaryScreen()
|
2001-10-06 14:13:28 +00:00
|
|
|
{
|
|
|
|
assert(m_primary == NULL);
|
|
|
|
|
2002-04-29 13:31:44 +00:00
|
|
|
// reset sequence number
|
|
|
|
m_seqNum = 0;
|
|
|
|
|
2002-06-09 17:59:32 +00:00
|
|
|
CString primary = m_config.getCanonicalName(m_name);
|
|
|
|
if (primary.empty()) {
|
|
|
|
throw XUnknownClient(m_name);
|
|
|
|
}
|
2002-06-03 13:45:30 +00:00
|
|
|
try {
|
|
|
|
// add connection
|
2002-06-09 17:21:33 +00:00
|
|
|
m_active = addConnection(primary, NULL);
|
|
|
|
m_primaryInfo = m_active;
|
2002-05-24 17:54:28 +00:00
|
|
|
|
2002-06-03 13:45:30 +00:00
|
|
|
// open screen
|
|
|
|
log((CLOG_DEBUG1 "creating primary screen"));
|
2002-06-19 11:23:49 +00:00
|
|
|
#if WINDOWS_LIKE
|
2002-06-03 13:45:30 +00:00
|
|
|
m_primary = new CMSWindowsPrimaryScreen;
|
2002-06-19 11:23:49 +00:00
|
|
|
#elif UNIX_LIKE
|
2002-06-03 13:45:30 +00:00
|
|
|
m_primary = new CXWindowsPrimaryScreen;
|
2001-11-19 00:33:36 +00:00
|
|
|
#endif
|
2002-06-03 13:45:30 +00:00
|
|
|
log((CLOG_DEBUG1 "opening primary screen"));
|
|
|
|
m_primary->open(this);
|
|
|
|
}
|
|
|
|
catch (...) {
|
2002-06-03 18:53:18 +00:00
|
|
|
if (m_primary != NULL) {
|
2002-06-09 17:21:33 +00:00
|
|
|
removeConnection(primary);
|
2002-06-03 18:53:18 +00:00
|
|
|
delete m_primary;
|
|
|
|
}
|
2002-06-03 13:45:30 +00:00
|
|
|
m_primary = NULL;
|
|
|
|
m_primaryInfo = NULL;
|
|
|
|
m_active = NULL;
|
|
|
|
throw;
|
|
|
|
}
|
2001-10-06 14:13:28 +00:00
|
|
|
|
2001-11-25 18:32:41 +00:00
|
|
|
// set the clipboard owner to the primary screen and then get the
|
|
|
|
// current clipboard data.
|
2002-04-27 14:19:53 +00:00
|
|
|
for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
|
2002-04-29 13:31:44 +00:00
|
|
|
CClipboardInfo& clipboard = m_clipboards[id];
|
2002-04-27 14:19:53 +00:00
|
|
|
m_primary->getClipboard(id, &clipboard.m_clipboard);
|
|
|
|
clipboard.m_clipboardData = clipboard.m_clipboard.marshall();
|
|
|
|
clipboard.m_clipboardReady = true;
|
|
|
|
clipboard.m_clipboardOwner = m_active->m_name;
|
|
|
|
}
|
2001-10-06 14:13:28 +00:00
|
|
|
}
|
|
|
|
|
2002-06-10 22:06:45 +00:00
|
|
|
void
|
|
|
|
CServer::closePrimaryScreen()
|
2001-10-06 14:13:28 +00:00
|
|
|
{
|
|
|
|
assert(m_primary != NULL);
|
|
|
|
|
|
|
|
// remove connection
|
2002-06-09 17:59:32 +00:00
|
|
|
CString primary = m_config.getCanonicalName(m_name);
|
2002-06-09 17:21:33 +00:00
|
|
|
removeConnection(primary);
|
2001-10-06 14:13:28 +00:00
|
|
|
|
|
|
|
// close the primary screen
|
|
|
|
try {
|
2002-04-27 18:49:03 +00:00
|
|
|
log((CLOG_DEBUG1 "closing primary screen"));
|
2001-10-06 14:13:28 +00:00
|
|
|
m_primary->close();
|
|
|
|
}
|
|
|
|
catch (...) {
|
|
|
|
// ignore
|
|
|
|
}
|
|
|
|
|
|
|
|
// clean up
|
2002-04-27 18:49:03 +00:00
|
|
|
log((CLOG_DEBUG1 "destroying primary screen"));
|
2001-10-06 14:13:28 +00:00
|
|
|
delete m_primary;
|
|
|
|
m_primary = NULL;
|
|
|
|
}
|
|
|
|
|
2002-06-10 22:06:45 +00:00
|
|
|
CServer::CScreenInfo*
|
2002-06-17 13:31:21 +00:00
|
|
|
CServer::addConnection(const CString& name, IServerProtocol* protocol)
|
2001-10-06 14:13:28 +00:00
|
|
|
{
|
2001-10-14 14:37:41 +00:00
|
|
|
log((CLOG_DEBUG "adding connection \"%s\"", name.c_str()));
|
2002-05-23 14:56:03 +00:00
|
|
|
|
2001-10-06 14:13:28 +00:00
|
|
|
CLock lock(&m_mutex);
|
2002-05-23 14:56:03 +00:00
|
|
|
|
2002-05-31 18:18:29 +00:00
|
|
|
// name must be in our configuration
|
|
|
|
if (!m_config.isScreen(name)) {
|
|
|
|
throw XUnknownClient(name);
|
|
|
|
}
|
2002-06-08 23:24:40 +00:00
|
|
|
|
|
|
|
// can only have one screen with a given name at any given time
|
2002-06-09 17:21:33 +00:00
|
|
|
if (m_screens.count(name) != 0) {
|
2002-06-08 23:24:40 +00:00
|
|
|
throw XDuplicateClient(name);
|
|
|
|
}
|
2002-05-31 18:09:43 +00:00
|
|
|
|
2002-05-23 14:56:03 +00:00
|
|
|
// save screen info
|
2002-06-09 17:21:33 +00:00
|
|
|
CScreenInfo* newScreen = new CScreenInfo(name, protocol);
|
|
|
|
m_screens.insert(std::make_pair(name, newScreen));
|
|
|
|
log((CLOG_DEBUG "added connection \"%s\"", name.c_str()));
|
2002-05-23 14:56:03 +00:00
|
|
|
|
2001-10-06 14:13:28 +00:00
|
|
|
return newScreen;
|
|
|
|
}
|
|
|
|
|
2002-06-10 22:06:45 +00:00
|
|
|
void
|
2002-06-17 13:31:21 +00:00
|
|
|
CServer::removeConnection(const CString& name)
|
2001-10-06 14:13:28 +00:00
|
|
|
{
|
2001-10-14 14:37:41 +00:00
|
|
|
log((CLOG_DEBUG "removing connection \"%s\"", name.c_str()));
|
2001-10-06 14:13:28 +00:00
|
|
|
CLock lock(&m_mutex);
|
2001-10-24 23:29:29 +00:00
|
|
|
|
|
|
|
// find screen info
|
2002-06-09 17:21:33 +00:00
|
|
|
CScreenList::iterator index = m_screens.find(name);
|
2001-10-14 16:58:01 +00:00
|
|
|
assert(index != m_screens.end());
|
2001-10-24 23:29:29 +00:00
|
|
|
|
|
|
|
// if this is active screen then we have to jump off of it
|
2002-06-23 23:24:22 +00:00
|
|
|
CScreenInfo* active = (m_activeSaver != NULL) ? m_activeSaver : m_active;
|
|
|
|
if (active == index->second && active != m_primaryInfo) {
|
2001-10-24 23:29:29 +00:00
|
|
|
// record new position (center of primary screen)
|
2002-06-22 19:20:21 +00:00
|
|
|
// FIXME -- should have separate "center" pixel reported by screen
|
2002-06-19 17:03:29 +00:00
|
|
|
m_x = m_primaryInfo->m_x + (m_primaryInfo->m_w >> 1);
|
|
|
|
m_y = m_primaryInfo->m_y + (m_primaryInfo->m_h >> 1);
|
2001-10-24 23:29:29 +00:00
|
|
|
|
|
|
|
// don't notify active screen since it probably already disconnected
|
2002-06-23 23:24:22 +00:00
|
|
|
log((CLOG_INFO "jump from \"%s\" to \"%s\" at %d,%d", active->m_name.c_str(), m_primaryInfo->m_name.c_str(), m_x, m_y));
|
2001-10-24 23:29:29 +00:00
|
|
|
|
|
|
|
// cut over
|
|
|
|
m_active = m_primaryInfo;
|
|
|
|
|
2002-06-23 23:24:22 +00:00
|
|
|
// enter new screen (unless we already have because of the
|
|
|
|
// screen saver)
|
|
|
|
if (m_activeSaver == NULL) {
|
|
|
|
m_primary->enter(m_x, m_y, false);
|
|
|
|
}
|
2001-10-24 23:29:29 +00:00
|
|
|
}
|
|
|
|
|
2002-06-22 19:20:21 +00:00
|
|
|
// if this screen had the cursor when the screen saver activated
|
|
|
|
// then we can't switch back to it when the screen saver
|
|
|
|
// deactivates.
|
|
|
|
if (m_activeSaver == index->second) {
|
|
|
|
m_activeSaver = NULL;
|
|
|
|
}
|
|
|
|
|
2001-10-24 23:29:29 +00:00
|
|
|
// done with screen info
|
2001-10-06 14:13:28 +00:00
|
|
|
delete index->second;
|
|
|
|
m_screens.erase(index);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// CServer::CScreenInfo
|
|
|
|
//
|
|
|
|
|
2002-06-17 13:31:21 +00:00
|
|
|
CServer::CScreenInfo::CScreenInfo(const CString& name,
|
|
|
|
IServerProtocol* protocol) :
|
2002-06-10 22:06:45 +00:00
|
|
|
m_thread(CThread::getCurrentThread()),
|
|
|
|
m_name(name),
|
|
|
|
m_protocol(protocol),
|
|
|
|
m_ready(false),
|
2002-06-19 17:03:29 +00:00
|
|
|
m_x(0),
|
|
|
|
m_y(0),
|
|
|
|
m_w(0),
|
|
|
|
m_h(0),
|
2002-06-10 22:06:45 +00:00
|
|
|
m_zoneSize(0)
|
2001-10-06 14:13:28 +00:00
|
|
|
{
|
2002-04-27 14:19:53 +00:00
|
|
|
for (ClipboardID id = 0; id < kClipboardEnd; ++id)
|
|
|
|
m_gotClipboard[id] = false;
|
2001-10-06 14:13:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CServer::CScreenInfo::~CScreenInfo()
|
|
|
|
{
|
|
|
|
// do nothing
|
|
|
|
}
|
2002-04-27 14:19:53 +00:00
|
|
|
|
|
|
|
|
|
|
|
//
|
2002-04-29 13:31:44 +00:00
|
|
|
// CServer::CClipboardInfo
|
2002-04-27 14:19:53 +00:00
|
|
|
//
|
|
|
|
|
2002-04-29 13:31:44 +00:00
|
|
|
CServer::CClipboardInfo::CClipboardInfo() :
|
2002-06-10 22:06:45 +00:00
|
|
|
m_clipboard(),
|
|
|
|
m_clipboardData(),
|
|
|
|
m_clipboardOwner(),
|
|
|
|
m_clipboardSeqNum(0),
|
|
|
|
m_clipboardReady(false)
|
2002-04-27 14:19:53 +00:00
|
|
|
{
|
|
|
|
// do nothing
|
|
|
|
}
|