diff --git a/client/CClient.cpp b/client/CClient.cpp index ab221a7e..69e6026c 100644 --- a/client/CClient.cpp +++ b/client/CClient.cpp @@ -27,6 +27,7 @@ CClient::CClient(const CString& clientName) : m_screen(NULL), m_server(NULL), m_camp(false), + m_session(NULL), m_active(false), m_rejected(true) { @@ -64,6 +65,13 @@ CClient::wasRejected() const return m_rejected; } +void +CClient::onError() +{ + // close down session but don't wait too long + deleteSession(3.0); +} + void CClient::onInfoChanged(const CClientInfo& info) { @@ -144,28 +152,31 @@ CClient::run() log((CLOG_NOTE "starting client \"%s\"", m_name.c_str())); // start server interactions - thread = new CThread(new TMethodJob( + { + CLock lock(&m_mutex); + m_session = new CThread(new TMethodJob( this, &CClient::runSession)); + } // handle events m_screen->run(); // clean up - deleteSession(thread); + deleteSession(); log((CLOG_NOTE "stopping client \"%s\"", m_name.c_str())); } catch (XBase& e) { log((CLOG_ERR "client error: %s", e.what())); // clean up - deleteSession(thread); + deleteSession(); log((CLOG_NOTE "stopping client \"%s\"", m_name.c_str())); CLock lock(&m_mutex); m_rejected = false; } catch (XThread&) { // clean up - deleteSession(thread); + deleteSession(); log((CLOG_NOTE "stopping client \"%s\"", m_name.c_str())); throw; } @@ -173,7 +184,7 @@ CClient::run() log((CLOG_DEBUG "unknown client error")); // clean up - deleteSession(thread); + deleteSession(); log((CLOG_NOTE "stopping client \"%s\"", m_name.c_str())); throw; } @@ -424,11 +435,20 @@ CClient::runSession(void*) } void -CClient::deleteSession(CThread* thread) +CClient::deleteSession(double timeout) { + // get session thread object + CThread* thread; + { + CLock lock(&m_mutex); + thread = m_session; + m_session = NULL; + } + + // shut it down if (thread != NULL) { thread->cancel(); - thread->wait(); + thread->wait(timeout); delete thread; } } diff --git a/client/CClient.h b/client/CClient.h index c555d87c..2e8e2256 100644 --- a/client/CClient.h +++ b/client/CClient.h @@ -39,6 +39,7 @@ public: bool wasRejected() const; // IScreenReceiver overrides + virtual void onError(); virtual void onInfoChanged(const CClientInfo&); virtual bool onGrabClipboard(ClipboardID); virtual void onClipboardChanged(ClipboardID, const CString&); @@ -47,7 +48,6 @@ public: virtual bool open(); virtual void run(); virtual void close(); -// FIXME -- can we avoid passing everything here? virtual void enter(SInt32 xAbs, SInt32 yAbs, UInt32 seqNum, KeyModifierMask mask, bool forScreensaver); @@ -80,7 +80,7 @@ private: // handle server messaging void runSession(void*); - void deleteSession(CThread*); + void deleteSession(double timeout = -1.0); void runServer(); CServerProxy* handshakeServer(IDataSocket*); @@ -91,6 +91,7 @@ private: IScreenReceiver* m_server; CNetworkAddress m_serverAddress; bool m_camp; + CThread* m_session; bool m_active; bool m_rejected; bool m_ownClipboard[kClipboardEnd]; diff --git a/client/CMSWindowsSecondaryScreen.cpp b/client/CMSWindowsSecondaryScreen.cpp index 78b514f4..3c93ac0c 100644 --- a/client/CMSWindowsSecondaryScreen.cpp +++ b/client/CMSWindowsSecondaryScreen.cpp @@ -206,12 +206,6 @@ CMSWindowsSecondaryScreen::getScreen() const return m_screen; } -void -CMSWindowsSecondaryScreen::onError() -{ - // ignore -} - void CMSWindowsSecondaryScreen::onScreensaver(bool) { diff --git a/client/CMSWindowsSecondaryScreen.h b/client/CMSWindowsSecondaryScreen.h index e9b956c7..b98a4251 100644 --- a/client/CMSWindowsSecondaryScreen.h +++ b/client/CMSWindowsSecondaryScreen.h @@ -33,7 +33,6 @@ public: virtual IScreen* getScreen() const; // IMSWindowsScreenEventHandler overrides - virtual void onError(); virtual void onScreensaver(bool activated); virtual bool onPreDispatch(const CEvent* event); virtual bool onEvent(CEvent* event); diff --git a/client/CSecondaryScreen.cpp b/client/CSecondaryScreen.cpp index a19bc4e4..9452ffae 100644 --- a/client/CSecondaryScreen.cpp +++ b/client/CSecondaryScreen.cpp @@ -18,13 +18,6 @@ CSecondaryScreen::~CSecondaryScreen() // do nothing } -bool -CSecondaryScreen::isActive() const -{ - CLock lock(&m_mutex); - return m_active; -} - void CSecondaryScreen::run() { @@ -85,7 +78,10 @@ CSecondaryScreen::open() } // hide the cursor - m_active = true; + { + CLock lock(&m_mutex); + m_active = true; + } leave(); } @@ -175,6 +171,13 @@ CSecondaryScreen::screensaver(bool activate) getScreen()->screensaver(activate); } +bool +CSecondaryScreen::isActive() const +{ + CLock lock(&m_mutex); + return m_active; +} + void CSecondaryScreen::getClipboard(ClipboardID id, IClipboard* clipboard) const diff --git a/client/CServerProxy.cpp b/client/CServerProxy.cpp index 2aa59a4a..b8a9a3b3 100644 --- a/client/CServerProxy.cpp +++ b/client/CServerProxy.cpp @@ -221,6 +221,12 @@ CServerProxy::getOutputStream() const return m_output; } +void +CServerProxy::onError() +{ + // ignore +} + void CServerProxy::onInfoChanged(const CClientInfo& info) { diff --git a/client/CServerProxy.h b/client/CServerProxy.h index 0370a646..e7f48d19 100644 --- a/client/CServerProxy.h +++ b/client/CServerProxy.h @@ -34,6 +34,7 @@ public: IOutputStream* getOutputStream() const; // IScreenReceiver overrides + virtual void onError(); virtual void onInfoChanged(const CClientInfo&); virtual bool onGrabClipboard(ClipboardID); virtual void onClipboardChanged(ClipboardID, const CString& data); diff --git a/client/CXWindowsSecondaryScreen.cpp b/client/CXWindowsSecondaryScreen.cpp index d8e5ab66..b0187ccb 100644 --- a/client/CXWindowsSecondaryScreen.cpp +++ b/client/CXWindowsSecondaryScreen.cpp @@ -145,13 +145,6 @@ CXWindowsSecondaryScreen::getScreen() const return m_screen; } -void -CXWindowsSecondaryScreen::onError() -{ - // ignore - // FIXME -- forward this? to whom? -} - void CXWindowsSecondaryScreen::onScreensaver(bool) { @@ -273,16 +266,18 @@ CXWindowsSecondaryScreen::createWindow() void CXWindowsSecondaryScreen::destroyWindow() { - CDisplayLock display(m_screen); - if (display != NULL) { - // release keys that are still pressed - releaseKeys(display); + { + CDisplayLock display(m_screen); + if (display != NULL) { + // release keys that are still pressed + releaseKeys(display); - // no longer impervious to server grabs - XTestGrabControl(display, False); + // no longer impervious to server grabs + XTestGrabControl(display, False); - // update - XSync(display, False); + // update + XSync(display, False); + } } // destroy window diff --git a/client/CXWindowsSecondaryScreen.h b/client/CXWindowsSecondaryScreen.h index 6237996b..07ddb346 100644 --- a/client/CXWindowsSecondaryScreen.h +++ b/client/CXWindowsSecondaryScreen.h @@ -31,7 +31,6 @@ public: virtual IScreen* getScreen() const; // IScreenEventHandler overrides - virtual void onError(); virtual void onScreensaver(bool activated); virtual bool onPreDispatch(const CEvent* event); virtual bool onEvent(CEvent* event); diff --git a/platform/CXWindowsScreen.cpp b/platform/CXWindowsScreen.cpp index ed573cbf..5ae7f31e 100644 --- a/platform/CXWindowsScreen.cpp +++ b/platform/CXWindowsScreen.cpp @@ -656,7 +656,7 @@ CXWindowsScreen::ioErrorHandler(Display*) // so we set it to NULL), and exit. log((CLOG_WARN "X display has unexpectedly disconnected")); s_screen->m_display = NULL; - s_screen->m_eventHandler->onError(); + s_screen->m_receiver->onError(); log((CLOG_CRIT "quiting due to X display disconnection")); exit(17); } diff --git a/platform/IMSWindowsScreenEventHandler.h b/platform/IMSWindowsScreenEventHandler.h index 33804a96..eb39542b 100755 --- a/platform/IMSWindowsScreenEventHandler.h +++ b/platform/IMSWindowsScreenEventHandler.h @@ -16,7 +16,6 @@ public: virtual void preDestroyWindow(HWND) = 0; // IScreenEventHandler overrides - virtual void onError() = 0; virtual void onScreensaver(bool activated) = 0; virtual bool onPreDispatch(const CEvent* event) = 0; virtual bool onEvent(CEvent* event) = 0; diff --git a/server/CMSWindowsPrimaryScreen.cpp b/server/CMSWindowsPrimaryScreen.cpp index 3906bcaf..d2e53b6f 100644 --- a/server/CMSWindowsPrimaryScreen.cpp +++ b/server/CMSWindowsPrimaryScreen.cpp @@ -145,12 +145,6 @@ CMSWindowsPrimaryScreen::getScreen() const return m_screen; } -void -CMSWindowsPrimaryScreen::onError() -{ - // ignore -} - void CMSWindowsPrimaryScreen::onScreensaver(bool activated) { diff --git a/server/CMSWindowsPrimaryScreen.h b/server/CMSWindowsPrimaryScreen.h index 5414d633..0b8af7b1 100644 --- a/server/CMSWindowsPrimaryScreen.h +++ b/server/CMSWindowsPrimaryScreen.h @@ -27,7 +27,6 @@ public: virtual IScreen* getScreen() const; // IMSWindowsScreenEventHandler overrides - virtual void onError(); virtual void onScreensaver(bool activated); virtual bool onPreDispatch(const CEvent* event); virtual bool onEvent(CEvent* event); diff --git a/server/CPrimaryClient.cpp b/server/CPrimaryClient.cpp index 89668c22..56bd3464 100644 --- a/server/CPrimaryClient.cpp +++ b/server/CPrimaryClient.cpp @@ -69,6 +69,13 @@ CPrimaryClient::getToggleMask() const return m_screen->getToggleMask(); } +void +CPrimaryClient::onError() +{ + // forward to server + m_server->onError(); +} + void CPrimaryClient::onInfoChanged(const CClientInfo& info) { @@ -79,9 +86,7 @@ CPrimaryClient::onInfoChanged(const CClientInfo& info) bool CPrimaryClient::onGrabClipboard(ClipboardID id) { - bool result = m_server->onGrabClipboard(getName(), id, m_seqNum); - m_clipboardOwner[id] = result; - return result; + return m_server->onGrabClipboard(getName(), id, m_seqNum); } void @@ -93,9 +98,8 @@ CPrimaryClient::onClipboardChanged(ClipboardID id, const CString& data) bool CPrimaryClient::open() { - // all clipboards are clean and owned by us + // all clipboards are clean for (UInt32 i = 0; i < kClipboardEnd; ++i) { - m_clipboardOwner[i] = true; m_clipboardDirty[i] = false; } @@ -159,7 +163,6 @@ CPrimaryClient::grabClipboard(ClipboardID id) m_screen->grabClipboard(id); // clipboard is dirty (because someone else owns it now) - m_clipboardOwner[id] = false; m_clipboardDirty[id] = true; } diff --git a/server/CPrimaryClient.h b/server/CPrimaryClient.h index 3605a8e1..a94da39e 100644 --- a/server/CPrimaryClient.h +++ b/server/CPrimaryClient.h @@ -35,6 +35,7 @@ public: KeyModifierMask getToggleMask() const; // IScreenReceiver overrides + virtual void onError(); virtual void onInfoChanged(const CClientInfo&); virtual bool onGrabClipboard(ClipboardID); virtual void onClipboardChanged(ClipboardID, const CString&); @@ -71,7 +72,6 @@ private: CString m_name; UInt32 m_seqNum; CClientInfo m_info; - bool m_clipboardOwner[kClipboardEnd]; // FIXME -- unneeded? bool m_clipboardDirty[kClipboardEnd]; }; diff --git a/server/CPrimaryScreen.cpp b/server/CPrimaryScreen.cpp index a649a227..4184c7fd 100644 --- a/server/CPrimaryScreen.cpp +++ b/server/CPrimaryScreen.cpp @@ -2,11 +2,10 @@ #include "IScreen.h" #include "IScreenReceiver.h" #include "ProtocolTypes.h" +#include "CLock.h" #include "CThread.h" #include "CLog.h" -// FIXME -- should be locking - // // CPrimaryScreen // @@ -84,7 +83,10 @@ CPrimaryScreen::open() } // enter the screen - enterNoWarp(); + { + CLock lock(&m_mutex); + enterNoWarp(); + } // send screen info m_receiver->onInfoChanged(info); @@ -104,6 +106,7 @@ void CPrimaryScreen::enter(SInt32 x, SInt32 y, bool forScreensaver) { log((CLOG_INFO "entering primary at %d,%d%s", x, y, forScreensaver ? " for screen saver" : "")); + CLock lock(&m_mutex); assert(m_active == true); enterNoWarp(); @@ -118,6 +121,8 @@ CPrimaryScreen::enter(SInt32 x, SInt32 y, bool forScreensaver) void CPrimaryScreen::enterNoWarp() { + // note -- must be locked on entry + // not active anymore m_active = false; @@ -135,6 +140,7 @@ bool CPrimaryScreen::leave() { log((CLOG_INFO "leaving primary")); + CLock lock(&m_mutex); assert(m_active == false); // subclass hook @@ -187,6 +193,7 @@ CPrimaryScreen::grabClipboard(ClipboardID id) bool CPrimaryScreen::isActive() const { + CLock lock(&m_mutex); return m_active; } diff --git a/server/CPrimaryScreen.h b/server/CPrimaryScreen.h index 9040222d..5df1987c 100644 --- a/server/CPrimaryScreen.h +++ b/server/CPrimaryScreen.h @@ -3,6 +3,7 @@ #include "ClipboardTypes.h" #include "KeyTypes.h" +#include "CMutex.h" class IClipboard; class IScreen; @@ -146,8 +147,9 @@ private: void enterNoWarp(); private: - // FIXME -- should have a mutex + CMutex m_mutex; + // object to notify of changes IScreenReceiver* m_receiver; // m_active is true if this screen has been left diff --git a/server/CServer.cpp b/server/CServer.cpp index 1491f6c1..d10606b1 100644 --- a/server/CServer.cpp +++ b/server/CServer.cpp @@ -212,6 +212,20 @@ CServer::getActivePrimarySides() const return sides; } +void +CServer::onError() +{ + // stop all running threads but don't wait too long since some + // threads may be unable to proceed until this thread returns. + stopThreads(3.0); + + // done with the HTTP server + delete m_httpServer; + m_httpServer = NULL; + + // note -- we do not attempt to close down the primary screen +} + void CServer::onInfoChanged(const CString& name, const CClientInfo& info) { @@ -334,20 +348,6 @@ CServer::onClipboardChangedNoLock(ClipboardID id, m_active->setClipboard(id, m_clipboards[id].m_clipboardData); } -void -CServer::onError() -{ - // stop all running threads but don't wait too long since some - // threads may be unable to proceed until this thread returns. - stopThreads(3.0); - - // done with the HTTP server - delete m_httpServer; - m_httpServer = NULL; - - // note -- we do not attempt to close down the primary screen -} - void CServer::onScreensaver(bool activated) { diff --git a/server/CServer.h b/server/CServer.h index b8d49038..734d8906 100644 --- a/server/CServer.h +++ b/server/CServer.h @@ -55,12 +55,12 @@ public: CString getPrimaryScreenName() const; // IServer overrides + virtual void onError(); virtual void onInfoChanged(const CString&, const CClientInfo&); virtual bool onGrabClipboard(const CString&, ClipboardID, UInt32); virtual void onClipboardChanged(ClipboardID, UInt32, const CString&); // IPrimaryScreenReceiver overrides - virtual void onError(); virtual void onScreensaver(bool activated); virtual void onKeyDown(KeyID, KeyModifierMask); virtual void onKeyUp(KeyID, KeyModifierMask); diff --git a/server/CXWindowsPrimaryScreen.cpp b/server/CXWindowsPrimaryScreen.cpp index 1f7fa7b1..1e75254e 100644 --- a/server/CXWindowsPrimaryScreen.cpp +++ b/server/CXWindowsPrimaryScreen.cpp @@ -132,13 +132,6 @@ CXWindowsPrimaryScreen::getScreen() const return m_screen; } -void -CXWindowsPrimaryScreen::onError() -{ - // tell server to shutdown - m_receiver->onError(); -} - void CXWindowsPrimaryScreen::onScreensaver(bool activated) { diff --git a/server/CXWindowsPrimaryScreen.h b/server/CXWindowsPrimaryScreen.h index 2a97a51c..ad625ff7 100644 --- a/server/CXWindowsPrimaryScreen.h +++ b/server/CXWindowsPrimaryScreen.h @@ -28,7 +28,6 @@ public: virtual IScreen* getScreen() const; // IScreenEventHandler overrides - virtual void onError(); virtual void onScreensaver(bool activated); virtual bool onPreDispatch(const CEvent* event); virtual bool onEvent(CEvent* event); diff --git a/synergy/IPrimaryScreenReceiver.h b/synergy/IPrimaryScreenReceiver.h index ff816928..f347786e 100644 --- a/synergy/IPrimaryScreenReceiver.h +++ b/synergy/IPrimaryScreenReceiver.h @@ -11,13 +11,6 @@ // an IPrimaryScreenReceiver* and notify it of events. class IPrimaryScreenReceiver : public IInterface { public: - // called if the display is unexpectedly closing. - - // called if the screen is unexpectedly closing. this implies that - // the screen is no longer usable and that the program should - // close the screen and possibly terminate. - virtual void onError() = 0; - // called when the screensaver is activated or deactivated virtual void onScreensaver(bool activated) = 0; diff --git a/synergy/IScreen.h b/synergy/IScreen.h index 861f69c5..08c337ab 100644 --- a/synergy/IScreen.h +++ b/synergy/IScreen.h @@ -43,7 +43,10 @@ public: // activate or deactivate the screen saver virtual void screensaver(bool activate) = 0; - // FIXME -- need explanation + // ensure that this thread attached with the visible desktop. this is + // mainly intended for windows which has an artificial distinction + // between desktops and a thread cannot interact with the visible + // desktop unless the thread is attached to that desktop. virtual void syncDesktop() = 0; // accessors @@ -58,8 +61,9 @@ public: // get the current cursor coordinates virtual void getCursorPos(SInt32& x, SInt32& y) const = 0; - // get the cursor center position - // FIXME -- need better explanation + // get the cursor center position. this is where we park the + // cursor to compute cursor motion deltas and should be far from + // the edges of the screen, typically the center. virtual void getCursorCenter(SInt32& x, SInt32& y) const = 0; }; diff --git a/synergy/IScreenEventHandler.h b/synergy/IScreenEventHandler.h index 123956be..4c6cd14e 100644 --- a/synergy/IScreenEventHandler.h +++ b/synergy/IScreenEventHandler.h @@ -18,11 +18,6 @@ class IScreenEventHandler : public IInterface { public: // manipulators - // called if the screen is unexpectedly closing. this implies that - // the screen is no longer usable and that the program should - // close the screen and possibly terminate. - virtual void onError() = 0; - // called when the screensaver is activated or deactivated virtual void onScreensaver(bool activated) = 0; diff --git a/synergy/IScreenReceiver.h b/synergy/IScreenReceiver.h index 02fcf936..da2d40c9 100644 --- a/synergy/IScreenReceiver.h +++ b/synergy/IScreenReceiver.h @@ -10,6 +10,11 @@ // notifications (indirectly) from the system. class IScreenReceiver : public IInterface { public: + // called if the screen is unexpectedly closing. this implies that + // the screen is no longer usable and that the program should + // close the screen and possibly terminate. + virtual void onError() = 0; + // notify of client info change virtual void onInfoChanged(const CClientInfo&) = 0; diff --git a/synergy/IServer.h b/synergy/IServer.h index f6a4e458..ee3798d6 100644 --- a/synergy/IServer.h +++ b/synergy/IServer.h @@ -17,6 +17,11 @@ class IServer : public IInterface { public: // manipulators + // called if the screen is unexpectedly closing. this implies that + // the screen is no longer usable and that the program should + // close the screen and possibly terminate. + virtual void onError() = 0; + // notify of client info change virtual void onInfoChanged(const CString& clientName, const CClientInfo&) = 0;