diff --git a/server/CServer.cpp b/server/CServer.cpp index 0a0a3845..e7cf497f 100644 --- a/server/CServer.cpp +++ b/server/CServer.cpp @@ -110,13 +110,49 @@ void CServer::quit() m_primary->stop(); } -void CServer::setConfig(const CConfig& config) +bool CServer::setConfig(const CConfig& config) { - CLock lock(&m_mutex); - // FIXME -- must disconnect screens no longer listed - // (that may include warping back to server's screen) - // FIXME -- server screen must be in new map or map is rejected - m_config = config; + typedef std::vector 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 + // dropped from the configuration. don't add the primary + // screen. + for (CScreenList::const_iterator index = m_screens.begin(); + index != m_screens.end(); ++index) { + if (!config.isScreen(index->first) && + index->second != m_primaryInfo) { + threads.push_back(index->second->m_thread); + } + } + + // cancel the old secondary screen threads + for (CThreads::iterator index = threads.begin(); + index != threads.end(); ++index) { + index->cancel(); + } + + // cut over + m_config = config; + } + + // 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(); + } + + return true; } CString CServer::getPrimaryScreenName() const @@ -137,14 +173,22 @@ UInt32 CServer::getActivePrimarySides() const { UInt32 sides = 0; CLock lock(&m_mutex); - if (!m_config.getNeighbor("primary", CConfig::kLeft).empty()) + if (!m_config.getNeighbor(getPrimaryScreenName(), + CConfig::kLeft).empty()) { sides |= CConfig::kLeftMask; - if (!m_config.getNeighbor("primary", CConfig::kRight).empty()) + } + if (!m_config.getNeighbor(getPrimaryScreenName(), + CConfig::kRight).empty()) { sides |= CConfig::kRightMask; - if (!m_config.getNeighbor("primary", CConfig::kTop).empty()) + } + if (!m_config.getNeighbor(getPrimaryScreenName(), + CConfig::kTop).empty()) { sides |= CConfig::kTopMask; - if (!m_config.getNeighbor("primary", CConfig::kBottom).empty()) + } + if (!m_config.getNeighbor(getPrimaryScreenName(), + CConfig::kBottom).empty()) { sides |= CConfig::kBottomMask; + } return sides; } @@ -1234,6 +1278,8 @@ CServer::CScreenInfo* CServer::addConnection( throw XDuplicateClient(name); } + // FIXME -- throw if the name is not in our map + // save screen info CScreenInfo* newScreen = new CScreenInfo(name, protocol); m_screens.insert(std::make_pair(name, newScreen)); @@ -1314,6 +1360,7 @@ CServer::CConnectionNote::~CConnectionNote() CServer::CScreenInfo::CScreenInfo(const CString& name, IServerProtocol* protocol) : + m_thread(CThread::getCurrentThread()), m_name(name), m_protocol(protocol), m_width(0), m_height(0), diff --git a/server/CServer.h b/server/CServer.h index 4a47d821..b0844704 100644 --- a/server/CServer.h +++ b/server/CServer.h @@ -8,6 +8,7 @@ #include "CClipboard.h" #include "CMutex.h" #include "CString.h" +#include "CThread.h" #include "XBase.h" #include #include @@ -32,8 +33,9 @@ public: // tell server to exit gracefully void quit(); - // update screen map - void setConfig(const CConfig&); + // update screen map. returns true iff the new configuration was + // accepted. + bool setConfig(const CConfig&); // handle events on server's screen. onMouseMovePrimary() returns // true iff the mouse enters a jump zone and jumps. @@ -105,6 +107,7 @@ private: ~CScreenInfo(); public: + CThread m_thread; CString m_name; IServerProtocol* m_protocol; SInt32 m_width, m_height; diff --git a/server/CServerProtocol1_0.cpp b/server/CServerProtocol1_0.cpp index 1d4240f0..8c58fd83 100644 --- a/server/CServerProtocol1_0.cpp +++ b/server/CServerProtocol1_0.cpp @@ -5,6 +5,7 @@ #include "ProtocolTypes.h" #include "IInputStream.h" #include "CLog.h" +#include "CThread.h" #include // @@ -27,9 +28,12 @@ void CServerProtocol1_0::run() { // handle messages until the client hangs up for (;;) { + CThread::testCancel(); + // wait for a message UInt8 code[4]; UInt32 n = getInputStream()->read(code, 4); + CThread::testCancel(); // verify we got an entire code if (n == 0) {