Checkpoint. synergys now works. Still need to do lib/client and

synergyc.
This commit is contained in:
crs 2004-02-14 14:04:36 +00:00
parent c44c18bfdc
commit 1861f21fb5
68 changed files with 3812 additions and 4114 deletions

View File

@ -14,8 +14,8 @@
#include "CServerTaskBarReceiver.h" #include "CServerTaskBarReceiver.h"
#include "CServer.h" #include "CServer.h"
#include "CEventQueue.h"
#include "CLock.h" #include "CLock.h"
#include "TMethodJob.h"
#include "CArch.h" #include "CArch.h"
// //
@ -23,71 +23,80 @@
// //
CServerTaskBarReceiver::CServerTaskBarReceiver() : CServerTaskBarReceiver::CServerTaskBarReceiver() :
m_quit(NULL), m_state(kNotRunning)
m_state(kNotRunning),
m_server(NULL)
{ {
// create a job for getting notification when the server's // do nothing
// status changes.
m_job = new TMethodJob<CServerTaskBarReceiver>(this,
&CServerTaskBarReceiver::statusChanged, NULL);
} }
CServerTaskBarReceiver::~CServerTaskBarReceiver() CServerTaskBarReceiver::~CServerTaskBarReceiver()
{ {
if (m_server != NULL) { // do nothing
m_server->removeStatusJob(m_job);
}
delete m_job;
delete m_quit;
} }
#include "CLog.h"
void void
CServerTaskBarReceiver::setServer(CServer* server) CServerTaskBarReceiver::updateStatus(CServer* server, const CString& errorMsg)
{ {
{ {
// update our status
CLock lock(&m_mutex); CLock lock(&m_mutex);
if (m_server != server) { m_errorMessage = errorMsg;
if (m_server != NULL) { if (server == NULL) {
m_server->removeStatusJob(m_job); if (m_errorMessage.empty()) {
m_state = kNotRunning;
} }
m_server = server; else {
if (m_server != NULL) { m_state = kNotWorking;
m_server->addStatusJob(m_job); }
}
else {
m_clients.clear();
server->getClients(m_clients);
if (m_clients.size() <= 1) {
m_state = kNotConnected;
}
else {
m_state = kConnected;
} }
} }
}
ARCH->updateReceiver(this);
}
void // let subclasses have a go
CServerTaskBarReceiver::setState(EState state) onStatusChanged(server);
{ LOG((CLOG_INFO "### status: %s", getToolTip().c_str()));
{
CLock lock(&m_mutex);
m_state = state;
} }
ARCH->updateReceiver(this);
}
void // tell task bar
CServerTaskBarReceiver::setQuitJob(IJob* job) ARCH->updateReceiver(this);
{
CLock lock(&m_mutex);
delete m_quit;
m_quit = job;
} }
CServerTaskBarReceiver::EState CServerTaskBarReceiver::EState
CServerTaskBarReceiver::getState() const CServerTaskBarReceiver::getStatus() const
{ {
return m_state; return m_state;
} }
CServer* const CString&
CServerTaskBarReceiver::getServer() const CServerTaskBarReceiver::getErrorMessage() const
{ {
return m_server; return m_errorMessage;
}
const CServerTaskBarReceiver::CClients&
CServerTaskBarReceiver::getClients() const
{
return m_clients;
}
void
CServerTaskBarReceiver::quit()
{
EVENTQUEUE->addEvent(CEvent(CEvent::kQuit));
}
void
CServerTaskBarReceiver::onStatusChanged(CServer*)
{
// do nothing
} }
void void
@ -110,7 +119,7 @@ CServerTaskBarReceiver::getToolTip() const
return "Synergy: Not running"; return "Synergy: Not running";
case kNotWorking: case kNotWorking:
return CString("Synergy: ") + m_errorMessage; return std::string("Synergy: ") + m_errorMessage;
case kNotConnected: case kNotConnected:
return "Synergy: Waiting for clients"; return "Synergy: Waiting for clients";
@ -122,50 +131,3 @@ CServerTaskBarReceiver::getToolTip() const
return ""; return "";
} }
} }
void
CServerTaskBarReceiver::quit()
{
if (m_quit != NULL) {
m_quit->run();
}
}
void
CServerTaskBarReceiver::onStatusChanged()
{
// do nothing
}
void
CServerTaskBarReceiver::statusChanged(void*)
{
// update our status
switch (m_server->getStatus(&m_errorMessage)) {
case CServer::kNotRunning:
setState(kNotRunning);
break;
case CServer::kRunning:
if (m_server->getNumClients() > 1)
setState(kConnected);
else
setState(kNotConnected);
break;
case CServer::kServerNameUnknown:
m_errorMessage = "Server name is not in configuration";
setState(kNotWorking);
break;
case CServer::kError:
setState(kNotWorking);
break;
default:
break;
}
// let subclasses have a go
onStatusChanged();
}

View File

@ -18,61 +18,24 @@
#include "CMutex.h" #include "CMutex.h"
#include "CString.h" #include "CString.h"
#include "IArchTaskBarReceiver.h" #include "IArchTaskBarReceiver.h"
#include "stdvector.h"
class CServer; class CServer;
class IJob;
//! Implementation of IArchTaskBarReceiver for the synergy server //! Implementation of IArchTaskBarReceiver for the synergy server
class CServerTaskBarReceiver : public IArchTaskBarReceiver { class CServerTaskBarReceiver : public IArchTaskBarReceiver {
public: public:
enum EState {
kNotRunning,
kNotWorking,
kNotConnected,
kConnected,
kMaxState
};
CServerTaskBarReceiver(); CServerTaskBarReceiver();
virtual ~CServerTaskBarReceiver(); virtual ~CServerTaskBarReceiver();
//! @name manipulators //! @name manipulators
//@{ //@{
//! Set server //! Update status
/*! /*!
Sets the server. The receiver will query state from this server. Determine the status and query required information from the server.
*/ */
void setServer(CServer*); void updateStatus(CServer*, const CString& errorMsg);
//! Set state
/*!
Sets the current server state.
*/
void setState(EState);
//! Set the quit job that causes the server to quit
/*!
Set the job that causes the server to quit.
*/
void setQuitJob(IJob* adopted);
//@}
//! @name accessors
//@{
//! Get state
/*!
Returns the current server state. The receiver is not locked
by this call; the caller must do the locking.
*/
EState getState() const;
//! Get server
/*!
Returns the server set by \c setServer().
*/
CServer* getServer() const;
//@} //@}
@ -86,6 +49,28 @@ public:
virtual std::string getToolTip() const; virtual std::string getToolTip() const;
protected: protected:
typedef std::vector<CString> CClients;
enum EState {
kNotRunning,
kNotWorking,
kNotConnected,
kConnected,
kMaxState
};
//! Get status
EState getStatus() const;
//! Get error message
const CString& getErrorMessage() const;
//! Get connected clients
const CClients& getClients() const;
//! Quit app
/*!
Causes the application to quit gracefully
*/
void quit(); void quit();
//! Status change notification //! Status change notification
@ -93,18 +78,13 @@ protected:
Called when status changes. The default implementation does Called when status changes. The default implementation does
nothing. nothing.
*/ */
virtual void onStatusChanged(); virtual void onStatusChanged(CServer* server);
private:
void statusChanged(void*);
private: private:
CMutex m_mutex; CMutex m_mutex;
IJob* m_quit;
EState m_state; EState m_state;
CServer* m_server;
IJob* m_job;
CString m_errorMessage; CString m_errorMessage;
CClients m_clients;
}; };
#endif #endif

View File

@ -53,9 +53,3 @@ CXWindowsServerTaskBarReceiver::getIcon() const
{ {
return NULL; return NULL;
} }
void
CXWindowsServerTaskBarReceiver::onStatusChanged()
{
// do nothing
}

View File

@ -28,10 +28,6 @@ public:
virtual void runMenu(int x, int y); virtual void runMenu(int x, int y);
virtual void primaryAction(); virtual void primaryAction();
virtual const Icon getIcon() const; virtual const Icon getIcon() const;
protected:
// CServerTaskBarReceiver overrides
virtual void onStatusChanged();
}; };
#endif #endif

View File

@ -12,22 +12,25 @@
* GNU General Public License for more details. * GNU General Public License for more details.
*/ */
#include "CServer.h" #include "CClientListener.h"
#include "CClientProxy.h"
#include "CConfig.h" #include "CConfig.h"
#include "IScreenFactory.h" #include "CPrimaryClient.h"
#include "CServer.h"
#include "CScreen.h"
#include "ProtocolTypes.h" #include "ProtocolTypes.h"
#include "Version.h" #include "Version.h"
#include "XScreen.h" #include "XScreen.h"
#include "CSocketMultiplexer.h"
#include "CTCPSocketFactory.h" #include "CTCPSocketFactory.h"
#include "XSocket.h" #include "XSocket.h"
#include "CLock.h"
#include "CMutex.h"
#include "CThread.h" #include "CThread.h"
#include "XThread.h" #include "CEventQueue.h"
#include "CFunctionJob.h" #include "CFunctionEventJob.h"
#include "CLog.h" #include "CLog.h"
#include "LogOutputters.h" #include "LogOutputters.h"
#include "CArch.h" #include "CArch.h"
#include "XArch.h"
#include "stdfstream.h" #include "stdfstream.h"
#include <cstring> #include <cstring>
@ -98,166 +101,301 @@ CArgs* CArgs::s_instance = NULL;
// platform dependent factories // platform dependent factories
// //
//! Factory for creating screens static
/*! CScreen*
Objects of this type create screens appropriate for the platform. createScreen()
*/
class CScreenFactory : public IScreenFactory {
public:
CScreenFactory() { }
virtual ~CScreenFactory() { }
// IScreenFactory overrides
virtual IPlatformScreen*
create(IScreenReceiver*, IPrimaryScreenReceiver*);
};
IPlatformScreen*
CScreenFactory::create(IScreenReceiver* receiver,
IPrimaryScreenReceiver* primaryReceiver)
{ {
#if WINDOWS_LIKE #if WINDOWS_LIKE
return new CMSWindowsScreen(receiver, primaryReceiver); return new CScreen(new CMSWindowsScreen(true));
#elif UNIX_LIKE #elif UNIX_LIKE
return new CXWindowsScreen(receiver, primaryReceiver); return new CScreen(new CXWindowsScreen(true));
#endif #endif
} }
//! CQuitJob
/*!
A job that cancels a given thread.
*/
class CQuitJob : public IJob {
public:
CQuitJob(const CThread& thread);
~CQuitJob();
// IJob overrides
virtual void run();
private:
CThread m_thread;
};
CQuitJob::CQuitJob(const CThread& thread) :
m_thread(thread)
{
// do nothing
}
CQuitJob::~CQuitJob()
{
// do nothing
}
void
CQuitJob::run()
{
m_thread.cancel();
}
// //
// platform independent main // platform independent main
// //
static CServer* s_server = NULL; static CServer* s_server = NULL;
static CPrimaryClient* s_primaryClient = NULL;
static CClientListener* s_listener = NULL;
static CServerTaskBarReceiver* s_taskBarReceiver = NULL; static CServerTaskBarReceiver* s_taskBarReceiver = NULL;
static static
int void
realMain(void) updateStatus()
{ {
int result = kExitSuccess; s_taskBarReceiver->updateStatus(s_server, "");
do {
bool opened = false;
bool locked = true;
try {
// if configuration has no screens then add this system
// as the default
if (ARG->m_config.begin() == ARG->m_config.end()) {
ARG->m_config.addScreen(ARG->m_name);
}
// set the contact address, if provided, in the config.
// otherwise, if the config doesn't have an address, use
// the default.
if (ARG->m_synergyAddress.isValid()) {
ARG->m_config.setSynergyAddress(ARG->m_synergyAddress);
}
else if (!ARG->m_config.getSynergyAddress().isValid()) {
ARG->m_config.setSynergyAddress(CNetworkAddress(kDefaultPort));
}
// create server
s_server = new CServer(ARG->m_name);
s_server->setConfig(ARG->m_config);
s_server->setScreenFactory(new CScreenFactory);
s_server->setSocketFactory(new CTCPSocketFactory);
s_server->setStreamFilterFactory(NULL);
// open server
try {
s_taskBarReceiver->setServer(s_server);
s_server->open();
opened = true;
// run server
DAEMON_RUNNING(true);
locked = false;
s_server->mainLoop();
// clean up
#define FINALLY do { \
if (!locked) { \
DAEMON_RUNNING(false); \
locked = true; \
} \
if (opened) { \
s_server->close(); \
} \
s_taskBarReceiver->setServer(NULL); \
delete s_server; \
s_server = NULL; \
} while (false)
FINALLY;
}
catch (XScreenUnavailable& e) {
// wait before retrying if we're going to retry
if (ARG->m_restartable) {
ARCH->sleep(e.getRetryTime());
}
else {
result = kExitFailed;
}
FINALLY;
}
catch (XThread&) {
FINALLY;
throw;
}
catch (...) {
// don't try to restart and fail
ARG->m_restartable = false;
result = kExitFailed;
FINALLY;
}
#undef FINALLY
}
catch (XBase& e) {
LOG((CLOG_CRIT "failed: %s", e.what()));
}
catch (XThread&) {
// terminated
ARG->m_restartable = false;
result = kExitTerminated;
}
} while (ARG->m_restartable);
return result;
} }
static
void
updateStatus(const CString& msg)
{
s_taskBarReceiver->updateStatus(s_server, msg);
}
static
void
handleClientConnected(const CEvent&, void* vlistener)
{
CClientListener* listener = reinterpret_cast<CClientListener*>(vlistener);
CClientProxy* client = listener->getNextClient();
if (client != NULL) {
s_server->adoptClient(client);
updateStatus();
}
}
static
CClientListener*
openClientListener(const CNetworkAddress& address)
{
CClientListener* listen =
new CClientListener(address, new CTCPSocketFactory, NULL);
EVENTQUEUE->adoptHandler(CClientListener::getConnectedEvent(), listen,
new CFunctionEventJob(
&handleClientConnected, listen));
return listen;
}
static
void
closeClientListener(CClientListener* listen)
{
if (listen != NULL) {
EVENTQUEUE->removeHandler(CClientListener::getConnectedEvent(), listen);
delete listen;
}
}
static
void
handleScreenError(const CEvent&, void*)
{
EVENTQUEUE->addEvent(CEvent(CEvent::kQuit));
}
static
CPrimaryClient*
openPrimaryClient(const CString& name)
{
LOG((CLOG_DEBUG1 "creating primary screen"));
CScreen* screen = createScreen();
CPrimaryClient* primaryClient = new CPrimaryClient(name, screen);
EVENTQUEUE->adoptHandler(IScreen::getErrorEvent(),
primaryClient->getEventTarget(),
new CFunctionEventJob(
&handleScreenError));
return primaryClient;
}
static
void
closePrimaryClient(CPrimaryClient* primaryClient)
{
if (primaryClient != NULL) {
EVENTQUEUE->removeHandler(IScreen::getErrorEvent(),
primaryClient->getEventTarget());
delete primaryClient;
}
}
static
void
handleNoClients(const CEvent&, void*)
{
updateStatus();
}
static
void
handleClientsDisconnected(const CEvent&, void*)
{
EVENTQUEUE->addEvent(CEvent(CEvent::kQuit));
}
static
CServer*
openServer(const CConfig& config, CPrimaryClient* primaryClient)
{
CServer* server = new CServer(config, primaryClient);
EVENTQUEUE->adoptHandler(CServer::getDisconnectedEvent(), server,
new CFunctionEventJob(handleNoClients));
return server;
}
static
void
closeServer(CServer* server)
{
if (server == NULL) {
return;
}
// tell all clients to disconnect
server->disconnect();
// wait for clients to disconnect for up to timeout seconds
double timeout = 3.0;
CEventQueueTimer* timer = EVENTQUEUE->newOneShotTimer(timeout, NULL);
EVENTQUEUE->adoptHandler(CEvent::kTimer, timer,
new CFunctionEventJob(handleClientsDisconnected));
EVENTQUEUE->adoptHandler(CServer::getDisconnectedEvent(), server,
new CFunctionEventJob(handleClientsDisconnected));
CEvent event;
EVENTQUEUE->getEvent(event);
while (event.getType() != CEvent::kQuit) {
EVENTQUEUE->dispatchEvent(event);
CEvent::deleteData(event);
EVENTQUEUE->getEvent(event);
}
EVENTQUEUE->removeHandler(CEvent::kTimer, timer);
EVENTQUEUE->deleteTimer(timer);
EVENTQUEUE->removeHandler(CServer::getDisconnectedEvent(), server);
// done with server
delete server;
}
static bool startServer();
static
void
retryStartHandler(const CEvent&, void* vtimer)
{
// discard old timer
CEventQueueTimer* timer = reinterpret_cast<CEventQueueTimer*>(vtimer);
EVENTQUEUE->deleteTimer(timer);
EVENTQUEUE->removeHandler(CEvent::kTimer, NULL);
// try starting the server again
LOG((CLOG_DEBUG1 "retry starting server"));
startServer();
}
static
bool
startServer()
{
double retryTime;
CPrimaryClient* primaryClient = NULL;
CClientListener* listener = NULL;
try {
CString name = ARG->m_config.getCanonicalName(ARG->m_name);
primaryClient = openPrimaryClient(name);
listener = openClientListener(ARG->m_config.getSynergyAddress());
s_server = openServer(ARG->m_config, primaryClient);
s_primaryClient = primaryClient;
s_listener = listener;
updateStatus();
LOG((CLOG_NOTE "started server"));
return true;
}
catch (XScreenUnavailable& e) {
LOG((CLOG_WARN "cannot open primary screen: %s", e.what()));
closeClientListener(listener);
closePrimaryClient(primaryClient);
updateStatus(CString("cannot open primary screen: ") + e.what());
retryTime = e.getRetryTime();
}
catch (XSocketAddressInUse& e) {
LOG((CLOG_WARN "cannot listen for clients: %s", e.what()));
closeClientListener(listener);
closePrimaryClient(primaryClient);
updateStatus(CString("cannot listen for clients: ") + e.what());
retryTime = 10.0;
}
catch (XScreenOpenFailure& e) {
LOG((CLOG_CRIT "cannot open primary screen: %s", e.what()));
closeClientListener(listener);
closePrimaryClient(primaryClient);
return false;
}
catch (XBase& e) {
LOG((CLOG_CRIT "failed to start server: %s", e.what()));
closeClientListener(listener);
closePrimaryClient(primaryClient);
return false;
}
if (ARG->m_restartable) {
// install a timer and handler to retry later
LOG((CLOG_DEBUG "retry in %.0f seconds", retryTime));
CEventQueueTimer* timer = EVENTQUEUE->newOneShotTimer(retryTime, NULL);
EVENTQUEUE->adoptHandler(CEvent::kTimer, timer,
new CFunctionEventJob(&retryStartHandler, timer));
return true;
}
else {
// don't try again
return false;
}
}
static
int
realMain()
{
// if configuration has no screens then add this system
// as the default
if (ARG->m_config.begin() == ARG->m_config.end()) {
ARG->m_config.addScreen(ARG->m_name);
}
// set the contact address, if provided, in the config.
// otherwise, if the config doesn't have an address, use
// the default.
if (ARG->m_synergyAddress.isValid()) {
ARG->m_config.setSynergyAddress(ARG->m_synergyAddress);
}
else if (!ARG->m_config.getSynergyAddress().isValid()) {
ARG->m_config.setSynergyAddress(CNetworkAddress(kDefaultPort));
}
// canonicalize the primary screen name
CString primaryName = ARG->m_config.getCanonicalName(ARG->m_name);
if (primaryName.empty()) {
LOG((CLOG_CRIT "unknown screen name `%s'", ARG->m_name.c_str()));
return kExitFailed;
}
// start the server. if this return false then we've failed and
// we shouldn't retry.
LOG((CLOG_DEBUG1 "starting server"));
if (!startServer()) {
return kExitFailed;
}
// run event loop. if startServer() failed we're supposed to retry
// later. the timer installed by startServer() will take care of
// that.
DAEMON_RUNNING(true);
CEvent event;
EVENTQUEUE->getEvent(event);
while (event.getType() != CEvent::kQuit) {
EVENTQUEUE->dispatchEvent(event);
CEvent::deleteData(event);
EVENTQUEUE->getEvent(event);
}
DAEMON_RUNNING(false);
// close down
LOG((CLOG_DEBUG1 "stopping server"));
closeClientListener(s_listener);
closeServer(s_server);
closePrimaryClient(s_primaryClient);
s_server = NULL;
s_listener = NULL;
s_primaryClient = NULL;
updateStatus();
LOG((CLOG_NOTE "stopped server"));
return kExitSuccess;
}
/* XXX
static static
void void
realMainEntry(void* vresult) realMainEntry(void* vresult)
@ -293,7 +431,7 @@ runMainInThread(void)
throw; throw;
} }
} }
*/
// //
// command line parsing // command line parsing
@ -666,9 +804,6 @@ daemonStartup(int argc, const char** argv)
{ {
CSystemLogger sysLogger(DAEMON_NAME); CSystemLogger sysLogger(DAEMON_NAME);
// have to cancel this thread to quit
s_taskBarReceiver->setQuitJob(new CQuitJob(CThread::getCurrentThread()));
// catch errors that would normally exit // catch errors that would normally exit
bye = &byeThrow; bye = &byeThrow;
@ -768,7 +903,6 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
// through the task bar. // through the task bar.
s_taskBarReceiver = new CMSWindowsServerTaskBarReceiver(instance, s_taskBarReceiver = new CMSWindowsServerTaskBarReceiver(instance,
&logBuffer); &logBuffer);
s_taskBarReceiver->setQuitJob(new CQuitJob(CThread::getCurrentThread()));
int result; int result;
try { try {
@ -817,15 +951,20 @@ main(int argc, char** argv)
{ {
CArch arch; CArch arch;
CLOG; CLOG;
CArgs args;
// go really fast
CThread::getCurrentThread().setPriority(-14);
CSocketMultiplexer multiplexer;
CEventQueue eventQueue;
// get program name // get program name
CArgs args;
ARG->m_pname = ARCH->getBasename(argv[0]); ARG->m_pname = ARCH->getBasename(argv[0]);
// make the task bar receiver. the user can control this app // make the task bar receiver. the user can control this app
// through the task bar. // through the task bar.
s_taskBarReceiver = new CXWindowsServerTaskBarReceiver; s_taskBarReceiver = new CXWindowsServerTaskBarReceiver;
s_taskBarReceiver->setQuitJob(new CQuitJob(CThread::getCurrentThread()));
// parse command line // parse command line
parse(argc, argv); parse(argc, argv);

View File

@ -555,6 +555,12 @@ CArch::isAnyAddr(CArchNetAddress addr)
return m_net->isAnyAddr(addr); return m_net->isAnyAddr(addr);
} }
bool
CArch::isEqualAddr(CArchNetAddress a, CArchNetAddress b)
{
return m_net->isEqualAddr(a, b);
}
void void
CArch::sleep(double timeout) CArch::sleep(double timeout)
{ {

View File

@ -153,6 +153,7 @@ public:
virtual void setAddrPort(CArchNetAddress, int port); virtual void setAddrPort(CArchNetAddress, int port);
virtual int getAddrPort(CArchNetAddress); virtual int getAddrPort(CArchNetAddress);
virtual bool isAnyAddr(CArchNetAddress); virtual bool isAnyAddr(CArchNetAddress);
virtual bool isEqualAddr(CArchNetAddress, CArchNetAddress);
// IArchSleep overrides // IArchSleep overrides
virtual void sleep(double timeout); virtual void sleep(double timeout);

View File

@ -575,6 +575,7 @@ CArchMultithreadPosix::interrupt()
lockMutex(m_threadMutex); lockMutex(m_threadMutex);
if (m_signalFunc != NULL) { if (m_signalFunc != NULL) {
m_signalFunc(m_signalUserData); m_signalFunc(m_signalUserData);
pthread_kill(m_mainThread->m_thread, SIGWAKEUP);
} }
else { else {
ARCH->cancelThread(m_mainThread); ARCH->cancelThread(m_mainThread);

View File

@ -29,6 +29,7 @@
#include <arpa/inet.h> #include <arpa/inet.h>
#include <fcntl.h> #include <fcntl.h>
#include <errno.h> #include <errno.h>
#include <string.h>
#if HAVE_POLL #if HAVE_POLL
# include <sys/poll.h> # include <sys/poll.h>
@ -750,6 +751,13 @@ CArchNetworkBSD::isAnyAddr(CArchNetAddress addr)
} }
} }
bool
CArchNetworkBSD::isEqualAddr(CArchNetAddress a, CArchNetAddress b)
{
return (a->m_len == b->m_len &&
memcmp(&a->m_addr, &b->m_addr, a->m_len) == 0);
}
void void
CArchNetworkBSD::throwError(int err) CArchNetworkBSD::throwError(int err)
{ {

View File

@ -77,6 +77,7 @@ public:
virtual void setAddrPort(CArchNetAddress, int port); virtual void setAddrPort(CArchNetAddress, int port);
virtual int getAddrPort(CArchNetAddress); virtual int getAddrPort(CArchNetAddress);
virtual bool isAnyAddr(CArchNetAddress); virtual bool isAnyAddr(CArchNetAddress);
virtual bool isEqualAddr(CArchNetAddress, CArchNetAddress);
private: private:
void throwError(int); void throwError(int);

View File

@ -265,6 +265,9 @@ public:
//! Get the port of an address //! Get the port of an address
virtual int getAddrPort(CArchNetAddress) = 0; virtual int getAddrPort(CArchNetAddress) = 0;
//! Test addresses for equality
virtual bool isEqualAddr(CArchNetAddress, CArchNetAddress) = 0;
//! Test for the "any" address //! Test for the "any" address
/*! /*!
Returns true if \c addr is the "any" address. \c newAnyAddr() Returns true if \c addr is the "any" address. \c newAnyAddr()

View File

@ -56,7 +56,6 @@ ARCH_STRING::vsnprintf(char* str, int size, const char* fmt, va_list ap)
#else // !HAVE_VSNPRINTF && !UNIX_LIKE #else // !HAVE_VSNPRINTF && !UNIX_LIKE
// FIXME
#error vsnprintf not implemented #error vsnprintf not implemented
#endif // !HAVE_VSNPRINTF #endif // !HAVE_VSNPRINTF

View File

@ -13,13 +13,12 @@
*/ */
#include "CEvent.h" #include "CEvent.h"
#include "CEventQueue.h"
// //
// CEvent // CEvent
// //
CEvent::Type CEvent::s_nextType = kLast;
CEvent::CEvent() : CEvent::CEvent() :
m_type(kUnknown), m_type(kUnknown),
m_target(NULL), m_target(NULL),
@ -55,20 +54,21 @@ CEvent::getData() const
} }
CEvent::Type CEvent::Type
CEvent::registerType() CEvent::registerType(const char* name)
{ {
// FIXME -- lock mutex (need a mutex) return EVENTQUEUE->registerType(name);
return s_nextType++;
} }
CEvent::Type CEvent::Type
CEvent::registerTypeOnce(Type& type) CEvent::registerTypeOnce(Type& type, const char* name)
{ {
// FIXME -- lock mutex (need a mutex) return EVENTQUEUE->registerTypeOnce(type, name);
if (type == CEvent::kUnknown) { }
type = s_nextType++;
} const char*
return type; CEvent::getTypeName(Type type)
{
return EVENTQUEUE->getTypeName(type);
} }
void void

View File

@ -16,6 +16,7 @@
#define CEVENT_H #define CEVENT_H
#include "BasicTypes.h" #include "BasicTypes.h"
#include "stdmap.h"
//! Event //! Event
/*! /*!
@ -46,6 +47,33 @@ public:
//! @name manipulators //! @name manipulators
//@{ //@{
//! Creates a new event type
/*!
Returns a unique event type id.
*/
static Type registerType(const char* name);
//! Creates a new event type
/*!
If \p type contains \c kUnknown then it is set to a unique event
type id otherwise it is left alone. The final value of \p type
is returned.
*/
static Type registerTypeOnce(Type& type, const char* name);
//! Get name for event
/*!
Returns the name for the event \p type. This is primarily for
debugging.
*/
static const char* getTypeName(Type type);
//! Release event data
/*!
Deletes event data for the given event.
*/
static void deleteData(const CEvent&);
//@} //@}
//! @name accessors //! @name accessors
//@{ //@{
@ -68,33 +96,12 @@ public:
*/ */
void* getData() const; void* getData() const;
//! Creates a new event type
/*!
Returns a unique event type id.
*/
static Type registerType();
//! Creates a new event type
/*!
If \p type contains \c kUnknown then it is set to a unique event
type id otherwise it is left alone. The final value of \p type
is returned.
*/
static Type registerTypeOnce(Type& type);
//! Release event data
/*!
Deletes event data for the given event.
*/
static void deleteData(const CEvent&);
//@} //@}
private: private:
Type m_type; Type m_type;
void* m_target; void* m_target;
void* m_data; void* m_data;
static Type s_nextType;
}; };
#endif #endif

View File

@ -13,7 +13,9 @@
*/ */
#include "CEventQueue.h" #include "CEventQueue.h"
#include "CLog.h"
#include "CSimpleEventQueueBuffer.h" #include "CSimpleEventQueueBuffer.h"
#include "CStopwatch.h"
#include "IEventJob.h" #include "IEventJob.h"
#include "CArch.h" #include "CArch.h"
@ -30,7 +32,8 @@ interrupt(void*)
// CEventQueue // CEventQueue
// //
CEventQueue::CEventQueue() CEventQueue::CEventQueue() :
m_nextType(CEvent::kLast)
{ {
setInstance(this); setInstance(this);
m_mutex = ARCH->newMutex(); m_mutex = ARCH->newMutex();
@ -46,6 +49,54 @@ CEventQueue::~CEventQueue()
setInstance(NULL); setInstance(NULL);
} }
CEvent::Type
CEventQueue::registerType(const char* name)
{
CArchMutexLock lock(m_mutex);
m_typeMap.insert(std::make_pair(m_nextType, name));
LOG((CLOG_DEBUG1 "registered event type %s as %d", name, m_nextType));
return m_nextType++;
}
CEvent::Type
CEventQueue::registerTypeOnce(CEvent::Type& type, const char* name)
{
CArchMutexLock lock(m_mutex);
if (type == CEvent::kUnknown) {
m_typeMap.insert(std::make_pair(m_nextType, name));
LOG((CLOG_DEBUG1 "registered event type %s as %d", name, m_nextType));
type = m_nextType++;
}
return type;
}
const char*
CEventQueue::getTypeName(CEvent::Type type)
{
switch (type) {
case CEvent::kUnknown:
return "nil";
case CEvent::kQuit:
return "quit";
case CEvent::kSystem:
return "system";
case CEvent::kTimer:
return "timer";
default:
CTypeMap::const_iterator i = m_typeMap.find(type);
if (i == m_typeMap.end()) {
return "<unknown>";
}
else {
return i->second;
}
}
}
void void
CEventQueue::adoptBuffer(IEventQueueBuffer* buffer) CEventQueue::adoptBuffer(IEventQueueBuffer* buffer)
{ {
@ -69,45 +120,55 @@ CEventQueue::adoptBuffer(IEventQueueBuffer* buffer)
bool bool
CEventQueue::getEvent(CEvent& event, double timeout) CEventQueue::getEvent(CEvent& event, double timeout)
{ {
CStopwatch timer(true);
retry:
// if no events are waiting then handle timers and then wait // if no events are waiting then handle timers and then wait
if (m_buffer->isEmpty()) { while (m_buffer->isEmpty()) {
// handle timers first // handle timers first
if (hasTimerExpired(event)) { if (hasTimerExpired(event)) {
return true; return true;
} }
// get time remaining in timeout
double timeLeft = timeout - timer.getTime();
if (timeout >= 0.0 && timeLeft <= 0.0) {
return false;
}
// get time until next timer expires. if there is a timer // get time until next timer expires. if there is a timer
// and it'll expire before the client's timeout then use // and it'll expire before the client's timeout then use
// that duration for our timeout instead. // that duration for our timeout instead.
double timerTimeout = getNextTimerTimeout(); double timerTimeout = getNextTimerTimeout();
if (timerTimeout >= 0.0 && timerTimeout < timeout) { if (timeout < 0.0 || (timerTimeout >= 0.0 && timerTimeout < timeLeft)) {
timeout = timerTimeout; timeLeft = timerTimeout;
} }
// wait for an event // wait for an event
m_buffer->waitForEvent(timeout); m_buffer->waitForEvent(timeLeft);
}
// if no events are pending then do the timers
if (m_buffer->isEmpty()) {
return hasTimerExpired(event);
} }
// get the event
UInt32 dataID; UInt32 dataID;
IEventQueueBuffer::Type type = m_buffer->getEvent(event, dataID); IEventQueueBuffer::Type type = m_buffer->getEvent(event, dataID);
switch (type) { switch (type) {
case IEventQueueBuffer::kNone: case IEventQueueBuffer::kNone:
if (timeout < 0.0 || timeout <= timer.getTime()) {
// don't want to fail if client isn't expecting that
// so if getEvent() fails with an infinite timeout
// then just try getting another event.
goto retry;
}
return false; return false;
case IEventQueueBuffer::kSystem: case IEventQueueBuffer::kSystem:
return true; return true;
case IEventQueueBuffer::kUser: case IEventQueueBuffer::kUser:
{ {
CArchMutexLock lock(m_mutex); CArchMutexLock lock(m_mutex);
event = removeEvent(dataID); event = removeEvent(dataID);
return true; return true;
} }
} }
} }
@ -156,9 +217,16 @@ CEventQueue::newTimer(double duration, void* target)
assert(duration > 0.0); assert(duration > 0.0);
CEventQueueTimer* timer = m_buffer->newTimer(duration, false); CEventQueueTimer* timer = m_buffer->newTimer(duration, false);
if (target == NULL) {
target = timer;
}
CArchMutexLock lock(m_mutex); CArchMutexLock lock(m_mutex);
m_timers.insert(timer); m_timers.insert(timer);
m_timerQueue.push(CTimer(timer, duration, target, false)); // initial duration is requested duration plus whatever's on
// the clock currently because the latter will be subtracted
// the next time we check for timers.
m_timerQueue.push(CTimer(timer, duration,
duration + m_time.getTime(), target, false));
return timer; return timer;
} }
@ -168,9 +236,16 @@ CEventQueue::newOneShotTimer(double duration, void* target)
assert(duration > 0.0); assert(duration > 0.0);
CEventQueueTimer* timer = m_buffer->newTimer(duration, true); CEventQueueTimer* timer = m_buffer->newTimer(duration, true);
if (target == NULL) {
target = timer;
}
CArchMutexLock lock(m_mutex); CArchMutexLock lock(m_mutex);
m_timers.insert(timer); m_timers.insert(timer);
m_timerQueue.push(CTimer(timer, duration, target, true)); // initial duration is requested duration plus whatever's on
// the clock currently because the latter will be subtracted
// the next time we check for timers.
m_timerQueue.push(CTimer(timer, duration,
duration + m_time.getTime(), target, true));
return timer; return timer;
} }
@ -401,13 +476,13 @@ CEventQueue::CTypeTarget::operator<(const CTypeTarget& tt) const
// CEventQueue::CTimer // CEventQueue::CTimer
// //
CEventQueue::CTimer::CTimer(CEventQueueTimer* timer, CEventQueue::CTimer::CTimer(CEventQueueTimer* timer, double timeout,
double timeout, void* target, bool oneShot) : double initialTime, void* target, bool oneShot) :
m_timer(timer), m_timer(timer),
m_timeout(timeout), m_timeout(timeout),
m_target(target), m_target(target),
m_oneShot(oneShot), m_oneShot(oneShot),
m_time(timeout) m_time(initialTime)
{ {
assert(m_timeout > 0.0); assert(m_timeout > 0.0);
} }

View File

@ -39,9 +39,9 @@ public:
virtual bool dispatchEvent(const CEvent& event); virtual bool dispatchEvent(const CEvent& event);
virtual void addEvent(const CEvent& event); virtual void addEvent(const CEvent& event);
virtual CEventQueueTimer* virtual CEventQueueTimer*
newTimer(double duration, void* target = NULL); newTimer(double duration, void* target);
virtual CEventQueueTimer* virtual CEventQueueTimer*
newOneShotTimer(double duration, void* target = NULL); newOneShotTimer(double duration, void* target);
virtual void deleteTimer(CEventQueueTimer*); virtual void deleteTimer(CEventQueueTimer*);
virtual void adoptHandler(void* target, IEventJob* dispatcher); virtual void adoptHandler(void* target, IEventJob* dispatcher);
virtual void adoptHandler(CEvent::Type type, virtual void adoptHandler(CEvent::Type type,
@ -50,8 +50,13 @@ public:
virtual IEventJob* orphanHandler(CEvent::Type type, void* target); virtual IEventJob* orphanHandler(CEvent::Type type, void* target);
virtual void removeHandler(void* target); virtual void removeHandler(void* target);
virtual void removeHandler(CEvent::Type type, void* target); virtual void removeHandler(CEvent::Type type, void* target);
virtual CEvent::Type
registerType(const char* name);
virtual CEvent::Type
registerTypeOnce(CEvent::Type& type, const char* name);
virtual bool isEmpty() const; virtual bool isEmpty() const;
virtual IEventJob* getHandler(CEvent::Type type, void* target) const; virtual IEventJob* getHandler(CEvent::Type type, void* target) const;
virtual const char* getTypeName(CEvent::Type type);
private: private:
void doAdoptHandler(CEvent::Type type, void doAdoptHandler(CEvent::Type type,
@ -77,7 +82,8 @@ private:
}; };
class CTimer { class CTimer {
public: public:
CTimer(CEventQueueTimer*, double timeout, void* target, bool oneShot); CTimer(CEventQueueTimer*, double timeout, double initialTime,
void* target, bool oneShot);
~CTimer(); ~CTimer();
void reset(); void reset();
@ -106,19 +112,28 @@ private:
typedef std::map<UInt32, CEvent> CEventTable; typedef std::map<UInt32, CEvent> CEventTable;
typedef std::vector<UInt32> CEventIDList; typedef std::vector<UInt32> CEventIDList;
typedef std::map<CTypeTarget, IEventJob*> CHandlerTable; typedef std::map<CTypeTarget, IEventJob*> CHandlerTable;
typedef std::map<CEvent::Type, const char*> CTypeMap;
CArchMutex m_mutex; CArchMutex m_mutex;
// registered events
CEvent::Type m_nextType;
CTypeMap m_typeMap;
// buffer of events
IEventQueueBuffer* m_buffer; IEventQueueBuffer* m_buffer;
// saved events
CEventTable m_events; CEventTable m_events;
CEventIDList m_oldEventIDs; CEventIDList m_oldEventIDs;
// timers
CStopwatch m_time; CStopwatch m_time;
CTimers m_timers; CTimers m_timers;
CTimerQueue m_timerQueue; CTimerQueue m_timerQueue;
CTimerEvent m_timerEvent; CTimerEvent m_timerEvent;
// event handlers
CHandlerTable m_handlers; CHandlerTable m_handlers;
}; };

View File

@ -0,0 +1,97 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2004 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "CSimpleEventQueueBuffer.h"
#include "CStopwatch.h"
#include "CArch.h"
class CEventQueueTimer { };
//
// CSimpleEventQueueBuffer
//
CSimpleEventQueueBuffer::CSimpleEventQueueBuffer()
{
m_queueMutex = ARCH->newMutex();
m_queueReadyCond = ARCH->newCondVar();
m_queueReady = false;
}
CSimpleEventQueueBuffer::~CSimpleEventQueueBuffer()
{
ARCH->closeCondVar(m_queueReadyCond);
ARCH->closeMutex(m_queueMutex);
}
void
CSimpleEventQueueBuffer::waitForEvent(double timeout)
{
CArchMutexLock lock(m_queueMutex);
CStopwatch timer(true);
while (!m_queueReady) {
double timeLeft = timeout;
if (timeLeft >= 0.0) {
timeLeft -= timer.getTime();
if (timeLeft < 0.0) {
return;
}
}
ARCH->waitCondVar(m_queueReadyCond, m_queueMutex, timeLeft);
}
}
IEventQueueBuffer::Type
CSimpleEventQueueBuffer::getEvent(CEvent& event, UInt32& dataID)
{
CArchMutexLock lock(m_queueMutex);
if (!m_queueReady) {
return kNone;
}
dataID = m_queue.back();
m_queue.pop_back();
m_queueReady = !m_queue.empty();
return kUser;
}
bool
CSimpleEventQueueBuffer::addEvent(UInt32 dataID)
{
CArchMutexLock lock(m_queueMutex);
m_queue.push_front(dataID);
if (!m_queueReady) {
m_queueReady = true;
ARCH->broadcastCondVar(m_queueReadyCond);
}
return true;
}
bool
CSimpleEventQueueBuffer::isEmpty() const
{
CArchMutexLock lock(m_queueMutex);
return !m_queueReady;
}
CEventQueueTimer*
CSimpleEventQueueBuffer::newTimer(double, bool) const
{
return new CEventQueueTimer;
}
void
CSimpleEventQueueBuffer::deleteTimer(CEventQueueTimer* timer) const
{
delete timer;
}

View File

@ -0,0 +1,49 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2004 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef CSIMPLEEVENTQUEUEBUFFER_H
#define CSIMPLEEVENTQUEUEBUFFER_H
#include "IEventQueueBuffer.h"
#include "IArchMultithread.h"
#include "stddeque.h"
//! In-memory event queue buffer
/*!
An event queue buffer provides a queue of events for an IEventQueue.
*/
class CSimpleEventQueueBuffer : public IEventQueueBuffer {
public:
CSimpleEventQueueBuffer();
~CSimpleEventQueueBuffer();
// IEventQueueBuffer overrides
virtual void waitForEvent(double timeout);
virtual Type getEvent(CEvent& event, UInt32& dataID);
virtual bool addEvent(UInt32 dataID);
virtual bool isEmpty() const;
virtual CEventQueueTimer*
newTimer(double duration, bool oneShot) const;
virtual void deleteTimer(CEventQueueTimer*) const;
private:
typedef std::deque<UInt32> CEventDeque;
CArchMutex m_queueMutex;
CArchCond m_queueReadyCond;
bool m_queueReady;
CEventDeque m_queue;
};
#endif

View File

@ -176,7 +176,7 @@ CStringUtil::CaselessCmp::cmpEqual(
const CString::value_type& a, const CString::value_type& a,
const CString::value_type& b) const CString::value_type& b)
{ {
// FIXME -- use std::tolower but not in all versions of libstdc++ have it // should use std::tolower but not in all versions of libstdc++ have it
return tolower(a) == tolower(b); return tolower(a) == tolower(b);
} }
@ -185,7 +185,7 @@ CStringUtil::CaselessCmp::cmpLess(
const CString::value_type& a, const CString::value_type& a,
const CString::value_type& b) const CString::value_type& b)
{ {
// FIXME -- use std::tolower but not in all versions of libstdc++ have it // should use std::tolower but not in all versions of libstdc++ have it
return tolower(a) < tolower(b); return tolower(a) < tolower(b);
} }

View File

@ -80,7 +80,8 @@ public:
is returned the data points to a \c CTimerEvent. The client must pass is returned the data points to a \c CTimerEvent. The client must pass
the returned timer to \c deleteTimer() (whether or not the timer has the returned timer to \c deleteTimer() (whether or not the timer has
expired) to release the timer. The returned timer event uses the expired) to release the timer. The returned timer event uses the
given \p target. given \p target. If \p target is NULL it uses the returned timer as
the target.
Events for a single timer don't accumulate in the queue, even if the Events for a single timer don't accumulate in the queue, even if the
client reading events can't keep up. Instead, the \c m_count member client reading events can't keep up. Instead, the \c m_count member
@ -89,7 +90,7 @@ public:
removed (or since the timer was added). removed (or since the timer was added).
*/ */
virtual CEventQueueTimer* virtual CEventQueueTimer*
newTimer(double duration, void* target = NULL) = 0; newTimer(double duration, void* target) = 0;
//! Create a one-shot timer //! Create a one-shot timer
/*! /*!
@ -99,11 +100,12 @@ public:
The \m c_count member of the \c CTimerEvent is always 1. The client The \m c_count member of the \c CTimerEvent is always 1. The client
must pass the returned timer to \c deleteTimer() (whether or not the must pass the returned timer to \c deleteTimer() (whether or not the
timer has expired) to release the timer. The returned timer event timer has expired) to release the timer. The returned timer event
uses the given \p target. uses the given \p target. If \p target is NULL it uses the returned
timer as the target.
*/ */
virtual CEventQueueTimer* virtual CEventQueueTimer*
newOneShotTimer(double duration, newOneShotTimer(double duration,
void* target = NULL) = 0; void* target) = 0;
//! Destroy a timer //! Destroy a timer
/*! /*!
@ -160,6 +162,23 @@ public:
*/ */
virtual void removeHandler(CEvent::Type type, void* target) = 0; virtual void removeHandler(CEvent::Type type, void* target) = 0;
//! Creates a new event type
/*!
Returns a unique event type id.
*/
virtual CEvent::Type
registerType(const char* name) = 0;
//! Creates a new event type
/*!
If \p type contains \c kUnknown then it is set to a unique event
type id otherwise it is left alone. The final value of \p type
is returned.
*/
virtual CEvent::Type
registerTypeOnce(CEvent::Type& type,
const char* name) = 0;
//@} //@}
//! @name accessors //! @name accessors
//@{ //@{
@ -179,6 +198,13 @@ public:
*/ */
virtual IEventJob* getHandler(CEvent::Type type, void* target) const = 0; virtual IEventJob* getHandler(CEvent::Type type, void* target) const = 0;
//! Get name for event
/*!
Returns the name for the event \p type. This is primarily for
debugging.
*/
virtual const char* getTypeName(CEvent::Type type) = 0;
//! Get the system event type target //! Get the system event type target
/*! /*!
Returns the target to use for dispatching \c CEvent::kSystem events. Returns the target to use for dispatching \c CEvent::kSystem events.

View File

@ -0,0 +1,94 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2004 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef IEVENTQUEUEBUFFER_H
#define IEVENTQUEUEBUFFER_H
#include "IInterface.h"
#include "BasicTypes.h"
class CEvent;
class CEventQueueTimer;
//! Event queue buffer interface
/*!
An event queue buffer provides a queue of events for an IEventQueue.
*/
class IEventQueueBuffer : public IInterface {
public:
enum Type {
kNone, //!< No event is available
kSystem, //!< Event is a system event
kUser //!< Event is a user event
};
//! @name manipulators
//@{
//! Block waiting for an event
/*!
Wait for an event in the event queue buffer for up to \p timeout
seconds.
*/
virtual void waitForEvent(double timeout) = 0;
//! Get the next event
/*!
Get the next event from the buffer. Return kNone if no event is
available. If a system event is next, return kSystem and fill in
event. The event data in a system event can point to a static
buffer (because CEvent::deleteData() will not attempt to delete
data in a kSystem event). Otherwise, return kUser and fill in
\p dataID with the value passed to \c addEvent().
*/
virtual Type getEvent(CEvent& event, UInt32& dataID) = 0;
//! Post an event
/*!
Add the given event to the end of the queue buffer. This is a user
event and \c getEvent() must be able to identify it as such and
return \p dataID. This method must cause \c waitForEvent() to
return at some future time if it's blocked waiting on an event.
*/
virtual bool addEvent(UInt32 dataID) = 0;
//@}
//! @name accessors
//@{
//! Check if event queue buffer is empty
/*!
Return true iff the event queue buffer is empty.
*/
virtual bool isEmpty() const = 0;
//! Create a timer object
/*!
Create and return a timer object. The object is opaque and is
used only by the buffer but it must be a valid object (i.e.
not NULL).
*/
virtual CEventQueueTimer*
newTimer(double duration, bool oneShot) const = 0;
//! Destroy a timer object
/*!
Destroy a timer object previously returned by \c newTimer().
*/
virtual void deleteTimer(CEventQueueTimer*) const = 0;
//@}
};
#endif

View File

@ -27,29 +27,34 @@ CEvent::Type IStream::s_outputShutdownEvent = CEvent::kUnknown;
CEvent::Type CEvent::Type
IStream::getInputReadyEvent() IStream::getInputReadyEvent()
{ {
return CEvent::registerTypeOnce(s_inputReadyEvent); return CEvent::registerTypeOnce(s_inputReadyEvent,
"IStream::inputReady");
} }
CEvent::Type CEvent::Type
IStream::getOutputFlushedEvent() IStream::getOutputFlushedEvent()
{ {
return CEvent::registerTypeOnce(s_outputFlushedEvent); return CEvent::registerTypeOnce(s_outputFlushedEvent,
"IStream::outputFlushed");
} }
CEvent::Type CEvent::Type
IStream::getOutputErrorEvent() IStream::getOutputErrorEvent()
{ {
return CEvent::registerTypeOnce(s_outputErrorEvent); return CEvent::registerTypeOnce(s_outputErrorEvent,
"IStream::outputError");
} }
CEvent::Type CEvent::Type
IStream::getInputShutdownEvent() IStream::getInputShutdownEvent()
{ {
return CEvent::registerTypeOnce(s_inputShutdownEvent); return CEvent::registerTypeOnce(s_inputShutdownEvent,
"IStream::inputShutdown");
} }
CEvent::Type CEvent::Type
IStream::getOutputShutdownEvent() IStream::getOutputShutdownEvent()
{ {
return CEvent::registerTypeOnce(s_outputShutdownEvent); return CEvent::registerTypeOnce(s_outputShutdownEvent,
"IStream::outputShutdown");
} }

View File

@ -141,6 +141,18 @@ CNetworkAddress::operator=(const CNetworkAddress& addr)
return *this; return *this;
} }
bool
CNetworkAddress::operator==(const CNetworkAddress& addr) const
{
return ARCH->isEqualAddr(m_address, addr.m_address);
}
bool
CNetworkAddress::operator!=(const CNetworkAddress& addr) const
{
return !operator==(addr);
}
bool bool
CNetworkAddress::isValid() const CNetworkAddress::isValid() const
{ {

View File

@ -55,6 +55,18 @@ public:
//! @name accessors //! @name accessors
//@{ //@{
//! Check address equality
/*!
Returns true if this address is equal to \p address.
*/
bool operator==(const CNetworkAddress&) const;
//! Check address inequality
/*!
Returns true if this address is not equal to \p address.
*/
bool operator!=(const CNetworkAddress&) const;
//! Check address validity //! Check address validity
/*! /*!
Returns true if this is not the invalid address. Returns true if this is not the invalid address.

View File

@ -18,6 +18,7 @@
#include "CLock.h" #include "CLock.h"
#include "CMutex.h" #include "CMutex.h"
#include "CThread.h" #include "CThread.h"
#include "CLog.h"
#include "TMethodJob.h" #include "TMethodJob.h"
#include "CArch.h" #include "CArch.h"
#include "XArch.h" #include "XArch.h"
@ -207,8 +208,8 @@ CSocketMultiplexer::serviceThread(void*)
// check for status // check for status
status = ARCH->pollSocket(&pfds[0], pfds.size(), -1); status = ARCH->pollSocket(&pfds[0], pfds.size(), -1);
} }
catch (XArchNetwork&) { catch (XArchNetwork& e) {
// FIXME -- uh oh LOG((CLOG_WARN "error in socket multiplexer: %s", e.what().c_str()));
status = 0; status = 0;
} }

View File

@ -62,6 +62,7 @@ CTCPListenSocket::bind(const CNetworkAddress& addr)
CLock lock(m_mutex); CLock lock(m_mutex);
ARCH->bindSocket(m_socket, addr.getAddress()); ARCH->bindSocket(m_socket, addr.getAddress());
ARCH->listenOnSocket(m_socket); ARCH->listenOnSocket(m_socket);
ARCH->setBlockingOnSocket(m_socket, false);
CSocketMultiplexer::getInstance()->addSocket(this, CSocketMultiplexer::getInstance()->addSocket(this,
new TSocketMultiplexerMethodJob<CTCPListenSocket>( new TSocketMultiplexerMethodJob<CTCPListenSocket>(
this, &CTCPListenSocket::serviceListening, this, &CTCPListenSocket::serviceListening,
@ -102,11 +103,13 @@ IDataSocket*
CTCPListenSocket::accept() CTCPListenSocket::accept()
{ {
try { try {
IDataSocket* socket =
new CTCPSocket(ARCH->acceptSocket(m_socket, NULL));
CSocketMultiplexer::getInstance()->addSocket(this, CSocketMultiplexer::getInstance()->addSocket(this,
new TSocketMultiplexerMethodJob<CTCPListenSocket>( new TSocketMultiplexerMethodJob<CTCPListenSocket>(
this, &CTCPListenSocket::serviceListening, this, &CTCPListenSocket::serviceListening,
m_socket, true, false)); m_socket, true, false));
return new CTCPSocket(ARCH->acceptSocket(m_socket, NULL)); return socket;
} }
catch (XArchNetwork&) { catch (XArchNetwork&) {
return NULL; return NULL;

View File

@ -19,6 +19,7 @@
#include "XSocket.h" #include "XSocket.h"
#include "CLock.h" #include "CLock.h"
#include "CEventQueue.h" #include "CEventQueue.h"
#include "CLog.h"
#include "IEventJob.h" #include "IEventJob.h"
#include "CArch.h" #include "CArch.h"
#include "XArch.h" #include "XArch.h"
@ -102,8 +103,8 @@ CTCPSocket::close()
ARCH->closeSocket(socket); ARCH->closeSocket(socket);
} }
catch (XArchNetwork& e) { catch (XArchNetwork& e) {
// FIXME -- just discard this for now // ignore, there's not much we can do
//throw XSocketIOClose(e.what()); LOG((CLOG_WARN "error closing socket: %s", e.what().c_str()));
} }
} }
} }
@ -257,7 +258,6 @@ CTCPSocket::connect(const CNetworkAddress& addr)
} }
try { try {
// FIXME -- don't throw if in progress, just return that info
ARCH->connectSocket(m_socket, addr.getAddress()); ARCH->connectSocket(m_socket, addr.getAddress());
sendSocketEvent(getConnectedEvent()); sendSocketEvent(getConnectedEvent());
onConnected(); onConnected();
@ -281,15 +281,13 @@ CTCPSocket::init()
m_readable = false; m_readable = false;
m_writable = false; m_writable = false;
// make socket non-blocking
// FIXME -- check for error
ARCH->setBlockingOnSocket(m_socket, false);
// turn off Nagle algorithm. we send lots of very short messages
// that should be sent without (much) delay. for example, the
// mouse motion messages are much less useful if they're delayed.
// FIXME -- the client should do this
try { try {
// make socket non-blocking
ARCH->setBlockingOnSocket(m_socket, false);
// turn off Nagle algorithm. we send lots of very short messages
// that should be sent without (much) delay. for example, the
// mouse motion messages are much less useful if they're delayed.
ARCH->setNoDelayOnSocket(m_socket, true); ARCH->setNoDelayOnSocket(m_socket, true);
} }
catch (XArchNetwork& e) { catch (XArchNetwork& e) {

View File

@ -24,11 +24,13 @@ CEvent::Type IDataSocket::s_failedEvent = CEvent::kUnknown;
CEvent::Type CEvent::Type
IDataSocket::getConnectedEvent() IDataSocket::getConnectedEvent()
{ {
return CEvent::registerTypeOnce(s_connectedEvent); return CEvent::registerTypeOnce(s_connectedEvent,
"IDataSocket::connected");
} }
CEvent::Type CEvent::Type
IDataSocket::getConnectionFailedEvent() IDataSocket::getConnectionFailedEvent()
{ {
return CEvent::registerTypeOnce(s_failedEvent); return CEvent::registerTypeOnce(s_failedEvent,
"IDataSocket::failed");
} }

View File

@ -23,5 +23,6 @@ CEvent::Type IListenSocket::s_connectingEvent = CEvent::kUnknown;
CEvent::Type CEvent::Type
IListenSocket::getConnectingEvent() IListenSocket::getConnectingEvent()
{ {
return CEvent::registerTypeOnce(s_connectingEvent); return CEvent::registerTypeOnce(s_connectingEvent,
"IListenSocket::connecting");
} }

View File

@ -23,5 +23,6 @@ CEvent::Type ISocket::s_disconnectedEvent = CEvent::kUnknown;
CEvent::Type CEvent::Type
ISocket::getDisconnectedEvent() ISocket::getDisconnectedEvent()
{ {
return CEvent::registerTypeOnce(s_disconnectedEvent); return CEvent::registerTypeOnce(s_disconnectedEvent,
"ISocket::disconnected");
} }

View File

@ -12,9 +12,10 @@
* GNU General Public License for more details. * GNU General Public License for more details.
*/ */
#include "CXWindowsEventQueue.h" #include "CXWindowsEventQueueBuffer.h"
#include "CEvent.h"
#include "CThread.h" #include "CThread.h"
#include "CEvent.h"
#include "IEventQueue.h"
#if UNIX_LIKE #if UNIX_LIKE
# if HAVE_POLL # if HAVE_POLL
# include <sys/poll.h> # include <sys/poll.h>
@ -42,52 +43,27 @@ class CEventQueueTimer { };
// //
// CXWindowsEventQueue // CXWindowsEventQueueBuffer
// //
CXWindowsEventQueue::CXWindowsEventQueue(Display* display) : CXWindowsEventQueueBuffer::CXWindowsEventQueueBuffer(
m_display(display) Display* display, Window window) :
m_display(display),
m_window(window)
{ {
assert(m_display != NULL);
assert(m_window != None);
m_userEvent = XInternAtom(m_display, "SYNERGY_USER_EVENT", False); m_userEvent = XInternAtom(m_display, "SYNERGY_USER_EVENT", False);
XSetWindowAttributes attr;
m_window = XCreateWindow(m_display, DefaultRootWindow(m_display),
0, 0, 1, 1, 0, 0, InputOnly, CopyFromParent,
0, &attr);
} }
CXWindowsEventQueue::~CXWindowsEventQueue() CXWindowsEventQueueBuffer::~CXWindowsEventQueueBuffer()
{ {
XDestroyWindow(m_display, m_window); // do nothing
} }
void void
CXWindowsEventQueue::processSystemEvent(CEvent& event) CXWindowsEventQueueBuffer::waitForEvent(double dtimeout)
{
event = CEvent(CEvent::kSystem, getSystemTarget(), &m_event);
}
void
CXWindowsEventQueue::processClientMessage(CEvent& event)
{
assert(m_event.xany.type == ClientMessage);
// handle user events specially
if (m_event.xclient.message_type == m_userEvent) {
// get event data
CEventData data = removeEventData(m_event.xclient.data.l[1]);
// create event
event = CEvent(static_cast<size_t>(m_event.xclient.data.l[0]),
data.first, data.second);
}
else {
processSystemEvent(event);
}
}
void
CXWindowsEventQueue::waitForEvent(double dtimeout)
{ {
// use poll() to wait for a message from the X server or for timeout. // use poll() to wait for a message from the X server or for timeout.
// this is a good deal more efficient than polling and sleeping. // this is a good deal more efficient than polling and sleeping.
@ -132,25 +108,27 @@ CXWindowsEventQueue::waitForEvent(double dtimeout)
CThread::testCancel(); CThread::testCancel();
} }
bool IEventQueueBuffer::Type
CXWindowsEventQueue::doGetEvent(CEvent& event) CXWindowsEventQueueBuffer::getEvent(CEvent& event, UInt32& dataID)
{ {
// get next event // get next event
XNextEvent(m_display, &m_event); XNextEvent(m_display, &m_event);
// process event // process event
if (m_event.xany.type == ClientMessage) { if (m_event.xany.type == ClientMessage &&
processClientMessage(event); m_event.xclient.message_type == m_userEvent) {
dataID = static_cast<UInt32>(m_event.xclient.data.l[0]);
return kUser;
} }
else { else {
processSystemEvent(event); event = CEvent(CEvent::kSystem,
IEventQueue::getSystemTarget(), &m_event);
return kSystem;
} }
return true;
} }
bool bool
CXWindowsEventQueue::doAddEvent(CEvent::Type type, UInt32 dataID) CXWindowsEventQueueBuffer::addEvent(UInt32 dataID)
{ {
// send ourself a message // send ourself a message
XEvent xevent; XEvent xevent;
@ -158,25 +136,29 @@ CXWindowsEventQueue::doAddEvent(CEvent::Type type, UInt32 dataID)
xevent.xclient.window = m_window; xevent.xclient.window = m_window;
xevent.xclient.message_type = m_userEvent; xevent.xclient.message_type = m_userEvent;
xevent.xclient.format = 32; xevent.xclient.format = 32;
xevent.xclient.data.l[0] = static_cast<long>(type); xevent.xclient.data.l[0] = static_cast<long>(dataID);
xevent.xclient.data.l[1] = static_cast<long>(dataID); if (XSendEvent(m_display, m_window, False, 0, &xevent) == 0) {
return (XSendEvent(m_display, m_window, False, 0, &xevent) != 0); return false;
}
// force waitForEvent() to return
XFlush(m_display);
} }
bool bool
CXWindowsEventQueue::doIsEmpty() const CXWindowsEventQueueBuffer::isEmpty() const
{ {
return (XPending(m_display) == 0); return (XPending(m_display) == 0);
} }
CEventQueueTimer* CEventQueueTimer*
CXWindowsEventQueue::doNewTimer(double, bool) const CXWindowsEventQueueBuffer::newTimer(double, bool) const
{ {
return new CEventQueueTimer(); return new CEventQueueTimer();
} }
void void
CXWindowsEventQueue::doDeleteTimer(CEventQueueTimer* timer) const CXWindowsEventQueueBuffer::deleteTimer(CEventQueueTimer* timer) const
{ {
delete timer; delete timer;
} }

View File

@ -12,44 +12,30 @@
* GNU General Public License for more details. * GNU General Public License for more details.
*/ */
#ifndef CXWINDOWSEVENTQUEUE_H #ifndef CXWINDOWSEVENTQUEUEBUFFER_H
#define CXWINDOWSEVENTQUEUE_H #define CXWINDOWSEVENTQUEUEBUFFER_H
#include "CEventQueue.h" #include "IEventQueueBuffer.h"
#if defined(X_DISPLAY_MISSING) #if defined(X_DISPLAY_MISSING)
# error X11 is required to build synergy # error X11 is required to build synergy
#else #else
# include <X11/Xlib.h> # include <X11/Xlib.h>
#endif #endif
//! Event queue for X11 //! Event queue buffer for X11
class CXWindowsEventQueue : public CEventQueue { class CXWindowsEventQueueBuffer : public IEventQueueBuffer {
public: public:
CXWindowsEventQueue(Display*); CXWindowsEventQueueBuffer(Display*, Window);
virtual ~CXWindowsEventQueue(); virtual ~CXWindowsEventQueueBuffer();
//! @name manipulators // IEventQueueBuffer overrides
//@{
//@}
//! @name accessors
//@{
//@}
protected:
// CEventQueue overrides
virtual void waitForEvent(double timeout); virtual void waitForEvent(double timeout);
virtual bool doGetEvent(CEvent& event); virtual Type getEvent(CEvent& event, UInt32& dataID);
virtual bool doAddEvent(CEvent::Type type, UInt32 dataID); virtual bool addEvent(UInt32 dataID);
virtual bool doIsEmpty() const; virtual bool isEmpty() const;
virtual CEventQueueTimer* virtual CEventQueueTimer*
doNewTimer(double duration, bool oneShot) const; newTimer(double duration, bool oneShot) const;
virtual void doDeleteTimer(CEventQueueTimer*) const; virtual void deleteTimer(CEventQueueTimer*) const;
private:
void processSystemEvent(CEvent& event);
void processClientMessage(CEvent& event);
private: private:
Display* m_display; Display* m_display;

File diff suppressed because it is too large Load Diff

View File

@ -17,9 +17,6 @@
#include "IPlatformScreen.h" #include "IPlatformScreen.h"
#include "CXWindowsKeyMapper.h" #include "CXWindowsKeyMapper.h"
#include "CMutex.h"
#include "CStopwatch.h"
#include "CPriorityQueue.h"
#include "stdvector.h" #include "stdvector.h"
#if defined(X_DISPLAY_MISSING) #if defined(X_DISPLAY_MISSING)
# error X11 is required to build synergy # error X11 is required to build synergy
@ -29,43 +26,22 @@
class CXWindowsClipboard; class CXWindowsClipboard;
class CXWindowsScreenSaver; class CXWindowsScreenSaver;
class IJob;
class IScreenReceiver;
class IPrimaryScreenReceiver;
//! Implementation of IPlatformScreen for X11 //! Implementation of IPlatformScreen for X11
class CXWindowsScreen : public IPlatformScreen { class CXWindowsScreen : public IPlatformScreen {
public: public:
CXWindowsScreen(IScreenReceiver*, IPrimaryScreenReceiver*); CXWindowsScreen(bool isPrimary);
virtual ~CXWindowsScreen(); virtual ~CXWindowsScreen();
//! @name manipulators //! @name manipulators
//@{ //@{
//! Add timer
/*!
Add a job to invoke every timeout seconds. The job is called
with the display locked. If a job timeout expires twice or
more before the job can be called then the job is called just
once. The caller retains ownership of the job.
*/
void addTimer(IJob*, double timeout);
//! Remove timer
/*!
Remove a job. The caller retains ownership of the job.
*/
void removeTimer(IJob*);
//@} //@}
// IPlatformScreen overrides // IPlatformScreen overrides
virtual void open(IKeyState*); virtual void setKeyState(IKeyState*);
virtual void close();
virtual void enable(); virtual void enable();
virtual void disable(); virtual void disable();
virtual void mainLoop();
virtual void exitMainLoop();
virtual void enter(); virtual void enter();
virtual bool leave(); virtual bool leave();
virtual bool setClipboard(ClipboardID, const IClipboard*); virtual bool setClipboard(ClipboardID, const IClipboard*);
@ -76,17 +52,22 @@ public:
virtual void resetOptions(); virtual void resetOptions();
virtual void setOptions(const COptionsList& options); virtual void setOptions(const COptionsList& options);
virtual void updateKeys(); virtual void updateKeys();
virtual void setSequenceNumber(UInt32);
virtual bool isPrimary() const; virtual bool isPrimary() const;
virtual bool getClipboard(ClipboardID, IClipboard*) const;
virtual void getShape(SInt32&, SInt32&, SInt32&, SInt32&) const; // IScreen overrides
virtual void getCursorPos(SInt32&, SInt32&) const; virtual void* getEventTarget() const;
virtual bool getClipboard(ClipboardID id, IClipboard*) const;
virtual void getShape(SInt32& x, SInt32& y,
SInt32& width, SInt32& height) const;
virtual void getCursorPos(SInt32& x, SInt32& y) const;
// IPrimaryScreen overrides // IPrimaryScreen overrides
virtual void reconfigure(UInt32 activeSides); virtual void reconfigure(UInt32 activeSides);
virtual void warpCursor(SInt32 x, SInt32 y); virtual void warpCursor(SInt32 x, SInt32 y);
virtual UInt32 addOneShotTimer(double timeout);
virtual SInt32 getJumpZoneSize() const; virtual SInt32 getJumpZoneSize() const;
virtual bool isAnyMouseButtonDown() const; virtual bool isAnyMouseButtonDown() const;
virtual void getCursorCenter(SInt32& x, SInt32& y) const;
virtual const char* getKeyName(KeyButton) const; virtual const char* getKeyName(KeyButton) const;
// ISecondaryScreen overrides // ISecondaryScreen overrides
@ -101,18 +82,16 @@ public:
bool isAutoRepeat) const; bool isAutoRepeat) const;
private: private:
// process events before dispatching to receiver // event sending
void onEvent(XEvent* event); void sendEvent(CEvent::Type, void* = NULL);
void sendClipboardEvent(CEvent::Type, ClipboardID);
// event handling
void handleSystemEvent(const CEvent&, void*);
// create the transparent cursor // create the transparent cursor
Cursor createBlankCursor() const; Cursor createBlankCursor() const;
// remove a timer without locking
void removeTimerNoLock(IJob*);
// process timers
bool processTimers();
// determine the clipboard from the X selection. returns // determine the clipboard from the X selection. returns
// kClipboardEnd if no such clipboard. // kClipboardEnd if no such clipboard.
ClipboardID getClipboardID(Atom selection) const; ClipboardID getClipboardID(Atom selection) const;
@ -125,40 +104,10 @@ private:
void destroyClipboardRequest(Window window); void destroyClipboardRequest(Window window);
// X I/O error handler // X I/O error handler
void onError();
static int ioErrorHandler(Display*); static int ioErrorHandler(Display*);
private: private:
// a timer priority queue element
class CTimer {
public:
CTimer(IJob* job, double startTime, double resetTime);
~CTimer();
// manipulators
void run();
void reset();
CTimer& operator-=(double);
// accessors
IJob* getJob() const
{
return m_job;
}
operator double() const;
bool operator<(const CTimer&) const;
private:
IJob* m_job;
double m_timeout;
double m_time;
double m_startTime;
};
class CKeyEventInfo { class CKeyEventInfo {
public: public:
int m_event; int m_event;
@ -167,9 +116,9 @@ private:
KeyCode m_keycode; KeyCode m_keycode;
}; };
bool isQuitEvent(XEvent*) const; Display* openDisplay() const;
void saveShape();
Window createWindow() const; Window openWindow() const;
void openIM(); void openIM();
bool grabMouseAndKeyboard(); bool grabMouseAndKeyboard();
@ -193,21 +142,13 @@ private:
static Bool findKeyEvent(Display*, XEvent* xevent, XPointer arg); static Bool findKeyEvent(Display*, XEvent* xevent, XPointer arg);
private: private:
typedef CPriorityQueue<CTimer> CTimerPriorityQueue;
// true if screen is being used as a primary screen, false otherwise // true if screen is being used as a primary screen, false otherwise
bool m_isPrimary; bool m_isPrimary;
// X is not thread safe
CMutex m_mutex;
Display* m_display; Display* m_display;
Window m_root; Window m_root;
Window m_window; Window m_window;
IScreenReceiver* m_receiver;
IPrimaryScreenReceiver* m_primaryReceiver;
// true if mouse has entered the screen // true if mouse has entered the screen
bool m_isOnScreen; bool m_isOnScreen;
@ -230,20 +171,11 @@ private:
// clipboards // clipboards
CXWindowsClipboard* m_clipboard[kClipboardEnd]; CXWindowsClipboard* m_clipboard[kClipboardEnd];
UInt32 m_sequenceNumber;
// the quit message
Atom m_atomQuit;
// screen saver stuff // screen saver stuff
CXWindowsScreenSaver* m_screensaver; CXWindowsScreenSaver* m_screensaver;
bool m_screensaverNotify; bool m_screensaverNotify;
Atom m_atomScreensaver;
// timers, the stopwatch used to time, and a mutex for the timers
CTimerPriorityQueue m_timers;
CStopwatch m_time;
CMutex m_timersMutex;
CTimer* m_oneShotTimer;
// logical to physical button mapping. m_buttons[i] gives the // logical to physical button mapping. m_buttons[i] gives the
// physical button for logical button i+1. // physical button for logical button i+1.

View File

@ -13,10 +13,12 @@
*/ */
#include "CXWindowsScreenSaver.h" #include "CXWindowsScreenSaver.h"
#include "CXWindowsScreen.h"
#include "CXWindowsUtil.h" #include "CXWindowsUtil.h"
#include "IPlatformScreen.h"
#include "CLog.h" #include "CLog.h"
#include "TMethodJob.h" #include "CEvent.h"
#include "IEventQueue.h"
#include "TMethodEventJob.h"
#include <X11/Xatom.h> #include <X11/Xatom.h>
#if defined(HAVE_X11_EXTENSIONS_XTEST_H) #if defined(HAVE_X11_EXTENSIONS_XTEST_H)
# include <X11/extensions/XTest.h> # include <X11/extensions/XTest.h>
@ -29,20 +31,16 @@
// //
CXWindowsScreenSaver::CXWindowsScreenSaver( CXWindowsScreenSaver::CXWindowsScreenSaver(
CXWindowsScreen* screen, Display* display) : Display* display, Window window, void* eventTarget) :
m_screen(screen),
m_display(display), m_display(display),
m_notify(None), m_xscreensaverSink(window),
m_eventTarget(eventTarget),
m_xscreensaver(None), m_xscreensaver(None),
m_xscreensaverActive(false), m_xscreensaverActive(false),
m_disabled(false), m_disabled(false),
m_suppressDisable(false), m_suppressDisable(false),
m_disableJobInstalled(false) m_disableTimer(NULL)
{ {
// screen saver disable callback
m_disableJob = new TMethodJob<CXWindowsScreenSaver>(this,
&CXWindowsScreenSaver::disableCallback);
// get atoms // get atoms
m_atomScreenSaver = XInternAtom(m_display, m_atomScreenSaver = XInternAtom(m_display,
"SCREENSAVER", False); "SCREENSAVER", False);
@ -52,24 +50,6 @@ CXWindowsScreenSaver::CXWindowsScreenSaver(
"ACTIVATE", False); "ACTIVATE", False);
m_atomScreenSaverDeactivate = XInternAtom(m_display, m_atomScreenSaverDeactivate = XInternAtom(m_display,
"DEACTIVATE", False); "DEACTIVATE", False);
m_atomSynergyScreenSaver = XInternAtom(m_display,
"SYNERGY_SCREENSAVER", False);
// create dummy window to receive xscreensaver responses. this
// shouldn't be necessary (we should be able to send responses
// to None) but it doesn't hurt.
XSetWindowAttributes attr;
attr.event_mask = 0;//PropertyChangeMask;
attr.do_not_propagate_mask = 0;
attr.override_redirect = True;
m_xscreensaverSink = XCreateWindow(m_display,
DefaultRootWindow(m_display),
0, 0, 1, 1, 0, 0,
InputOnly, CopyFromParent,
CWDontPropagate | CWEventMask |
CWOverrideRedirect,
&attr);
LOG((CLOG_DEBUG "xscreensaver sink window is 0x%08x", m_xscreensaverSink));
// watch top-level windows for changes // watch top-level windows for changes
{ {
@ -94,28 +74,39 @@ CXWindowsScreenSaver::CXWindowsScreenSaver(
// get the built-in settings // get the built-in settings
XGetScreenSaver(m_display, &m_timeout, &m_interval, XGetScreenSaver(m_display, &m_timeout, &m_interval,
&m_preferBlanking, &m_allowExposures); &m_preferBlanking, &m_allowExposures);
// install disable timer event handler
EVENTQUEUE->adoptHandler(CEvent::kTimer, this,
new TMethodEventJob<CXWindowsScreenSaver>(this,
&CXWindowsScreenSaver::handleDisableTimer));
} }
CXWindowsScreenSaver::~CXWindowsScreenSaver() CXWindowsScreenSaver::~CXWindowsScreenSaver()
{ {
// clear watch list
clearWatchForXScreenSaver();
// stop watching root for events
CXWindowsUtil::CErrorLock lock(m_display);
Window root = DefaultRootWindow(m_display);
XSelectInput(m_display, root, m_rootEventMask);
// destroy dummy sink window
XDestroyWindow(m_display, m_xscreensaverSink);
// done with disable job // done with disable job
m_screen->removeTimer(m_disableJob); if (m_disableTimer != NULL) {
delete m_disableJob; EVENTQUEUE->deleteTimer(m_disableTimer);
}
EVENTQUEUE->removeHandler(CEvent::kTimer, this);
if (m_display != NULL) {
XSetScreenSaver(m_display, m_timeout, m_interval,
m_preferBlanking, m_allowExposures);
clearWatchForXScreenSaver();
CXWindowsUtil::CErrorLock lock(m_display);
XSelectInput(m_display, DefaultRootWindow(m_display), m_rootEventMask);
}
}
void
CXWindowsScreenSaver::destroy()
{
m_display = NULL;
delete this;
} }
bool bool
CXWindowsScreenSaver::onPreDispatch(const XEvent* xevent) CXWindowsScreenSaver::handleXEvent(const XEvent* xevent)
{ {
switch (xevent->type) { switch (xevent->type) {
case CreateNotify: case CreateNotify:
@ -175,18 +166,12 @@ CXWindowsScreenSaver::onPreDispatch(const XEvent* xevent)
return false; return false;
} }
void
CXWindowsScreenSaver::setNotify(Window notify)
{
m_notify = notify;
}
void void
CXWindowsScreenSaver::enable() CXWindowsScreenSaver::enable()
{ {
// for xscreensaver // for xscreensaver
m_disabled = false; m_disabled = false;
updateDisableJob(); updateDisableTimer();
// for built-in X screen saver // for built-in X screen saver
XSetScreenSaver(m_display, m_timeout, m_interval, XSetScreenSaver(m_display, m_timeout, m_interval,
@ -198,7 +183,7 @@ CXWindowsScreenSaver::disable()
{ {
// for xscreensaver // for xscreensaver
m_disabled = true; m_disabled = true;
updateDisableJob(); updateDisableTimer();
// use built-in X screen saver // use built-in X screen saver
XGetScreenSaver(m_display, &m_timeout, &m_interval, XGetScreenSaver(m_display, &m_timeout, &m_interval,
@ -213,7 +198,7 @@ CXWindowsScreenSaver::activate()
{ {
// remove disable job timer // remove disable job timer
m_suppressDisable = true; m_suppressDisable = true;
updateDisableJob(); updateDisableTimer();
// try xscreensaver // try xscreensaver
findXScreenSaver(); findXScreenSaver();
@ -231,7 +216,7 @@ CXWindowsScreenSaver::deactivate()
{ {
// reinstall disable job timer // reinstall disable job timer
m_suppressDisable = false; m_suppressDisable = false;
updateDisableJob(); updateDisableTimer();
// try xscreensaver // try xscreensaver
findXScreenSaver(); findXScreenSaver();
@ -256,27 +241,6 @@ CXWindowsScreenSaver::isActive() const
return false; return false;
} }
void
CXWindowsScreenSaver::sendNotify(bool activated)
{
if (m_notify != None) {
XEvent event;
event.xclient.type = ClientMessage;
event.xclient.display = m_display;
event.xclient.window = m_notify;
event.xclient.message_type = m_atomSynergyScreenSaver;
event.xclient.format = 32;
event.xclient.data.l[0] = activated ? 1 : 0;
event.xclient.data.l[1] = 0;
event.xclient.data.l[2] = 0;
event.xclient.data.l[3] = 0;
event.xclient.data.l[4] = 0;
CXWindowsUtil::CErrorLock lock(m_display);
XSendEvent(m_display, m_notify, False, 0, &event);
}
}
bool bool
CXWindowsScreenSaver::findXScreenSaver() CXWindowsScreenSaver::findXScreenSaver()
{ {
@ -351,9 +315,18 @@ CXWindowsScreenSaver::setXScreenSaverActive(bool activated)
// from activating since that'll just pop up the password // from activating since that'll just pop up the password
// dialog if locking is enabled. // dialog if locking is enabled.
m_suppressDisable = activated; m_suppressDisable = activated;
updateDisableJob(); updateDisableTimer();
sendNotify(activated); if (activated) {
EVENTQUEUE->addEvent(CEvent(
IPlatformScreen::getScreensaverActivatedEvent(),
m_eventTarget));
}
else {
EVENTQUEUE->addEvent(CEvent(
IPlatformScreen::getScreensaverDeactivatedEvent(),
m_eventTarget));
}
} }
} }
@ -441,23 +414,20 @@ CXWindowsScreenSaver::addWatchXScreenSaver(Window window)
} }
void void
CXWindowsScreenSaver::updateDisableJob() CXWindowsScreenSaver::updateDisableTimer()
{ {
assert(m_disableJob != NULL); if (m_disabled && !m_suppressDisable && m_disableTimer == NULL) {
if (m_disabled && !m_suppressDisable && !m_disableJobInstalled) {
// 5 seconds should be plenty often to suppress the screen saver // 5 seconds should be plenty often to suppress the screen saver
m_disableJobInstalled = true; m_disableTimer = EVENTQUEUE->newTimer(5.0, this);
m_screen->addTimer(m_disableJob, 5.0);
} }
else if ((!m_disabled || m_suppressDisable) && m_disableJobInstalled) { else if ((!m_disabled || m_suppressDisable) && m_disableTimer != NULL) {
m_disableJobInstalled = false; EVENTQUEUE->deleteTimer(m_disableTimer);
m_screen->removeTimer(m_disableJob); m_disableTimer = NULL;
} }
} }
void void
CXWindowsScreenSaver::disableCallback(void*) CXWindowsScreenSaver::handleDisableTimer(const CEvent&, void*)
{ {
// send fake mouse motion directly to xscreensaver // send fake mouse motion directly to xscreensaver
if (m_xscreensaver != None) { if (m_xscreensaver != None) {

View File

@ -23,16 +23,13 @@
# include <X11/Xlib.h> # include <X11/Xlib.h>
#endif #endif
class IJob; class CEvent;
class CXWindowsScreen; class CEventQueueTimer;
//! X11 screen saver implementation //! X11 screen saver implementation
class CXWindowsScreenSaver : public IScreenSaver { class CXWindowsScreenSaver : public IScreenSaver {
public: public:
// note -- the caller must ensure that Display* passed to c'tor isn't CXWindowsScreenSaver(Display*, Window, void* eventTarget);
// being used in another call to Xlib when calling any method on this
// object (including during the c'tor and d'tor).
CXWindowsScreenSaver(CXWindowsScreen*, Display*);
virtual ~CXWindowsScreenSaver(); virtual ~CXWindowsScreenSaver();
//! @name manipulators //! @name manipulators
@ -40,22 +37,17 @@ public:
//! Event filtering //! Event filtering
/*! /*!
Called for each event before event translation and dispatch. Return Should be called for each system event before event translation and
true to skip translation and dispatch. Subclasses should call the dispatch. Returns true to skip translation and dispatch.
superclass's version first and return true if it returns true.
*/ */
bool onPreDispatch(const XEvent*); bool handleXEvent(const XEvent*);
//! Set notify target //! Destroy without the display
/*! /*!
Tells this object to send a ClientMessage to the given window Tells this object to delete itself without using the X11 display.
when the screen saver activates or deactivates. Only one window It may leak some resources as a result.
can be notified at a time. The message type is the "SCREENSAVER"
atom, the format is 32, and the data.l[0] member is non-zero
if activated, zero if deactivated. Pass None to disable
notification.
*/ */
void setNotify(Window); void destroy();
//@} //@}
@ -67,9 +59,6 @@ public:
virtual bool isActive() const; virtual bool isActive() const;
private: private:
// send a notification
void sendNotify(bool activated);
// find and set the running xscreensaver's window. returns true iff // find and set the running xscreensaver's window. returns true iff
// found. // found.
bool findXScreenSaver(); bool findXScreenSaver();
@ -98,25 +87,22 @@ private:
void addWatchXScreenSaver(Window window); void addWatchXScreenSaver(Window window);
// install/uninstall the job used to suppress the screensaver // install/uninstall the job used to suppress the screensaver
void updateDisableJob(); void updateDisableTimer();
// called periodically to prevent the screen saver from starting // called periodically to prevent the screen saver from starting
void disableCallback(void*); void handleDisableTimer(const CEvent&, void*);
private: private:
typedef std::map<Window, long> CWatchList; typedef std::map<Window, long> CWatchList;
// the event loop object
CXWindowsScreen* m_screen;
// the X display // the X display
Display* m_display; Display* m_display;
// old event mask on root window // window to receive xscreensaver repsonses
long m_rootEventMask; Window m_xscreensaverSink;
// window to notify on screen saver activation/deactivation // the target for the events we generate
Window m_notify; void* m_eventTarget;
// xscreensaver's window // xscreensaver's window
Window m_xscreensaver; Window m_xscreensaver;
@ -124,8 +110,8 @@ private:
// xscreensaver activation state // xscreensaver activation state
bool m_xscreensaverActive; bool m_xscreensaverActive;
// dummy window to receive xscreensaver repsonses // old event mask on root window
Window m_xscreensaverSink; long m_rootEventMask;
// potential xscreensaver windows being watched // potential xscreensaver windows being watched
CWatchList m_watchWindows; CWatchList m_watchWindows;
@ -135,7 +121,6 @@ private:
Atom m_atomScreenSaverVersion; Atom m_atomScreenSaverVersion;
Atom m_atomScreenSaverActivate; Atom m_atomScreenSaverActivate;
Atom m_atomScreenSaverDeactivate; Atom m_atomScreenSaverDeactivate;
Atom m_atomSynergyScreenSaver;
// built-in screen saver settings // built-in screen saver settings
int m_timeout; int m_timeout;
@ -151,11 +136,8 @@ private:
// to activate the screen saver even if disabled. // to activate the screen saver even if disabled.
bool m_suppressDisable; bool m_suppressDisable;
// true iff the disabled job timer is installed // the disable timer (NULL if not installed)
bool m_disableJobInstalled; CEventQueueTimer* m_disableTimer;
// the job used to invoke disableCallback
IJob* m_disableJob;
}; };
#endif #endif

View File

@ -49,7 +49,7 @@ libplatform_a_SOURCES = \
CXWindowsClipboardTextConverter.cpp \ CXWindowsClipboardTextConverter.cpp \
CXWindowsClipboardUCS2Converter.cpp \ CXWindowsClipboardUCS2Converter.cpp \
CXWindowsClipboardUTF8Converter.cpp \ CXWindowsClipboardUTF8Converter.cpp \
CXWindowsEventQueue.cpp \ CXWindowsEventQueueBuffer.cpp \
CXWindowsKeyMapper.cpp \ CXWindowsKeyMapper.cpp \
CXWindowsScreen.cpp \ CXWindowsScreen.cpp \
CXWindowsScreenSaver.cpp \ CXWindowsScreenSaver.cpp \
@ -58,7 +58,7 @@ libplatform_a_SOURCES = \
CXWindowsClipboardTextConverter.h \ CXWindowsClipboardTextConverter.h \
CXWindowsClipboardUCS2Converter.h \ CXWindowsClipboardUCS2Converter.h \
CXWindowsClipboardUTF8Converter.h \ CXWindowsClipboardUTF8Converter.h \
CXWindowsEventQueue.h \ CXWindowsEventQueueBuffer.h \
CXWindowsKeyMapper.h \ CXWindowsKeyMapper.h \
CXWindowsScreen.h \ CXWindowsScreen.h \
CXWindowsScreenSaver.h \ CXWindowsScreenSaver.h \

View File

@ -0,0 +1,189 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2004 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "CClientListener.h"
#include "CClientProxy.h"
#include "CClientProxyUnknown.h"
#include "CPacketStreamFilter.h"
#include "IStreamFilterFactory.h"
#include "IDataSocket.h"
#include "IListenSocket.h"
#include "ISocketFactory.h"
#include "XSocket.h"
#include "CLog.h"
#include "IEventQueue.h"
#include "TMethodEventJob.h"
//
// CClientListener
//
CEvent::Type CClientListener::s_connectedEvent = CEvent::kUnknown;
CClientListener::CClientListener(const CNetworkAddress& address,
ISocketFactory* socketFactory,
IStreamFilterFactory* streamFilterFactory) :
m_socketFactory(socketFactory),
m_streamFilterFactory(streamFilterFactory)
{
assert(m_socketFactory != NULL);
try {
// create listen socket
m_listen = m_socketFactory->createListen();
// bind listen address
LOG((CLOG_DEBUG1 "binding listen socket"));
m_listen->bind(address);
}
catch (XSocketAddressInUse& e) {
delete m_listen;
delete m_socketFactory;
delete m_streamFilterFactory;
throw;
}
catch (XBase& e) {
delete m_listen;
delete m_socketFactory;
delete m_streamFilterFactory;
throw;
}
LOG((CLOG_DEBUG1 "listening for clients"));
// setup event handler
EVENTQUEUE->adoptHandler(IListenSocket::getConnectingEvent(), m_listen,
new TMethodEventJob<CClientListener>(this,
&CClientListener::handleClientConnecting));
}
CClientListener::~CClientListener()
{
LOG((CLOG_DEBUG1 "stop listening for clients"));
// discard already connected clients
for (CNewClients::iterator index = m_newClients.begin();
index != m_newClients.end(); ++index) {
CClientProxyUnknown* client = *index;
EVENTQUEUE->removeHandler(client);
delete client;
}
// discard waiting clients
CClientProxy* client = getNextClient();
while (client != NULL) {
delete client;
client = getNextClient();
}
EVENTQUEUE->removeHandler(IListenSocket::getConnectingEvent(), m_listen);
delete m_listen;
delete m_socketFactory;
delete m_streamFilterFactory;
}
CClientProxy*
CClientListener::getNextClient()
{
CClientProxy* client = NULL;
if (!m_waitingClients.empty()) {
client = m_waitingClients.front();
m_waitingClients.pop_front();
EVENTQUEUE->removeHandler(CClientProxy::getDisconnectedEvent(), client);
}
return client;
}
CEvent::Type
CClientListener::getConnectedEvent()
{
return CEvent::registerTypeOnce(s_connectedEvent,
"CClientListener::connected");
}
void
CClientListener::handleClientConnecting(const CEvent&, void*)
{
// accept client connection
IStream* stream = m_listen->accept();
if (stream == NULL) {
return;
}
LOG((CLOG_NOTE "accepted client connection"));
// filter socket messages, including a packetizing filter
if (m_streamFilterFactory != NULL) {
stream = m_streamFilterFactory->create(stream, true);
}
stream = new CPacketStreamFilter(stream, true);
// create proxy for unknown client
CClientProxyUnknown* client = new CClientProxyUnknown(stream, 30.0);
m_newClients.insert(client);
// watch for events from unknown client
EVENTQUEUE->adoptHandler(CClientProxyUnknown::getSuccessEvent(), client,
new TMethodEventJob<CClientListener>(this,
&CClientListener::handleUnknownClient, client));
EVENTQUEUE->adoptHandler(CClientProxyUnknown::getFailureEvent(), client,
new TMethodEventJob<CClientListener>(this,
&CClientListener::handleUnknownClient, client));
}
void
CClientListener::handleUnknownClient(const CEvent&, void* vclient)
{
CClientProxyUnknown* unknownClient =
reinterpret_cast<CClientProxyUnknown*>(vclient);
// we should have the client in our new client list
assert(m_newClients.count(unknownClient) == 1);
// get the real client proxy and install it
CClientProxy* client = unknownClient->orphanClientProxy();
if (client != NULL) {
// handshake was successful
m_waitingClients.push_back(client);
EVENTQUEUE->addEvent(CEvent(getConnectedEvent(), this));
// watch for client to disconnect while it's in our queue
EVENTQUEUE->adoptHandler(CClientProxy::getDisconnectedEvent(), client,
new TMethodEventJob<CClientListener>(this,
&CClientListener::handleClientDisconnected,
client));
}
// now finished with unknown client
EVENTQUEUE->removeHandler(CClientProxyUnknown::getSuccessEvent(), client);
EVENTQUEUE->removeHandler(CClientProxyUnknown::getFailureEvent(), client);
m_newClients.erase(unknownClient);
delete unknownClient;
}
void
CClientListener::handleClientDisconnected(const CEvent&, void* vclient)
{
CClientProxy* client = reinterpret_cast<CClientProxy*>(vclient);
// find client in waiting clients queue
for (CWaitingClients::iterator i = m_waitingClients.begin(),
n = m_waitingClients.end(); i != n; ++i) {
if (*i == client) {
m_waitingClients.erase(i);
EVENTQUEUE->removeHandler(CClientProxy::getDisconnectedEvent(),
client);
delete client;
break;
}
}
}

View File

@ -0,0 +1,76 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2004 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef CCLIENTLISTENER_H
#define CCLIENTLISTENER_H
#include "CConfig.h"
#include "CEvent.h"
#include "stddeque.h"
#include "stdset.h"
class CClientProxy;
class CClientProxyUnknown;
class CNetworkAddress;
class IListenSocket;
class ISocketFactory;
class IStreamFilterFactory;
class CClientListener {
public:
// The factories are adopted.
CClientListener(const CNetworkAddress&,
ISocketFactory*, IStreamFilterFactory*);
~CClientListener();
//! @name accessors
//@{
//! Get next connected client
/*!
Returns the next connected client and removes it from the internal
list. The client is responsible for deleting the returned client.
Returns NULL if no clients are available.
*/
CClientProxy* getNextClient();
//! Get connected event type
/*!
Returns the connected event type. This is sent whenever a
a client connects.
*/
static CEvent::Type getConnectedEvent();
//@}
private:
// client connection event handlers
void handleClientConnecting(const CEvent&, void*);
void handleUnknownClient(const CEvent&, void*);
void handleClientDisconnected(const CEvent&, void*);
private:
typedef std::set<CClientProxyUnknown*> CNewClients;
typedef std::deque<CClientProxy*> CWaitingClients;
IListenSocket* m_listen;
ISocketFactory* m_socketFactory;
IStreamFilterFactory* m_streamFilterFactory;
CNewClients m_newClients;
CWaitingClients m_waitingClients;
static CEvent::Type s_connectedEvent;
};
#endif

View File

@ -13,15 +13,18 @@
*/ */
#include "CClientProxy.h" #include "CClientProxy.h"
#include "CProtocolUtil.h"
#include "IStream.h" #include "IStream.h"
#include "CLog.h"
// //
// CClientProxy // CClientProxy
// //
CClientProxy::CClientProxy(IServer* server, CEvent::Type CClientProxy::s_readyEvent = CEvent::kUnknown;
const CString& name, IStream* stream) : CEvent::Type CClientProxy::s_disconnectedEvent = CEvent::kUnknown;
m_server(server),
CClientProxy::CClientProxy(const CString& name, IStream* stream) :
m_name(name), m_name(name),
m_stream(stream) m_stream(stream)
{ {
@ -33,10 +36,14 @@ CClientProxy::~CClientProxy()
delete m_stream; delete m_stream;
} }
IServer* void
CClientProxy::getServer() const CClientProxy::close(const char* msg)
{ {
return m_server; LOG((CLOG_DEBUG1 "send close \"%s\" to \"%s\"", msg, getName().c_str()));
CProtocolUtil::writef(getStream(), msg);
// force the close to be sent before we return
getStream()->flush();
} }
IStream* IStream*
@ -51,8 +58,22 @@ CClientProxy::getName() const
return m_name; return m_name;
} }
const CMutex* CEvent::Type
CClientProxy::getMutex() const CClientProxy::getReadyEvent()
{ {
return &m_mutex; return CEvent::registerTypeOnce(s_readyEvent,
"CClientProxy::ready");
}
CEvent::Type
CClientProxy::getDisconnectedEvent()
{
return CEvent::registerTypeOnce(s_disconnectedEvent,
"CClientProxy::disconnected");
}
void*
CClientProxy::getEventTarget() const
{
return static_cast<IScreen*>(const_cast<CClientProxy*>(this));
} }

View File

@ -16,11 +16,10 @@
#define CCLIENTPROXY_H #define CCLIENTPROXY_H
#include "IClient.h" #include "IClient.h"
#include "CMutex.h" #include "CEvent.h"
#include "CString.h" #include "CString.h"
class IStream; class IStream;
class IServer;
//! Generic proxy for client //! Generic proxy for client
class CClientProxy : public IClient { class CClientProxy : public IClient {
@ -28,17 +27,21 @@ public:
/*! /*!
\c name is the name of the client. \c name is the name of the client.
*/ */
CClientProxy(IServer* server, const CString& name, IStream* adoptedStream); CClientProxy(const CString& name, IStream* adoptedStream);
~CClientProxy(); ~CClientProxy();
//! @name accessors //! @name manipulators
//@{ //@{
//! Get server //! Disconnect
/*! /*!
Returns the server passed to the c'tor. Ask the client to disconnect, using \p msg as the reason.
*/ */
IServer* getServer() const; void close(const char* msg);
//@}
//! @name accessors
//@{
//! Get stream //! Get stream
/*! /*!
@ -46,12 +49,31 @@ public:
*/ */
IStream* getStream() const; IStream* getStream() const;
//! Get ready event type
/*!
Returns the ready event type. This is sent when the client has
completed the initial handshake. Until it is sent, the client is
not fully connected.
*/
static CEvent::Type getReadyEvent();
//! Get disconnect event type
/*!
Returns the disconnect event type. This is sent when the client
disconnects or is disconnected. The target is getEventTarget().
*/
static CEvent::Type getDisconnectedEvent();
//@} //@}
// IScreen
virtual void* getEventTarget() const;
virtual bool getClipboard(ClipboardID id, IClipboard*) const = 0;
virtual void getShape(SInt32& x, SInt32& y,
SInt32& width, SInt32& height) const = 0;
virtual void getCursorPos(SInt32& x, SInt32& y) const = 0;
// IClient overrides // IClient overrides
virtual void open() = 0;
virtual void mainLoop() = 0;
virtual void close() = 0;
virtual void enter(SInt32 xAbs, SInt32 yAbs, virtual void enter(SInt32 xAbs, SInt32 yAbs,
UInt32 seqNum, KeyModifierMask mask, UInt32 seqNum, KeyModifierMask mask,
bool forScreensaver) = 0; bool forScreensaver) = 0;
@ -71,25 +93,13 @@ public:
virtual void resetOptions() = 0; virtual void resetOptions() = 0;
virtual void setOptions(const COptionsList& options) = 0; virtual void setOptions(const COptionsList& options) = 0;
virtual CString getName() const; virtual CString getName() const;
virtual SInt32 getJumpZoneSize() const = 0;
virtual void getShape(SInt32& x, SInt32& y,
SInt32& width, SInt32& height) const = 0;
virtual void getCursorPos(SInt32& x, SInt32& y) const = 0;
virtual void getCursorCenter(SInt32& x, SInt32& y) const = 0;
protected:
//! Get mutex
/*!
Returns the mutex for this object. Subclasses should use this
mutex to protect their data.
*/
const CMutex* getMutex() const;
private: private:
CMutex m_mutex;
IServer* m_server;
CString m_name; CString m_name;
IStream* m_stream; IStream* m_stream;
static CEvent::Type s_readyEvent;
static CEvent::Type s_disconnectedEvent;
}; };
#endif #endif

View File

@ -13,12 +13,9 @@
*/ */
#include "CClientProxy1_0.h" #include "CClientProxy1_0.h"
#include "CServer.h"
#include "CClipboard.h"
#include "CProtocolUtil.h" #include "CProtocolUtil.h"
#include "XSynergy.h" #include "XSynergy.h"
#include "IStream.h" #include "IStream.h"
#include "CLock.h"
#include "CLog.h" #include "CLog.h"
#include "IEventQueue.h" #include "IEventQueue.h"
#include "TMethodEventJob.h" #include "TMethodEventJob.h"
@ -28,16 +25,12 @@
// CClientProxy1_0 // CClientProxy1_0
// //
CClientProxy1_0::CClientProxy1_0(IServer* server, CClientProxy1_0::CClientProxy1_0(const CString& name, IStream* stream) :
const CString& name, IStream* stream) : CClientProxy(name, stream),
CClientProxy(server, name, stream),
m_heartbeatAlarm(kHeartRate * kHeartBeatsUntilDeath), m_heartbeatAlarm(kHeartRate * kHeartBeatsUntilDeath),
m_heartbeatTimer(NULL) m_heartbeatTimer(NULL),
m_parser(&CClientProxy1_0::parseHandshakeMessage)
{ {
for (UInt32 i = 0; i < kClipboardEnd; ++i) {
m_clipboardDirty[i] = true;
}
// install event handlers // install event handlers
EVENTQUEUE->adoptHandler(IStream::getInputReadyEvent(), EVENTQUEUE->adoptHandler(IStream::getInputReadyEvent(),
stream->getEventTarget(), stream->getEventTarget(),
@ -59,7 +52,8 @@ CClientProxy1_0::CClientProxy1_0(IServer* server,
new TMethodEventJob<CClientProxy1_0>(this, new TMethodEventJob<CClientProxy1_0>(this,
&CClientProxy1_0::handleFlatline, NULL)); &CClientProxy1_0::handleFlatline, NULL));
// FIXME -- open() replacement must install initial heartbeat timer LOG((CLOG_DEBUG1 "querying client \"%s\" info", getName().c_str()));
CProtocolUtil::writef(getStream(), kMsgQInfo);
} }
CClientProxy1_0::~CClientProxy1_0() CClientProxy1_0::~CClientProxy1_0()
@ -70,11 +64,9 @@ CClientProxy1_0::~CClientProxy1_0()
void void
CClientProxy1_0::disconnect() CClientProxy1_0::disconnect()
{ {
CLock lock(getMutex());
removeHandlers(); removeHandlers();
// FIXME -- send disconnect event (server should be listening for this)
getStream()->flush();
getStream()->close(); getStream()->close();
EVENTQUEUE->addEvent(CEvent(getDisconnectedEvent(), getEventTarget()));
} }
void void
@ -98,7 +90,6 @@ CClientProxy1_0::removeHandlers()
void void
CClientProxy1_0::addHeartbeatTimer() CClientProxy1_0::addHeartbeatTimer()
{ {
CLock lock(getMutex());
if (m_heartbeatAlarm > 0.0) { if (m_heartbeatAlarm > 0.0) {
m_heartbeatTimer = EVENTQUEUE->newOneShotTimer(m_heartbeatAlarm, this); m_heartbeatTimer = EVENTQUEUE->newOneShotTimer(m_heartbeatAlarm, this);
} }
@ -107,7 +98,6 @@ CClientProxy1_0::addHeartbeatTimer()
void void
CClientProxy1_0::removeHeartbeatTimer() CClientProxy1_0::removeHeartbeatTimer()
{ {
CLock lock(getMutex());
if (m_heartbeatTimer != NULL) { if (m_heartbeatTimer != NULL) {
EVENTQUEUE->deleteTimer(m_heartbeatTimer); EVENTQUEUE->deleteTimer(m_heartbeatTimer);
m_heartbeatTimer = NULL; m_heartbeatTimer = NULL;
@ -130,7 +120,7 @@ CClientProxy1_0::handleData(const CEvent&, void*)
// parse message // parse message
LOG((CLOG_DEBUG2 "msg from \"%s\": %c%c%c%c", getName().c_str(), code[0], code[1], code[2], code[3])); LOG((CLOG_DEBUG2 "msg from \"%s\": %c%c%c%c", getName().c_str(), code[0], code[1], code[2], code[3]));
if (!parseMessage(code)) { if (!(this->*m_parser)(code)) {
LOG((CLOG_ERR "invalid message from client \"%s\"", getName().c_str())); LOG((CLOG_ERR "invalid message from client \"%s\"", getName().c_str()));
disconnect(); disconnect();
return; return;
@ -145,11 +135,35 @@ CClientProxy1_0::handleData(const CEvent&, void*)
addHeartbeatTimer(); addHeartbeatTimer();
} }
bool
CClientProxy1_0::parseHandshakeMessage(const UInt8* code)
{
if (memcmp(code, kMsgCNoop, 4) == 0) {
// discard no-ops
LOG((CLOG_DEBUG2 "no-op from", getName().c_str()));
return true;
}
else if (memcmp(code, kMsgDInfo, 4) == 0) {
// future messages get parsed by parseMessage
m_parser = &CClientProxy1_0::parseMessage;
if (recvInfo()) {
EVENTQUEUE->addEvent(CEvent(getReadyEvent(), getEventTarget()));
return true;
}
}
return false;
}
bool bool
CClientProxy1_0::parseMessage(const UInt8* code) CClientProxy1_0::parseMessage(const UInt8* code)
{ {
if (memcmp(code, kMsgDInfo, 4) == 0) { if (memcmp(code, kMsgDInfo, 4) == 0) {
return recvInfo(true); if (recvInfo()) {
EVENTQUEUE->addEvent(
CEvent(getShapeChangedEvent(), getEventTarget()));
return true;
}
return false;
} }
else if (memcmp(code, kMsgCNoop, 4) == 0) { else if (memcmp(code, kMsgCNoop, 4) == 0) {
// discard no-ops // discard no-ops
@ -168,14 +182,14 @@ CClientProxy1_0::parseMessage(const UInt8* code)
void void
CClientProxy1_0::handleDisconnect(const CEvent&, void*) CClientProxy1_0::handleDisconnect(const CEvent&, void*)
{ {
LOG((CLOG_NOTE "client \"%s\" disconnected", getName().c_str())); LOG((CLOG_NOTE "client \"%s\" has disconnected", getName().c_str()));
disconnect(); disconnect();
} }
void void
CClientProxy1_0::handleWriteError(const CEvent&, void*) CClientProxy1_0::handleWriteError(const CEvent&, void*)
{ {
LOG((CLOG_ERR "error writing to client \"%s\"", getName().c_str())); LOG((CLOG_WARN "error writing to client \"%s\"", getName().c_str()));
disconnect(); disconnect();
} }
@ -187,44 +201,28 @@ CClientProxy1_0::handleFlatline(const CEvent&, void*)
disconnect(); disconnect();
} }
// FIXME -- replace this bool
void CClientProxy1_0::getClipboard(ClipboardID id, IClipboard* clipboard) const
CClientProxy1_0::open()
{ {
// send request CClipboard::copy(clipboard, &m_clipboard[id].m_clipboard);
LOG((CLOG_DEBUG1 "querying client \"%s\" info", getName().c_str())); return true;
CProtocolUtil::writef(getStream(), kMsgQInfo);
getStream()->flush();
// wait for and verify reply
UInt8 code[4];
for (;;) {
UInt32 n = getStream()->read(code, 4);
if (n == 4) {
if (memcmp(code, kMsgCNoop, 4) == 0) {
// discard heartbeats
continue;
}
if (memcmp(code, kMsgDInfo, 4) == 0) {
break;
}
}
throw XBadClient();
}
// handle reply
recvInfo(false);
} }
// FIXME -- replace this
void void
CClientProxy1_0::close() CClientProxy1_0::getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) const
{ {
LOG((CLOG_DEBUG1 "send close to \"%s\"", getName().c_str())); x = m_info.m_x;
CProtocolUtil::writef(getStream(), kMsgCClose); y = m_info.m_y;
w = m_info.m_w;
h = m_info.m_h;
}
// force the close to be sent before we return void
getStream()->flush(); CClientProxy1_0::getCursorPos(SInt32& x, SInt32& y) const
{
assert(0 && "shouldn't be called");
x = m_info.m_mx;
y = m_info.m_my;
} }
void void
@ -250,10 +248,9 @@ void
CClientProxy1_0::setClipboard(ClipboardID id, const CString& data) CClientProxy1_0::setClipboard(ClipboardID id, const CString& data)
{ {
// ignore if this clipboard is already clean // ignore if this clipboard is already clean
CLock lock(getMutex()); if (m_clipboard[id].m_dirty) {
if (m_clipboardDirty[id]) {
// this clipboard is now clean // this clipboard is now clean
m_clipboardDirty[id] = false; m_clipboard[id].m_dirty = false;
LOG((CLOG_DEBUG "send clipboard %d to \"%s\" size=%d", id, getName().c_str(), data.size())); LOG((CLOG_DEBUG "send clipboard %d to \"%s\" size=%d", id, getName().c_str(), data.size()));
CProtocolUtil::writef(getStream(), kMsgDClipboard, id, 0, &data); CProtocolUtil::writef(getStream(), kMsgDClipboard, id, 0, &data);
@ -267,15 +264,13 @@ CClientProxy1_0::grabClipboard(ClipboardID id)
CProtocolUtil::writef(getStream(), kMsgCClipboard, id, 0); CProtocolUtil::writef(getStream(), kMsgCClipboard, id, 0);
// this clipboard is now dirty // this clipboard is now dirty
CLock lock(getMutex()); m_clipboard[id].m_dirty = true;
m_clipboardDirty[id] = true;
} }
void void
CClientProxy1_0::setClipboardDirty(ClipboardID id, bool dirty) CClientProxy1_0::setClipboardDirty(ClipboardID id, bool dirty)
{ {
CLock lock(getMutex()); m_clipboard[id].m_dirty = dirty;
m_clipboardDirty[id] = dirty;
} }
void void
@ -342,7 +337,6 @@ CClientProxy1_0::resetOptions()
CProtocolUtil::writef(getStream(), kMsgCResetOptions); CProtocolUtil::writef(getStream(), kMsgCResetOptions);
// reset heart rate and death // reset heart rate and death
CLock lock(getMutex());
m_heartbeatAlarm = kHeartRate * kHeartBeatsUntilDeath; m_heartbeatAlarm = kHeartRate * kHeartBeatsUntilDeath;
removeHeartbeatTimer(); removeHeartbeatTimer();
addHeartbeatTimer(); addHeartbeatTimer();
@ -355,7 +349,6 @@ CClientProxy1_0::setOptions(const COptionsList& options)
CProtocolUtil::writef(getStream(), kMsgDSetOptions, &options); CProtocolUtil::writef(getStream(), kMsgDSetOptions, &options);
// check options // check options
CLock lock(getMutex());
for (UInt32 i = 0, n = options.size(); i < n; i += 2) { for (UInt32 i = 0, n = options.size(); i < n; i += 2) {
if (options[i] == kOptionHeartbeat) { if (options[i] == kOptionHeartbeat) {
double rate = 1.0e-3 * static_cast<double>(options[i + 1]); double rate = 1.0e-3 * static_cast<double>(options[i + 1]);
@ -369,73 +362,33 @@ CClientProxy1_0::setOptions(const COptionsList& options)
} }
} }
SInt32
CClientProxy1_0::getJumpZoneSize() const
{
CLock lock(getMutex());
return m_info.m_zoneSize;
}
void
CClientProxy1_0::getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) const
{
CLock lock(getMutex());
x = m_info.m_x;
y = m_info.m_y;
w = m_info.m_w;
h = m_info.m_h;
}
void
CClientProxy1_0::getCursorPos(SInt32&, SInt32&) const
{
assert(0 && "shouldn't be called");
}
void
CClientProxy1_0::getCursorCenter(SInt32& x, SInt32& y) const
{
CLock lock(getMutex());
x = m_info.m_mx;
y = m_info.m_my;
}
bool bool
CClientProxy1_0::recvInfo(bool notify) CClientProxy1_0::recvInfo()
{ {
{ // parse the message
CLock lock(getMutex()); SInt16 x, y, w, h, zoneSize, mx, my;
if (!CProtocolUtil::readf(getStream(), kMsgDInfo + 4,
&x, &y, &w, &h, &zoneSize, &mx, &my)) {
return false;
}
LOG((CLOG_DEBUG "received client \"%s\" info shape=%d,%d %dx%d, zone=%d, pos=%d,%d", getName().c_str(), x, y, w, h, zoneSize, mx, my));
// parse the message // validate
SInt16 x, y, w, h, zoneSize, mx, my; if (w <= 0 || h <= 0 || zoneSize < 0) {
if (!CProtocolUtil::readf(getStream(), kMsgDInfo + 4, return false;
&x, &y, &w, &h, &zoneSize, &mx, &my)) { }
return false; if (mx < x || my < y || mx >= x + w || my >= y + h) {
} return false;
LOG((CLOG_DEBUG "received client \"%s\" info shape=%d,%d %dx%d, zone=%d, pos=%d,%d", getName().c_str(), x, y, w, h, zoneSize, mx, my));
// validate
if (w <= 0 || h <= 0 || zoneSize < 0) {
return false;
}
if (mx < x || my < y || mx >= x + w || my >= y + h) {
return false;
}
// save
m_info.m_x = x;
m_info.m_y = y;
m_info.m_w = w;
m_info.m_h = h;
m_info.m_zoneSize = zoneSize;
m_info.m_mx = mx;
m_info.m_my = my;
} }
// tell server of change // save
if (notify) { m_info.m_x = x;
getServer()->onInfoChanged(getName(), m_info); m_info.m_y = y;
} m_info.m_w = w;
m_info.m_h = h;
m_info.m_zoneSize = zoneSize;
m_info.m_mx = mx;
m_info.m_my = my;
// acknowledge receipt // acknowledge receipt
LOG((CLOG_DEBUG1 "send info ack to \"%s\"", getName().c_str())); LOG((CLOG_DEBUG1 "send info ack to \"%s\"", getName().c_str()));
@ -461,9 +414,17 @@ CClientProxy1_0::recvClipboard()
return false; return false;
} }
// send update. this calls us back to reset our clipboard dirty flag // save clipboard
// so don't hold a lock during the call. m_clipboard[id].m_clipboard.unmarshall(data, 0);
getServer()->onClipboardChanged(id, seqNum, data); m_clipboard[id].m_sequenceNumber = seqNum;
// notify
CClipboardInfo* info = new CClipboardInfo;
info->m_id = id;
info->m_sequenceNumber = seqNum;
EVENTQUEUE->addEvent(CEvent(getClipboardChangedEvent(),
getEventTarget(), info));
return true; return true;
} }
@ -483,8 +444,25 @@ CClientProxy1_0::recvGrabClipboard()
return false; return false;
} }
// send update. this calls us back to reset our clipboard dirty flag // notify
// so don't hold a lock during the call. CClipboardInfo* info = new CClipboardInfo;
getServer()->onGrabClipboard(getName(), id, seqNum); info->m_id = id;
info->m_sequenceNumber = seqNum;
EVENTQUEUE->addEvent(CEvent(getClipboardGrabbedEvent(),
getEventTarget(), info));
return true; return true;
} }
//
// CClientProxy1_0::CClientClipboard
//
CClientProxy1_0::CClientClipboard::CClientClipboard() :
m_clipboard(),
m_sequenceNumber(0),
m_dirty(true)
{
// do nothing
}

View File

@ -16,6 +16,7 @@
#define CCLIENTPROXY1_0_H #define CCLIENTPROXY1_0_H
#include "CClientProxy.h" #include "CClientProxy.h"
#include "CClipboard.h"
#include "ProtocolTypes.h" #include "ProtocolTypes.h"
class CEvent; class CEvent;
@ -24,14 +25,16 @@ class CEventQueueTimer;
//! Proxy for client implementing protocol version 1.0 //! Proxy for client implementing protocol version 1.0
class CClientProxy1_0 : public CClientProxy { class CClientProxy1_0 : public CClientProxy {
public: public:
CClientProxy1_0(IServer* server, const CString& name, CClientProxy1_0(const CString& name, IStream* adoptedStream);
IStream* adoptedStream);
~CClientProxy1_0(); ~CClientProxy1_0();
// IScreen
virtual bool getClipboard(ClipboardID id, IClipboard*) const;
virtual void getShape(SInt32& x, SInt32& y,
SInt32& width, SInt32& height) const;
virtual void getCursorPos(SInt32& x, SInt32& y) const;
// IClient overrides // IClient overrides
virtual void open();
virtual void mainLoop();
virtual void close();
virtual void enter(SInt32 xAbs, SInt32 yAbs, virtual void enter(SInt32 xAbs, SInt32 yAbs,
UInt32 seqNum, KeyModifierMask mask, UInt32 seqNum, KeyModifierMask mask,
bool forScreensaver); bool forScreensaver);
@ -50,13 +53,9 @@ public:
virtual void screensaver(bool activate); virtual void screensaver(bool activate);
virtual void resetOptions(); virtual void resetOptions();
virtual void setOptions(const COptionsList& options); virtual void setOptions(const COptionsList& options);
virtual SInt32 getJumpZoneSize() const;
virtual void getShape(SInt32& x, SInt32& y,
SInt32& width, SInt32& height) const;
virtual void getCursorPos(SInt32& x, SInt32& y) const;
virtual void getCursorCenter(SInt32& x, SInt32& y) const;
protected: protected:
virtual bool parseHandshakeMessage(const UInt8* code);
virtual bool parseMessage(const UInt8* code); virtual bool parseMessage(const UInt8* code);
private: private:
@ -70,15 +69,27 @@ private:
void handleWriteError(const CEvent&, void*); void handleWriteError(const CEvent&, void*);
void handleFlatline(const CEvent&, void*); void handleFlatline(const CEvent&, void*);
bool recvInfo(bool notify); bool recvInfo();
bool recvClipboard(); bool recvClipboard();
bool recvGrabClipboard(); bool recvGrabClipboard();
private: private:
typedef bool (CClientProxy1_0::*MessageParser)(const UInt8*);
struct CClientClipboard {
public:
CClientClipboard();
public:
CClipboard m_clipboard;
UInt32 m_sequenceNumber;
bool m_dirty;
};
CClientInfo m_info; CClientInfo m_info;
bool m_clipboardDirty[kClipboardEnd]; CClientClipboard m_clipboard[kClipboardEnd];
double m_heartbeatAlarm; double m_heartbeatAlarm;
CEventQueueTimer* m_heartbeatTimer; CEventQueueTimer* m_heartbeatTimer;
MessageParser m_parser;
}; };
#endif #endif

View File

@ -21,9 +21,8 @@
// CClientProxy1_1 // CClientProxy1_1
// //
CClientProxy1_1::CClientProxy1_1(IServer* server, CClientProxy1_1::CClientProxy1_1(const CString& name, IStream* stream) :
const CString& name, IStream* stream) : CClientProxy1_0(name, stream)
CClientProxy1_0(server, name, stream)
{ {
// do nothing // do nothing
} }

View File

@ -20,8 +20,7 @@
//! Proxy for client implementing protocol version 1.1 //! Proxy for client implementing protocol version 1.1
class CClientProxy1_1 : public CClientProxy1_0 { class CClientProxy1_1 : public CClientProxy1_0 {
public: public:
CClientProxy1_1(IServer* server, const CString& name, CClientProxy1_1(const CString& name, IStream* adoptedStream);
IStream* adoptedStream);
~CClientProxy1_1(); ~CClientProxy1_1();
// IClient overrides // IClient overrides

View File

@ -0,0 +1,277 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2004 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "CClientProxyUnknown.h"
#include "CClientProxy1_0.h"
#include "CClientProxy1_1.h"
#include "ProtocolTypes.h"
#include "CProtocolUtil.h"
#include "XSynergy.h"
#include "IStream.h"
#include "XIO.h"
#include "CLog.h"
#include "CString.h"
#include "IEventQueue.h"
#include "TMethodEventJob.h"
//
// CClientProxyUnknown
//
CEvent::Type CClientProxyUnknown::s_successEvent = CEvent::kUnknown;
CEvent::Type CClientProxyUnknown::s_failureEvent = CEvent::kUnknown;
CClientProxyUnknown::CClientProxyUnknown(IStream* stream, double timeout) :
m_stream(stream),
m_proxy(NULL),
m_ready(false)
{
EVENTQUEUE->adoptHandler(CEvent::kTimer, this,
new TMethodEventJob<CClientProxyUnknown>(this,
&CClientProxyUnknown::handleTimeout, NULL));
m_timer = EVENTQUEUE->newOneShotTimer(timeout, this);
addStreamHandlers();
LOG((CLOG_DEBUG1 "saying hello"));
CProtocolUtil::writef(m_stream, kMsgHello,
kProtocolMajorVersion,
kProtocolMinorVersion);
}
CClientProxyUnknown::~CClientProxyUnknown()
{
removeHandlers();
removeTimer();
delete m_stream;
delete m_proxy;
}
CClientProxy*
CClientProxyUnknown::orphanClientProxy()
{
if (m_ready) {
removeHandlers();
CClientProxy* proxy = m_proxy;
m_proxy = NULL;
return proxy;
}
else {
return NULL;
}
}
CEvent::Type
CClientProxyUnknown::getSuccessEvent()
{
return CEvent::registerTypeOnce(s_successEvent,
"CClientProxy::success");
}
CEvent::Type
CClientProxyUnknown::getFailureEvent()
{
return CEvent::registerTypeOnce(s_failureEvent,
"CClientProxy::failure");
}
void
CClientProxyUnknown::sendSuccess()
{
m_ready = true;
removeTimer();
EVENTQUEUE->addEvent(CEvent(getSuccessEvent(), this));
}
void
CClientProxyUnknown::sendFailure()
{
delete m_proxy;
m_proxy = NULL;
m_ready = false;
removeHandlers();
removeTimer();
EVENTQUEUE->addEvent(CEvent(getFailureEvent(), this));
}
void
CClientProxyUnknown::addStreamHandlers()
{
assert(m_stream != NULL);
EVENTQUEUE->adoptHandler(IStream::getInputReadyEvent(),
m_stream->getEventTarget(),
new TMethodEventJob<CClientProxyUnknown>(this,
&CClientProxyUnknown::handleData));
EVENTQUEUE->adoptHandler(IStream::getOutputErrorEvent(),
m_stream->getEventTarget(),
new TMethodEventJob<CClientProxyUnknown>(this,
&CClientProxyUnknown::handleWriteError));
EVENTQUEUE->adoptHandler(IStream::getInputShutdownEvent(),
m_stream->getEventTarget(),
new TMethodEventJob<CClientProxyUnknown>(this,
&CClientProxyUnknown::handleDisconnect));
EVENTQUEUE->adoptHandler(IStream::getOutputShutdownEvent(),
m_stream->getEventTarget(),
new TMethodEventJob<CClientProxyUnknown>(this,
&CClientProxyUnknown::handleWriteError));
}
void
CClientProxyUnknown::addProxyHandlers()
{
assert(m_proxy != NULL);
EVENTQUEUE->adoptHandler(CClientProxy::getReadyEvent(),
m_proxy,
new TMethodEventJob<CClientProxyUnknown>(this,
&CClientProxyUnknown::handleReady));
EVENTQUEUE->adoptHandler(CClientProxy::getDisconnectedEvent(),
m_proxy,
new TMethodEventJob<CClientProxyUnknown>(this,
&CClientProxyUnknown::handleDisconnect));
}
void
CClientProxyUnknown::removeHandlers()
{
if (m_stream != NULL) {
EVENTQUEUE->removeHandler(IStream::getInputReadyEvent(),
m_stream->getEventTarget());
EVENTQUEUE->removeHandler(IStream::getOutputErrorEvent(),
m_stream->getEventTarget());
EVENTQUEUE->removeHandler(IStream::getInputShutdownEvent(),
m_stream->getEventTarget());
EVENTQUEUE->removeHandler(IStream::getOutputShutdownEvent(),
m_stream->getEventTarget());
}
if (m_proxy != NULL) {
EVENTQUEUE->removeHandler(CClientProxy::getReadyEvent(),
m_proxy);
EVENTQUEUE->removeHandler(CClientProxy::getDisconnectedEvent(),
m_proxy);
}
}
void
CClientProxyUnknown::removeTimer()
{
if (m_timer != NULL) {
EVENTQUEUE->deleteTimer(m_timer);
EVENTQUEUE->removeHandler(CEvent::kTimer, this);
m_timer = NULL;
}
}
void
CClientProxyUnknown::handleData(const CEvent&, void*)
{
LOG((CLOG_DEBUG1 "parsing hello reply"));
CString name("<unknown>");
try {
// limit the maximum length of the hello
UInt32 n = m_stream->getSize();
if (n > kMaxHelloLength) {
LOG((CLOG_DEBUG1 "hello reply too long"));
throw XBadClient();
}
// parse the reply to hello
SInt16 major, minor;
if (!CProtocolUtil::readf(m_stream, kMsgHelloBack,
&major, &minor, &name)) {
throw XBadClient();
}
// disallow invalid version numbers
if (major <= 0 || minor < 0) {
throw XIncompatibleClient(major, minor);
}
// remove stream event handlers. the proxy we're about to create
// may install its own handlers and we don't want to accidentally
// remove those later.
removeHandlers();
// create client proxy for highest version supported by the client
if (major == 1) {
switch (minor) {
case 0:
m_proxy = new CClientProxy1_0(name, m_stream);
break;
case 1:
m_proxy = new CClientProxy1_1(name, m_stream);
break;
}
}
// hangup (with error) if version isn't supported
if (m_proxy == NULL) {
throw XIncompatibleClient(major, minor);
}
// the proxy is created and now proxy now owns the stream
LOG((CLOG_DEBUG1 "created proxy for client \"%s\" version %d.%d", name.c_str(), major, minor));
m_stream = NULL;
// wait until the proxy signals that it's ready or has disconnected
addProxyHandlers();
return;
}
catch (XIncompatibleClient& e) {
// client is incompatible
LOG((CLOG_WARN "client \"%s\" has incompatible version %d.%d)", name.c_str(), e.getMajor(), e.getMinor()));
CProtocolUtil::writef(m_stream,
kMsgEIncompatible,
kProtocolMajorVersion, kProtocolMinorVersion);
}
catch (XBadClient&) {
// client not behaving
LOG((CLOG_WARN "protocol error from client \"%s\"", name.c_str()));
CProtocolUtil::writef(m_stream, kMsgEBad);
}
catch (XBase& e) {
// misc error
LOG((CLOG_WARN "error communicating with client \"%s\": %s", name.c_str(), e.what()));
}
sendFailure();
}
void
CClientProxyUnknown::handleWriteError(const CEvent&, void*)
{
LOG((CLOG_NOTE "error communicating with new client"));
sendFailure();
}
void
CClientProxyUnknown::handleTimeout(const CEvent&, void*)
{
LOG((CLOG_NOTE "new client is unresponsive"));
sendFailure();
}
void
CClientProxyUnknown::handleDisconnect(const CEvent&, void*)
{
LOG((CLOG_NOTE "new client disconnected"));
sendFailure();
}
void
CClientProxyUnknown::handleReady(const CEvent&, void*)
{
sendSuccess();
}

View File

@ -0,0 +1,83 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2004 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef CCLIENTPROXYUNKNOWN_H
#define CCLIENTPROXYUNKNOWN_H
#include "CEvent.h"
class CClientProxy;
class CEventQueueTimer;
class IStream;
class CClientProxyUnknown {
public:
CClientProxyUnknown(IStream* stream, double timeout);
~CClientProxyUnknown();
//! @name manipulators
//@{
//! Get the client proxy
/*!
Returns the client proxy created after a successful handshake
(i.e. when this object sends a success event). Returns NULL
if the handshake is unsuccessful or incomplete.
*/
CClientProxy* orphanClientProxy();
//@}
//! @name accessors
//@{
//! Get success event type
/*!
Returns the success event type. This is sent when the client has
correctly responded to the hello message. The target is this.
*/
static CEvent::Type getSuccessEvent();
//! Get failure event type
/*!
Returns the failure event type. This is sent when a client fails
to correctly respond to the hello message. The target is this.
*/
static CEvent::Type getFailureEvent();
//@}
private:
void sendSuccess();
void sendFailure();
void addStreamHandlers();
void addProxyHandlers();
void removeHandlers();
void removeTimer();
void handleData(const CEvent&, void*);
void handleWriteError(const CEvent&, void*);
void handleTimeout(const CEvent&, void*);
void handleDisconnect(const CEvent&, void*);
void handleReady(const CEvent&, void*);
private:
IStream* m_stream;
CEventQueueTimer* m_timer;
CClientProxy* m_proxy;
bool m_ready;
static CEvent::Type s_successEvent;
static CEvent::Type s_failureEvent;
};
#endif

View File

@ -446,11 +446,9 @@ CConfig::getOptions(const CString& name) const
bool bool
CConfig::operator==(const CConfig& x) const CConfig::operator==(const CConfig& x) const
{ {
/* FIXME -- no compare available for CNetworkAddress
if (m_synergyAddress != x.m_synergyAddress) { if (m_synergyAddress != x.m_synergyAddress) {
return false; return false;
} }
*/
if (m_map.size() != x.m_map.size()) { if (m_map.size() != x.m_map.size()) {
return false; return false;
} }

View File

@ -14,10 +14,6 @@
#include "CPrimaryClient.h" #include "CPrimaryClient.h"
#include "CScreen.h" #include "CScreen.h"
#include "IScreenFactory.h"
#include "IServer.h"
#include "XScreen.h"
#include "XSynergy.h"
#include "CClipboard.h" #include "CClipboard.h"
#include "CLog.h" #include "CLog.h"
@ -25,66 +21,31 @@
// CPrimaryClient // CPrimaryClient
// //
CPrimaryClient::CPrimaryClient(IScreenFactory* screenFactory, CPrimaryClient::CPrimaryClient(const CString& name, CScreen* screen) :
IServer* server,
IPrimaryScreenReceiver* receiver,
const CString& name) :
m_server(server),
m_name(name), m_name(name),
m_seqNum(0) m_screen(screen)
{ {
assert(m_server != NULL); // all clipboards are clean
for (UInt32 i = 0; i < kClipboardEnd; ++i) {
// create screen m_clipboardDirty[i] = false;
LOG((CLOG_DEBUG1 "creating primary screen"));
if (screenFactory != NULL) {
IPlatformScreen* platformScreen =
screenFactory->create(this, receiver);
if (platformScreen != NULL) {
m_screen = new CScreen(platformScreen, this);
}
}
if (m_screen == NULL) {
throw XScreenOpenFailure();
} }
} }
CPrimaryClient::~CPrimaryClient() CPrimaryClient::~CPrimaryClient()
{ {
LOG((CLOG_DEBUG1 "destroying primary screen"));
delete m_screen; delete m_screen;
} }
void
CPrimaryClient::exitMainLoop()
{
m_screen->exitMainLoop();
}
void void
CPrimaryClient::reconfigure(UInt32 activeSides) CPrimaryClient::reconfigure(UInt32 activeSides)
{ {
m_screen->reconfigure(activeSides); m_screen->reconfigure(activeSides);
} }
UInt32
CPrimaryClient::addOneShotTimer(double timeout)
{
return m_screen->addOneShotTimer(timeout);
}
void void
CPrimaryClient::getClipboard(ClipboardID id, CString& data) const CPrimaryClient::getCursorCenter(SInt32& x, SInt32& y) const
{ {
CClipboard clipboard; m_screen->getCursorCenter(x, y);
m_screen->getClipboard(id, &clipboard);
data = clipboard.marshall();
}
bool
CPrimaryClient::isLockedToScreen() const
{
return m_screen->isLockedToScreen();
} }
KeyModifierMask KeyModifierMask
@ -93,64 +54,41 @@ CPrimaryClient::getToggleMask() const
return m_screen->getActiveModifiers(); return m_screen->getActiveModifiers();
} }
void bool
CPrimaryClient::onError() CPrimaryClient::isLockedToScreen() const
{ {
// forward to server return m_screen->isLockedToScreen();
m_server->onError();
} }
void void*
CPrimaryClient::onInfoChanged(const CClientInfo& info) CPrimaryClient::getEventTarget() const
{ {
m_info = info; return m_screen->getEventTarget();
try {
m_server->onInfoChanged(getName(), m_info);
}
catch (XBadClient&) {
// ignore
}
} }
bool bool
CPrimaryClient::onGrabClipboard(ClipboardID id) CPrimaryClient::getClipboard(ClipboardID id, IClipboard* clipboard) const
{ {
try { return m_screen->getClipboard(id, clipboard);
return m_server->onGrabClipboard(getName(), id, m_seqNum); }
}
catch (XBadClient&) { SInt32
return false; CPrimaryClient::getJumpZoneSize() const
} {
return m_screen->getJumpZoneSize();
} }
void void
CPrimaryClient::onClipboardChanged(ClipboardID id, const CString& data) CPrimaryClient::getShape(SInt32& x, SInt32& y,
SInt32& width, SInt32& height) const
{ {
m_server->onClipboardChanged(id, m_seqNum, data); m_screen->getShape(x, y, width, height);
} }
void void
CPrimaryClient::open() CPrimaryClient::getCursorPos(SInt32& x, SInt32& y) const
{ {
// all clipboards are clean m_screen->getCursorPos(x, y);
for (UInt32 i = 0; i < kClipboardEnd; ++i) {
m_clipboardDirty[i] = false;
}
// now open the screen
m_screen->open();
}
void
CPrimaryClient::mainLoop()
{
m_screen->mainLoop();
}
void
CPrimaryClient::close()
{
m_screen->close();
} }
void void
@ -169,8 +107,7 @@ void
CPrimaryClient::enter(SInt32 xAbs, SInt32 yAbs, CPrimaryClient::enter(SInt32 xAbs, SInt32 yAbs,
UInt32 seqNum, KeyModifierMask, bool screensaver) UInt32 seqNum, KeyModifierMask, bool screensaver)
{ {
// note -- we must not call any server methods except onError(). m_screen->setSequenceNumber(seqNum);
m_seqNum = seqNum;
if (!screensaver) { if (!screensaver) {
m_screen->warpCursor(xAbs, yAbs); m_screen->warpCursor(xAbs, yAbs);
} }
@ -180,15 +117,12 @@ CPrimaryClient::enter(SInt32 xAbs, SInt32 yAbs,
bool bool
CPrimaryClient::leave() CPrimaryClient::leave()
{ {
// note -- we must not call any server methods except onError().
return m_screen->leave(); return m_screen->leave();
} }
void void
CPrimaryClient::setClipboard(ClipboardID id, const CString& data) CPrimaryClient::setClipboard(ClipboardID id, const CString& data)
{ {
// note -- we must not call any server methods except onError().
// ignore if this clipboard is already clean // ignore if this clipboard is already clean
if (m_clipboardDirty[id]) { if (m_clipboardDirty[id]) {
// this clipboard is now clean // this clipboard is now clean
@ -284,31 +218,3 @@ CPrimaryClient::getName() const
{ {
return m_name; return m_name;
} }
SInt32
CPrimaryClient::getJumpZoneSize() const
{
return m_info.m_zoneSize;
}
void
CPrimaryClient::getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) const
{
x = m_info.m_x;
y = m_info.m_y;
w = m_info.m_w;
h = m_info.m_h;
}
void
CPrimaryClient::getCursorPos(SInt32&, SInt32&) const
{
assert(0 && "shouldn't be called");
}
void
CPrimaryClient::getCursorCenter(SInt32& x, SInt32& y) const
{
x = m_info.m_mx;
y = m_info.m_my;
}

View File

@ -16,14 +16,9 @@
#define CPRIMARYCLIENT_H #define CPRIMARYCLIENT_H
#include "IClient.h" #include "IClient.h"
#include "IScreenReceiver.h"
#include "ProtocolTypes.h" #include "ProtocolTypes.h"
class CScreen; class CScreen;
class IClipboard;
class IScreenFactory;
class IPrimaryScreenReceiver;
class IServer;
//! Primary screen as pseudo-client //! Primary screen as pseudo-client
/*! /*!
@ -31,50 +26,34 @@ The primary screen does not have a client associated with it. This
class provides a pseudo-client to allow the primary screen to be class provides a pseudo-client to allow the primary screen to be
treated as if it was on a client. treated as if it was on a client.
*/ */
class CPrimaryClient : public IScreenReceiver, public IClient { class CPrimaryClient : public IClient {
public: public:
/*! /*!
\c name is the name of the server. The caller retains ownership of \c name is the name of the server. \p screen is adopted.
\c factory. Throws XScreenOpenFailure or whatever the factory can
throw if the screen cannot be created.
*/ */
CPrimaryClient(IScreenFactory* factory, IServer*, CPrimaryClient(const CString& name, CScreen* screen);
IPrimaryScreenReceiver*, const CString& name);
~CPrimaryClient(); ~CPrimaryClient();
//! @name manipulators //! @name manipulators
//@{ //@{
//! Exit event loop
/*!
Force mainLoop() to return. This call can return before
mainLoop() does (i.e. asynchronously). This may only be
called between a successful open() and close().
*/
void exitMainLoop();
//! Update configuration //! Update configuration
/*! /*!
Handles reconfiguration of jump zones. Handles reconfiguration of jump zones.
*/ */
void reconfigure(UInt32 activeSides); void reconfigure(UInt32 activeSides);
//! Install a one-shot timer
/*!
Installs a one-shot timer for \c timeout seconds and returns the
id of the timer (which will be passed to \c onTimerExpired()).
*/
UInt32 addOneShotTimer(double timeout);
//@} //@}
//! @name accessors //! @name accessors
//@{ //@{
//! Get clipboard //! Get cursor center position
/*! /*!
Save the marshalled contents of the clipboard indicated by \c id. Return the cursor center position which is where we park the
cursor to compute cursor motion deltas and should be far from
the edges of the screen, typically the center.
*/ */
void getClipboard(ClipboardID, CString&) const; void getCursorCenter(SInt32& x, SInt32& y) const;
//! Get toggle key state //! Get toggle key state
/*! /*!
@ -90,19 +69,19 @@ public:
//@} //@}
// IScreenReceiver overrides // FIXME -- these probably belong on IScreen
virtual void onError();
virtual void onInfoChanged(const CClientInfo&);
virtual bool onGrabClipboard(ClipboardID);
virtual void onClipboardChanged(ClipboardID, const CString&);
// XXX -- these go in IClient
virtual void enable(); virtual void enable();
virtual void disable(); virtual void disable();
// IScreen overrides
virtual void* getEventTarget() const;
virtual bool getClipboard(ClipboardID id, IClipboard*) const;
virtual SInt32 getJumpZoneSize() const;
virtual void getShape(SInt32& x, SInt32& y,
SInt32& width, SInt32& height) const;
virtual void getCursorPos(SInt32& x, SInt32& y) const;
// IClient overrides // IClient overrides
virtual void open();
virtual void mainLoop();
virtual void close();
virtual void enter(SInt32 xAbs, SInt32 yAbs, virtual void enter(SInt32 xAbs, SInt32 yAbs,
UInt32 seqNum, KeyModifierMask mask, UInt32 seqNum, KeyModifierMask mask,
bool forScreensaver); bool forScreensaver);
@ -122,18 +101,10 @@ public:
virtual void resetOptions(); virtual void resetOptions();
virtual void setOptions(const COptionsList& options); virtual void setOptions(const COptionsList& options);
virtual CString getName() const; virtual CString getName() const;
virtual SInt32 getJumpZoneSize() const;
virtual void getShape(SInt32& x, SInt32& y,
SInt32& width, SInt32& height) const;
virtual void getCursorPos(SInt32& x, SInt32& y) const;
virtual void getCursorCenter(SInt32& x, SInt32& y) const;
private: private:
IServer* m_server;
CScreen* m_screen;
CString m_name; CString m_name;
UInt32 m_seqNum; CScreen* m_screen;
CClientInfo m_info;
bool m_clipboardDirty[kClipboardEnd]; bool m_clipboardDirty[kClipboardEnd];
}; };

File diff suppressed because it is too large Load Diff

View File

@ -15,84 +15,40 @@
#ifndef CSERVER_H #ifndef CSERVER_H
#define CSERVER_H #define CSERVER_H
#include "IServer.h"
#include "IPrimaryScreenReceiver.h"
#include "CConfig.h" #include "CConfig.h"
#include "CClipboard.h" #include "CClipboard.h"
#include "CCondVar.h" #include "ClipboardTypes.h"
#include "CMutex.h" #include "KeyTypes.h"
#include "CThread.h" #include "MouseTypes.h"
#include "CJobList.h" #include "CEvent.h"
#include "CStopwatch.h" #include "CStopwatch.h"
#include "stdlist.h"
#include "stdmap.h" #include "stdmap.h"
#include "stdset.h"
#include "stdvector.h" #include "stdvector.h"
class CClientProxy; class CClientProxy;
class CClientProxyUnknown;
class CEventQueueTimer;
class CPrimaryClient; class CPrimaryClient;
class IClient; class IClient;
class IDataSocket;
class IScreenFactory;
class IServerProtocol;
class ISocketFactory;
class IStreamFilterFactory;
//! Synergy server //! Synergy server
/*! /*!
This class implements the top-level server algorithms for synergy. This class implements the top-level server algorithms for synergy.
*/ */
class CServer : public IServer, public IPrimaryScreenReceiver { class CServer {
public: public:
enum EStatus {
kNotRunning,
kRunning,
kServerNameUnknown,
kError,
kMaxStatus
};
/*! /*!
The server will look itself up in the configuration using \c serverName Start the server with the configuration \p config and the primary
as its name. client (local screen) \p primaryClient. The client retains
ownership of \p primaryClient.
*/ */
CServer(const CString& serverName); CServer(const CConfig& config, CPrimaryClient* primaryClient);
~CServer(); ~CServer();
//! @name manipulators //! @name manipulators
//@{ //@{
//! Open server
/*!
Open the server. Throws XScreenUnavailable if the server's
screen cannot be opened but might be available after some time.
Otherwise throws some other exception if the server's screen or
the server cannot be opened and retrying won't help.
*/
void open();
//! Server main loop
/*!
Run server's event loop and return when exitMainLoop() is called.
This must be called between a successful open() and close().
(cancellation point)
*/
void mainLoop();
//! Exit event loop
/*!
Force mainLoop() to return. This call can return before
mainLoop() does (i.e. asynchronously). This may only be
called between a successful open() and close().
*/
void exitMainLoop();
//! Close server
/*!
Close the server.
*/
void close();
//! Set configuration //! Set configuration
/*! /*!
Change the server's configuration. Returns true iff the new Change the server's configuration. Returns true iff the new
@ -101,67 +57,26 @@ public:
*/ */
bool setConfig(const CConfig&); bool setConfig(const CConfig&);
//! Set screen factory //! Add a client
/*! /*!
Sets the factory for creating screens. This must be set before Adds \p client to the server. The client is adopted and will be
calling open(). This object takes ownership of the factory. destroyed when the client disconnects or is disconnected.
*/ */
void setScreenFactory(IScreenFactory*); void adoptClient(IClient* client);
//! Set socket factory //! Disconnect clients
/*! /*!
Sets the factory used to create a socket to connect to the server. Disconnect clients. This tells them to disconnect but does not wait
This must be set before calling mainLoop(). This object takes for them to actually do so. The server sends the disconnected event
ownership of the factory. when they're all disconnected (or immediately if none are connected).
The caller can also just destroy this object to force the disconnection.
*/ */
void setSocketFactory(ISocketFactory*); void disconnect();
//! Set stream filter factory
/*!
Sets the factory used to filter the socket streams used to
communicate with the server. This object takes ownership
of the factory.
*/
void setStreamFilterFactory(IStreamFilterFactory*);
//! Add a job to notify of status changes
/*!
The added job is run whenever the server's status changes in
certain externally visible ways. The client keeps ownership
of the job.
*/
void addStatusJob(IJob*);
//! Remove a job to notify of status changes
/*!
Removes a previously added status notification job. A job can
remove itself when called but must not remove any other jobs.
The client keeps ownership of the job.
*/
void removeStatusJob(IJob*);
//@} //@}
//! @name accessors //! @name accessors
//@{ //@{
//! Get configuration
/*!
Returns the current configuration.
*/
void getConfig(CConfig*) const;
//! Get canonical screen name
/*!
Returns the canonical version of a screen name.
*/
CString getCanonicalName(const CString& name) const;
//! Get name
/*!
Returns the server's name passed to the c'tor
*/
CString getPrimaryScreenName() const;
//! Get number of connected clients //! Get number of connected clients
/*! /*!
Returns the number of connected clients, including the server itself. Returns the number of connected clients, including the server itself.
@ -174,33 +89,22 @@ public:
*/ */
void getClients(std::vector<CString>& list) const; void getClients(std::vector<CString>& list) const;
//! Get the status //! Get error event type
/*! /*!
Returns the current status and status message. Returns the error event type. This is sent when the server fails
for some reason.
*/ */
EStatus getStatus(CString* = NULL) const; static CEvent::Type getErrorEvent();
//! Get disconnected event type
/*!
Returns the disconnected event type. This is sent when all the
clients have disconnected.
*/
static CEvent::Type getDisconnectedEvent();
//@} //@}
// 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 onScreensaver(bool activated);
virtual void onOneShotTimerExpired(UInt32 id);
virtual void onKeyDown(KeyID, KeyModifierMask, KeyButton);
virtual void onKeyUp(KeyID, KeyModifierMask, KeyButton);
virtual void onKeyRepeat(KeyID, KeyModifierMask,
SInt32 count, KeyButton);
virtual void onMouseDown(ButtonID);
virtual void onMouseUp(ButtonID);
virtual bool onMouseMovePrimary(SInt32 x, SInt32 y);
virtual void onMouseMoveSecondary(SInt32 dx, SInt32 dy);
virtual void onMouseWheel(SInt32 delta);
protected: protected:
//! Handle special keys //! Handle special keys
/*! /*!
@ -208,36 +112,18 @@ protected:
*/ */
bool onCommandKey(KeyID, KeyModifierMask, bool down); bool onCommandKey(KeyID, KeyModifierMask, bool down);
//! Exit event loop and note an error condition
/*!
Force mainLoop() to return by throwing an exception. This call
can return before mainLoop() does (i.e. asynchronously). This
may only be called between a successful open() and close().
*/
void exitMainLoopWithError();
private: private:
typedef std::list<CThread> CThreadList; // get canonical name of client
CString getName(const IClient*) const;
// notify status jobs of a change
void runStatusJobs() const;
// set new status
void setStatus(EStatus, const char* msg = NULL);
// get the sides of the primary screen that have neighbors // get the sides of the primary screen that have neighbors
UInt32 getActivePrimarySides() const; UInt32 getActivePrimarySides() const;
// handle mouse motion
bool onMouseMovePrimaryNoLock(SInt32 x, SInt32 y);
void onMouseMoveSecondaryNoLock(SInt32 dx, SInt32 dy);
// set the clipboard
void onClipboardChangedNoLock(ClipboardID,
UInt32 seqNum, const CString& data);
// returns true iff mouse should be locked to the current screen // returns true iff mouse should be locked to the current screen
bool isLockedToScreenNoLock() const; bool isLockedToScreen() const;
// returns the jump zone of the client
SInt32 getJumpZoneSize(IClient*) const;
// change the active screen // change the active screen
void switchScreen(IClient*, void switchScreen(IClient*,
@ -260,57 +146,98 @@ private:
bool isSwitchOkay(IClient* dst, EDirection, bool isSwitchOkay(IClient* dst, EDirection,
SInt32 x, SInt32 y); SInt32 x, SInt32 y);
// update switch state due to a mouse move that doesn't try to // update switch state due to a mouse move at \p x, \p y that
// switch screens. // doesn't switch screens.
void onNoSwitch(bool inTapZone); void noSwitch(SInt32 x, SInt32 y);
// reset switch wait state // stop switch timers
void clearSwitchState(); void stopSwitch();
// start two tap switch timer
void startSwitchTwoTap();
// arm the two tap switch timer if \p x, \p y is outside the tap zone
void armSwitchTwoTap(SInt32 x, SInt32 y);
// stop the two tap switch timer
void stopSwitchTwoTap();
// returns true iff the two tap switch timer is started
bool isSwitchTwoTapStarted() const;
// returns true iff should switch because of two tap
bool shouldSwitchTwoTap() const;
// start delay switch timer
void startSwitchWait(SInt32 x, SInt32 y);
// stop delay switch timer
void stopSwitchWait();
// returns true iff the delay switch timer is started
bool isSwitchWaitStarted() const;
// send screen options to \c client // send screen options to \c client
void sendOptions(IClient* client) const; void sendOptions(IClient* client) const;
// open/close the primary screen // process options from configuration
void openPrimaryScreen(); void processOptions();
void closePrimaryScreen();
// update the clipboard if owned by the primary screen // event handlers
void updatePrimaryClipboard(ClipboardID); void handleShapeChanged(const CEvent&, void*);
void handleClipboardGrabbed(const CEvent&, void*);
void handleClipboardChanged(const CEvent&, void*);
void handleKeyDownEvent(const CEvent&, void*);
void handleKeyUpEvent(const CEvent&, void*);
void handleKeyRepeatEvent(const CEvent&, void*);
void handleButtonDownEvent(const CEvent&, void*);
void handleButtonUpEvent(const CEvent&, void*);
void handleMotionPrimaryEvent(const CEvent&, void*);
void handleMotionSecondaryEvent(const CEvent&, void*);
void handleWheelEvent(const CEvent&, void*);
void handleScreensaverActivatedEvent(const CEvent&, void*);
void handleScreensaverDeactivatedEvent(const CEvent&, void*);
void handleSwitchWaitTimeout(const CEvent&, void*);
void handleClientDisconnected(const CEvent&, void*);
void handleClientCloseTimeout(const CEvent&, void*);
// close all clients that are *not* in config, not including the // event processing
// primary client. void onClipboardChanged(IClient* sender,
ClipboardID id, UInt32 seqNum);
void onScreensaver(bool activated);
void onKeyDown(KeyID, KeyModifierMask, KeyButton);
void onKeyUp(KeyID, KeyModifierMask, KeyButton);
void onKeyRepeat(KeyID, KeyModifierMask, SInt32, KeyButton);
void onMouseDown(ButtonID);
void onMouseUp(ButtonID);
bool onMouseMovePrimary(SInt32 x, SInt32 y);
void onMouseMoveSecondary(SInt32 dx, SInt32 dy);
void onMouseWheel(SInt32 delta);
// add client to list and attach event handlers for client
bool addClient(IClient*);
// remove client from list and detach event handlers for client
bool removeClient(IClient*);
// close a client
void closeClient(IClient*, const char* msg);
// close clients not in \p config
void closeClients(const CConfig& config); void closeClients(const CConfig& config);
// start a thread, adding it to the list of threads // close all clients whether they've completed the handshake or not,
CThread startThread(IJob* adopted); // except the primary client
void closeAllClients();
// cancel running threads, waiting at most timeout seconds for // remove clients from internal state
// them to finish. void removeActiveClient(IClient*);
void stopThreads(double timeout = -1.0); void removeOldClient(IClient*);
// reap threads, clearing finished threads from the thread list. // force the cursor off of \p client
// doReapThreads does the work on the given thread list. void forceLeaveClient(IClient* client);
void reapThreads();
void doReapThreads(CThreadList&);
// thread method to accept incoming client connections
void acceptClients(void*);
// thread method to do client interaction
void runClient(void*);
CClientProxy* handshakeClient(IDataSocket*);
// connection list maintenance
void addConnection(IClient*);
void removeConnection(const CString& name);
private: private:
class XServerRethrow : public XBase {
protected:
// XBase overrides
virtual CString getWhat() const throw();
};
class CClipboardInfo { class CClipboardInfo {
public: public:
CClipboardInfo(); CClipboardInfo();
@ -322,52 +249,27 @@ private:
UInt32 m_clipboardSeqNum; UInt32 m_clipboardSeqNum;
}; };
CMutex m_mutex;
// the name of the primary screen
CString m_name;
// true if we should exit the main loop by throwing an exception.
// this is used to propagate an exception from one of our threads
// to the mainLoop() thread. but, since we can't make a copy of
// the original exception, we return an arbitrary, unique
// exception type. the caller of mainLoop() cannot catch this
// exception except through XBase or ....
bool m_error;
// how long to wait to bind our socket until we give up
double m_bindTimeout;
// factories
IScreenFactory* m_screenFactory;
ISocketFactory* m_socketFactory;
IStreamFilterFactory* m_streamFilterFactory;
// running threads
CThreadList m_threads;
CThread* m_acceptClientThread;
// the screens
typedef std::map<CString, IClient*> CClientList;
typedef std::map<CString, CThread> CClientThreadList;
// all clients indexed by name
CClientList m_clients;
// run thread of all secondary screen clients. does not include the
// primary screen's run thread.
CClientThreadList m_clientThreads;
// the primary screen client // the primary screen client
CPrimaryClient* m_primaryClient; CPrimaryClient* m_primaryClient;
// all clients (including the primary client) indexed by name
typedef std::map<CString, IClient*> CClientList;
typedef std::set<IClient*> CClientSet;
CClientList m_clients;
CClientSet m_clientSet;
// all old connections that we're waiting to hangup
typedef std::map<IClient*, CEventQueueTimer*> COldClients;
COldClients m_oldClients;
// the client with focus // the client with focus
IClient* m_active; IClient* m_active;
// the sequence number of enter messages // the sequence number of enter messages
UInt32 m_seqNum; UInt32 m_seqNum;
// current mouse position (in absolute secondary screen coordinates) // current mouse position (in absolute screen coordinates) on
// whichever screen is active
SInt32 m_x, m_y; SInt32 m_x, m_y;
// current configuration // current configuration
@ -387,8 +289,7 @@ private:
// state for delayed screen switching // state for delayed screen switching
double m_switchWaitDelay; double m_switchWaitDelay;
UInt32 m_switchWaitTimer; CEventQueueTimer* m_switchWaitTimer;
bool m_switchWaitEngaged;
SInt32 m_switchWaitX, m_switchWaitY; SInt32 m_switchWaitX, m_switchWaitY;
// state for double-tap screen switching // state for double-tap screen switching
@ -398,19 +299,8 @@ private:
bool m_switchTwoTapArmed; bool m_switchTwoTapArmed;
SInt32 m_switchTwoTapZone; SInt32 m_switchTwoTapZone;
// the status change jobs and status static CEvent::Type s_errorEvent;
CJobList m_statusJobs; static CEvent::Type s_disconnectedEvent;
EStatus m_status;
CString m_statusMessage;
//---
/*
IListenSocket* m_listen;
typedef std::map<CProvisionalClient*,
CEventQueueTimer*> CProvisionalClients;
CProvisionalClients m_provisional;
*/
}; };
#endif #endif

View File

@ -25,19 +25,21 @@ MAINTAINERCLEANFILES = \
noinst_LIBRARIES = libserver.a noinst_LIBRARIES = libserver.a
libserver_a_SOURCES = \ libserver_a_SOURCES = \
CClientListener.cpp \
CClientProxy.cpp \ CClientProxy.cpp \
CClientProxy1_0.cpp \ CClientProxy1_0.cpp \
CClientProxy1_1.cpp \ CClientProxy1_1.cpp \
CClientProxyUnknown.cpp \
CConfig.cpp \ CConfig.cpp \
CPrimaryClient.cpp \ CPrimaryClient.cpp \
CProvisionalClient.cpp \
CServer.cpp \ CServer.cpp \
CClientListener.h \
CClientProxy.h \ CClientProxy.h \
CClientProxy1_0.h \ CClientProxy1_0.h \
CClientProxy1_1.h \ CClientProxy1_1.h \
CClientProxyUnknown.h \
CConfig.h \ CConfig.h \
CPrimaryClient.h \ CPrimaryClient.h \
CProvisionalClient.h \
CServer.h \ CServer.h \
$(NULL) $(NULL)
INCLUDES = \ INCLUDES = \

View File

@ -73,7 +73,6 @@ CProtocolUtil::vwritef(IStream* stream,
} }
// fill buffer // fill buffer
// FIXME -- can we use alloca?
UInt8* buffer = new UInt8[size]; UInt8* buffer = new UInt8[size];
writef(buffer, fmt, args); writef(buffer, fmt, args);

View File

@ -14,41 +14,26 @@
#include "CScreen.h" #include "CScreen.h"
#include "IPlatformScreen.h" #include "IPlatformScreen.h"
#include "IScreenReceiver.h"
#include "ISecondaryScreen.h"
#include "ProtocolTypes.h" #include "ProtocolTypes.h"
#include "CLock.h"
#include "CThread.h"
#include "CLog.h" #include "CLog.h"
#include "IEventQueue.h"
// //
// CScreen // CScreen
// //
CScreen::CScreen(IPlatformScreen* platformScreen, IScreenReceiver* receiver) : CScreen::CScreen(IPlatformScreen* platformScreen) :
m_screen(platformScreen), m_screen(platformScreen),
m_receiver(receiver),
m_isPrimary(platformScreen->isPrimary()), m_isPrimary(platformScreen->isPrimary()),
m_enabled(false), m_enabled(false),
m_entered(m_isPrimary), m_entered(m_isPrimary),
m_toggleKeys(0), m_toggleKeys(0),
m_screenSaverSync(true) m_screenSaverSync(true)
{ {
// do nothing assert(m_screen != NULL);
}
CScreen::~CScreen()
{
delete m_screen;
}
void
CScreen::open()
{
CLock lock(&m_mutex);
// open screen // open screen
m_screen->open(this); m_screen->setKeyState(this);
// reset options // reset options
resetOptions(); resetOptions();
@ -56,23 +41,20 @@ CScreen::open()
LOG((CLOG_DEBUG "opened display")); LOG((CLOG_DEBUG "opened display"));
} }
void CScreen::~CScreen()
CScreen::close()
{ {
CLock lock(&m_mutex); if (m_enabled) {
disable();
}
assert(!m_enabled); assert(!m_enabled);
assert(m_entered == m_isPrimary); assert(m_entered == m_isPrimary);
delete m_screen;
// close screen
m_screen->close();
LOG((CLOG_DEBUG "closed display")); LOG((CLOG_DEBUG "closed display"));
} }
void void
CScreen::enable() CScreen::enable()
{ {
CLock lock(&m_mutex);
assert(!m_enabled); assert(!m_enabled);
m_screen->enable(); m_screen->enable();
@ -90,7 +72,6 @@ CScreen::enable()
void void
CScreen::disable() CScreen::disable()
{ {
CLock lock(&m_mutex);
assert(m_enabled); assert(m_enabled);
if (!m_isPrimary && m_entered) { if (!m_isPrimary && m_entered) {
@ -111,34 +92,9 @@ CScreen::disable()
m_enabled = false; m_enabled = false;
} }
void
CScreen::mainLoop()
{
// change our priority
CThread::getCurrentThread().setPriority(-14);
// run event loop
try {
LOG((CLOG_DEBUG "entering event loop"));
m_screen->mainLoop();
LOG((CLOG_DEBUG "exiting event loop"));
}
catch (...) {
LOG((CLOG_DEBUG "exiting event loop"));
throw;
}
}
void
CScreen::exitMainLoop()
{
m_screen->exitMainLoop();
}
void void
CScreen::enter() CScreen::enter()
{ {
CLock lock(&m_mutex);
assert(m_entered == false); assert(m_entered == false);
LOG((CLOG_INFO "entering screen")); LOG((CLOG_INFO "entering screen"));
@ -157,7 +113,6 @@ CScreen::enter()
bool bool
CScreen::leave() CScreen::leave()
{ {
CLock lock(&m_mutex);
assert(m_entered == true); assert(m_entered == true);
LOG((CLOG_INFO "leaving screen")); LOG((CLOG_INFO "leaving screen"));
@ -209,8 +164,6 @@ CScreen::grabClipboard(ClipboardID id)
void void
CScreen::screensaver(bool activate) CScreen::screensaver(bool activate)
{ {
CLock lock(&m_mutex);
if (!m_isPrimary) { if (!m_isPrimary) {
// activate/deactivation screen saver iff synchronization enabled // activate/deactivation screen saver iff synchronization enabled
if (m_screenSaverSync) { if (m_screenSaverSync) {
@ -222,7 +175,6 @@ CScreen::screensaver(bool activate)
void void
CScreen::keyDown(KeyID id, KeyModifierMask mask, KeyButton button) CScreen::keyDown(KeyID id, KeyModifierMask mask, KeyButton button)
{ {
CLock lock(&m_mutex);
assert(!m_isPrimary); assert(!m_isPrimary);
// check for ctrl+alt+del emulation // check for ctrl+alt+del emulation
@ -256,7 +208,6 @@ void
CScreen::keyRepeat(KeyID id, CScreen::keyRepeat(KeyID id,
KeyModifierMask mask, SInt32 count, KeyButton button) KeyModifierMask mask, SInt32 count, KeyButton button)
{ {
CLock lock(&m_mutex);
assert(!m_isPrimary); assert(!m_isPrimary);
// if we haven't seen this button go down then ignore it // if we haven't seen this button go down then ignore it
@ -316,7 +267,6 @@ CScreen::keyRepeat(KeyID id,
void void
CScreen::keyUp(KeyID, KeyModifierMask, KeyButton button) CScreen::keyUp(KeyID, KeyModifierMask, KeyButton button)
{ {
CLock lock(&m_mutex);
assert(!m_isPrimary); assert(!m_isPrimary);
// if we haven't seen this button go down then ignore it // if we haven't seen this button go down then ignore it
@ -372,8 +322,6 @@ CScreen::mouseWheel(SInt32 delta)
void void
CScreen::resetOptions() CScreen::resetOptions()
{ {
CLock lock(&m_mutex);
// reset options // reset options
m_numLockHalfDuplex = false; m_numLockHalfDuplex = false;
m_capsLockHalfDuplex = false; m_capsLockHalfDuplex = false;
@ -394,8 +342,6 @@ CScreen::resetOptions()
void void
CScreen::setOptions(const COptionsList& options) CScreen::setOptions(const COptionsList& options)
{ {
CLock lock(&m_mutex);
// update options // update options
bool oldScreenSaverSync = m_screenSaverSync; bool oldScreenSaverSync = m_screenSaverSync;
for (UInt32 i = 0, n = options.size(); i < n; i += 2) { for (UInt32 i = 0, n = options.size(); i < n; i += 2) {
@ -427,37 +373,18 @@ CScreen::setOptions(const COptionsList& options)
m_screen->setOptions(options); m_screen->setOptions(options);
} }
UInt32 void
CScreen::addOneShotTimer(double timeout) CScreen::setSequenceNumber(UInt32 seqNum)
{ {
return m_screen->addOneShotTimer(timeout); return m_screen->setSequenceNumber(seqNum);
} }
bool bool
CScreen::isOnScreen() const CScreen::isOnScreen() const
{ {
CLock lock(&m_mutex);
return m_entered; return m_entered;
} }
void
CScreen::getClipboard(ClipboardID id,
IClipboard* clipboard) const
{
m_screen->getClipboard(id, clipboard);
}
SInt32
CScreen::getJumpZoneSize() const
{
if (!m_isPrimary) {
return 0;
}
else {
return m_screen->getJumpZoneSize();
}
}
bool bool
CScreen::isLockedToScreen() const CScreen::isLockedToScreen() const
{ {
@ -488,6 +415,35 @@ CScreen::isLockedToScreen() const
return false; return false;
} }
SInt32
CScreen::getJumpZoneSize() const
{
if (!m_isPrimary) {
return 0;
}
else {
return m_screen->getJumpZoneSize();
}
}
void
CScreen::getCursorCenter(SInt32& x, SInt32& y) const
{
m_screen->getCursorCenter(x, y);
}
void*
CScreen::getEventTarget() const
{
return m_screen;
}
bool
CScreen::getClipboard(ClipboardID id, IClipboard* clipboard) const
{
return m_screen->getClipboard(id, clipboard);
}
void void
CScreen::getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) const CScreen::getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) const
{ {
@ -503,8 +459,6 @@ CScreen::getCursorPos(SInt32& x, SInt32& y) const
void void
CScreen::updateKeys() CScreen::updateKeys()
{ {
CLock lock(&m_mutex);
// clear key state // clear key state
memset(m_keys, 0, sizeof(m_keys)); memset(m_keys, 0, sizeof(m_keys));
memset(m_fakeKeys, 0, sizeof(m_fakeKeys)); memset(m_fakeKeys, 0, sizeof(m_fakeKeys));
@ -522,8 +476,6 @@ CScreen::updateKeys()
void void
CScreen::releaseKeys() CScreen::releaseKeys()
{ {
CLock lock(&m_mutex);
// release keys that we've synthesized a press for and only those // release keys that we've synthesized a press for and only those
// keys. we don't want to synthesize a release on a key the user // keys. we don't want to synthesize a release on a key the user
// is still physically pressing. // is still physically pressing.
@ -539,16 +491,12 @@ CScreen::releaseKeys()
void void
CScreen::setKeyDown(KeyButton key) CScreen::setKeyDown(KeyButton key)
{ {
CLock lock(&m_mutex);
m_keys[key & 0xffu] |= kDown; m_keys[key & 0xffu] |= kDown;
} }
void void
CScreen::setToggled(KeyModifierMask mask) CScreen::setToggled(KeyModifierMask mask)
{ {
CLock lock(&m_mutex);
if (!isToggle(mask)) { if (!isToggle(mask)) {
return; return;
} }
@ -565,8 +513,6 @@ CScreen::setToggled(KeyModifierMask mask)
void void
CScreen::addModifier(KeyModifierMask mask, KeyButtons& keys) CScreen::addModifier(KeyModifierMask mask, KeyButtons& keys)
{ {
CLock lock(&m_mutex);
// the modifier must have associated keys // the modifier must have associated keys
if (keys.empty()) { if (keys.empty()) {
return; return;
@ -608,8 +554,6 @@ CScreen::setToggleState(KeyModifierMask mask)
KeyButton KeyButton
CScreen::isAnyKeyDown() const CScreen::isAnyKeyDown() const
{ {
CLock lock(&m_mutex);
for (UInt32 i = 1; i < 256; ++i) { for (UInt32 i = 1; i < 256; ++i) {
if ((m_keys[i] & kDown) != 0) { if ((m_keys[i] & kDown) != 0) {
return static_cast<KeyButton>(i); return static_cast<KeyButton>(i);
@ -621,8 +565,6 @@ CScreen::isAnyKeyDown() const
bool bool
CScreen::isKeyDown(KeyButton key) const CScreen::isKeyDown(KeyButton key) const
{ {
CLock lock(&m_mutex);
key &= 0xffu; key &= 0xffu;
return (key != 0 && ((m_keys[key] & kDown) != 0)); return (key != 0 && ((m_keys[key] & kDown) != 0));
} }
@ -638,8 +580,6 @@ CScreen::isToggle(KeyModifierMask mask) const
bool bool
CScreen::isHalfDuplex(KeyModifierMask mask) const CScreen::isHalfDuplex(KeyModifierMask mask) const
{ {
CLock lock(&m_mutex);
return ((mask == KeyModifierCapsLock && m_capsLockHalfDuplex) || return ((mask == KeyModifierCapsLock && m_capsLockHalfDuplex) ||
(mask == KeyModifierNumLock && m_numLockHalfDuplex)); (mask == KeyModifierNumLock && m_numLockHalfDuplex));
} }
@ -647,8 +587,6 @@ CScreen::isHalfDuplex(KeyModifierMask mask) const
bool bool
CScreen::isModifierActive(KeyModifierMask mask) const CScreen::isModifierActive(KeyModifierMask mask) const
{ {
CLock lock(&m_mutex);
MaskToKeys::const_iterator i = m_maskToKeys.find(mask); MaskToKeys::const_iterator i = m_maskToKeys.find(mask);
if (i == m_maskToKeys.end()) { if (i == m_maskToKeys.end()) {
return false; return false;
@ -675,7 +613,6 @@ CScreen::isModifierActive(KeyModifierMask mask) const
KeyModifierMask KeyModifierMask
CScreen::getActiveModifiers() const CScreen::getActiveModifiers() const
{ {
CLock lock(&m_mutex);
if (m_isPrimary) { if (m_isPrimary) {
// we don't keep primary key state up to date so get the // we don't keep primary key state up to date so get the
// current state. // current state.
@ -688,8 +625,6 @@ bool
CScreen::mapModifier(Keystrokes& keys, Keystrokes& undo, CScreen::mapModifier(Keystrokes& keys, Keystrokes& undo,
KeyModifierMask mask, bool desireActive) const KeyModifierMask mask, bool desireActive) const
{ {
CLock lock(&m_mutex);
// look up modifier // look up modifier
MaskToKeys::const_iterator i = m_maskToKeys.find(mask); MaskToKeys::const_iterator i = m_maskToKeys.find(mask);
if (i == m_maskToKeys.end()) { if (i == m_maskToKeys.end()) {
@ -751,7 +686,6 @@ CScreen::mapModifier(Keystrokes& keys, Keystrokes& undo,
KeyModifierMask KeyModifierMask
CScreen::getMaskForKey(KeyButton key) const CScreen::getMaskForKey(KeyButton key) const
{ {
CLock lock(&m_mutex);
KeyToMask::const_iterator i = m_keyToMask.find(key); KeyToMask::const_iterator i = m_keyToMask.find(key);
if (i == m_keyToMask.end()) { if (i == m_keyToMask.end()) {
return 0; return 0;
@ -767,12 +701,8 @@ CScreen::enablePrimary()
// get notified of screen saver activation/deactivation // get notified of screen saver activation/deactivation
m_screen->openScreensaver(true); m_screen->openScreensaver(true);
// collect and send screen info // claim screen changed size
CClientInfo info; EVENTQUEUE->addEvent(CEvent(getShapeChangedEvent(), getEventTarget()));
m_screen->getShape(info.m_x, info.m_y, info.m_w, info.m_h);
m_screen->getCursorPos(info.m_mx, info.m_my);
info.m_zoneSize = getJumpZoneSize();
m_receiver->onInfoChanged(info);
} }
void void

View File

@ -12,45 +12,32 @@
* GNU General Public License for more details. * GNU General Public License for more details.
*/ */
#ifndef CSECONDARYSCREEN_H #ifndef CSCREEN_H
#define CSECONDARYSCREEN_H #define CSCREEN_H
#include "IKeyState.h" #include "IKeyState.h"
#include "IScreen.h"
#include "ClipboardTypes.h" #include "ClipboardTypes.h"
#include "MouseTypes.h" #include "MouseTypes.h"
#include "OptionTypes.h" #include "OptionTypes.h"
#include "CMutex.h"
#include "stdmap.h" #include "stdmap.h"
class IClipboard; class IClipboard;
class IPlatformScreen; class IPlatformScreen;
class IScreenReceiver;
//! Platform independent screen //! Platform independent screen
/*! /*!
This is a platform independent screen. It can work as either a This is a platform independent screen. It can work as either a
primary or secondary screen. primary or secondary screen.
*/ */
class CScreen : public IKeyState { class CScreen : public IScreen, public IKeyState {
public: public:
CScreen(IPlatformScreen* platformScreen, IScreenReceiver*); CScreen(IPlatformScreen* platformScreen);
virtual ~CScreen(); virtual ~CScreen();
//! @name manipulators //! @name manipulators
//@{ //@{
//! Open screen
/*!
Opens the screen.
*/
void open();
//! Close screen
/*!
Closes the screen.
*/
void close();
//! Activate screen //! Activate screen
/*! /*!
Activate the screen, preparing it to report system and user events. Activate the screen, preparing it to report system and user events.
@ -66,21 +53,6 @@ public:
*/ */
void disable(); void disable();
//! Run event loop
/*!
Run the screen's event loop. This returns when it detects
the application should terminate or when exitMainLoop() is called.
mainLoop() may only be called between open() and close().
*/
void mainLoop();
//! Exit event loop
/*!
Force mainLoop() to return. This call can return before
mainLoop() does (i.e. asynchronously).
*/
void exitMainLoop();
//! Enter screen //! Enter screen
/*! /*!
Called when the user navigates to this screen. Called when the user navigates to this screen.
@ -196,12 +168,11 @@ public:
*/ */
void setOptions(const COptionsList& options); void setOptions(const COptionsList& options);
//! Install a one-shot timer //! Set clipboard sequence number
/*! /*!
Installs a one-shot timer for \c timeout seconds and returns the Sets the sequence number to use in subsequent clipboard events.
id of the timer.
*/ */
UInt32 addOneShotTimer(double timeout); void setSequenceNumber(UInt32);
//@} //@}
//! @name accessors //! @name accessors
@ -213,19 +184,6 @@ public:
*/ */
bool isOnScreen() const; bool isOnScreen() const;
//! Get clipboard
/*!
Saves the contents of the system clipboard indicated by \c id.
*/
void getClipboard(ClipboardID id, IClipboard*) const;
//! Get jump zone size
/*!
Returns the jump zone size, the size of the regions on the edges of
the screen that cause the cursor to jump to another screen.
*/
SInt32 getJumpZoneSize() const;
//! Get screen lock state //! Get screen lock state
/*! /*!
Returns true if there's any reason that the user should not be Returns true if there's any reason that the user should not be
@ -236,22 +194,30 @@ public:
*/ */
bool isLockedToScreen() const; bool isLockedToScreen() const;
//! Get screen shape //! Get jump zone size
/*! /*!
Returns the position of the upper-left corner of the screen in \c x Return the jump zone size, the size of the regions on the edges of
and \c y and the size of the screen in \c width and \c height. the screen that cause the cursor to jump to another screen.
*/ */
void getShape(SInt32& x, SInt32& y, SInt32 getJumpZoneSize() const;
SInt32& width, SInt32& height) const;
//! Get cursor position //! Get cursor center position
/*! /*!
Returns the current position of the cursor in \c x,y. Return the cursor center position which is where we park the
cursor to compute cursor motion deltas and should be far from
the edges of the screen, typically the center.
*/ */
void getCursorPos(SInt32& x, SInt32& y) const; void getCursorCenter(SInt32& x, SInt32& y) const;
//@} //@}
// IScreen overrides
virtual void* getEventTarget() const;
virtual bool getClipboard(ClipboardID id, IClipboard*) const;
virtual void getShape(SInt32& x, SInt32& y,
SInt32& width, SInt32& height) const;
virtual void getCursorPos(SInt32& x, SInt32& y) const;
// IKeyState overrides // IKeyState overrides
virtual void updateKeys(); virtual void updateKeys();
virtual void releaseKeys(); virtual void releaseKeys();
@ -307,14 +273,9 @@ private:
typedef std::map<KeyModifierMask, KeyButtons> MaskToKeys; typedef std::map<KeyModifierMask, KeyButtons> MaskToKeys;
typedef std::map<KeyButton, KeyModifierMask> KeyToMask; typedef std::map<KeyButton, KeyModifierMask> KeyToMask;
CMutex m_mutex;
// our platform dependent screen // our platform dependent screen
IPlatformScreen* m_screen; IPlatformScreen* m_screen;
// our screen receiver
IScreenReceiver* m_receiver;
// true if screen is being used as a primary screen, false otherwise // true if screen is being used as a primary screen, false otherwise
bool m_isPrimary; bool m_isPrimary;

View File

@ -15,7 +15,7 @@
#ifndef ICLIENT_H #ifndef ICLIENT_H
#define ICLIENT_H #define ICLIENT_H
#include "IInterface.h" #include "IScreen.h"
#include "ClipboardTypes.h" #include "ClipboardTypes.h"
#include "KeyTypes.h" #include "KeyTypes.h"
#include "MouseTypes.h" #include "MouseTypes.h"
@ -27,43 +27,18 @@
This interface defines the methods necessary for the server to This interface defines the methods necessary for the server to
communicate with a client. communicate with a client.
*/ */
class IClient : public IInterface { class IClient : public IScreen {
public: public:
//! @name manipulators //! @name manipulators
//@{ //@{
//! Open client
/*!
Open the client. Throw if the client cannot be opened. If the
screen cannot be opened but retrying later may succeed then throw
XScreenUnavailable.
*/
virtual void open() = 0;
//! Client main loop
/*!
Run client's event loop. This method is typically called in a
separate thread and is exited by cancelling the thread. This
must be called between a successful open() and close().
(cancellation point)
*/
virtual void mainLoop() = 0;
//! Close client
/*!
Close the client.
*/
virtual void close() = 0;
//! Enter screen //! Enter screen
/*! /*!
Enter the screen. The cursor should be warped to \c xAbs,yAbs. Enter the screen. The cursor should be warped to \p xAbs,yAbs.
The client should record seqNum for future reporting of \p mask is the expected toggle button state and the client should
clipboard changes. \c mask is the expected toggle button state update its state to match. \p forScreensaver is true iff the
and the client should update its state to match. \c forScreensaver screen is being entered because the screen saver is starting.
is true iff the screen is being entered because the screen saver is Subsequent clipboard events should report \p seqNum.
starting.
*/ */
virtual void enter(SInt32 xAbs, SInt32 yAbs, virtual void enter(SInt32 xAbs, SInt32 yAbs,
UInt32 seqNum, KeyModifierMask mask, UInt32 seqNum, KeyModifierMask mask,
@ -180,35 +155,14 @@ public:
*/ */
virtual CString getName() const = 0; virtual CString getName() const = 0;
//! Get jump zone size //@}
/*!
Called to get the jump zone size.
*/
virtual SInt32 getJumpZoneSize() const = 0;
//! Get screen shape // IScreen overrides
/*! virtual void* getEventTarget() const = 0;
Return the position of the upper-left corner of the screen in \c x and virtual bool getClipboard(ClipboardID id, IClipboard*) const = 0;
\c y and the size of the screen in \c width and \c height.
*/
virtual void getShape(SInt32& x, SInt32& y, virtual void getShape(SInt32& x, SInt32& y,
SInt32& width, SInt32& height) const = 0; SInt32& width, SInt32& height) const = 0;
//! Get cursor position
/*!
Return the current position of the cursor in \c x and \c y.
*/
virtual void getCursorPos(SInt32& x, SInt32& y) const = 0; virtual void getCursorPos(SInt32& x, SInt32& y) const = 0;
//! Get cursor center position
/*!
Return the cursor center position which 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;
//@}
}; };
#endif #endif

View File

@ -0,0 +1,149 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2004 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "IPlatformScreen.h"
//
// IPlatformScreen
//
CEvent::Type IPlatformScreen::s_keyDownEvent = CEvent::kUnknown;
CEvent::Type IPlatformScreen::s_keyUpEvent = CEvent::kUnknown;
CEvent::Type IPlatformScreen::s_keyRepeatEvent = CEvent::kUnknown;
CEvent::Type IPlatformScreen::s_buttonDownEvent = CEvent::kUnknown;
CEvent::Type IPlatformScreen::s_buttonUpEvent = CEvent::kUnknown;
CEvent::Type IPlatformScreen::s_motionPrimaryEvent = CEvent::kUnknown;
CEvent::Type IPlatformScreen::s_motionSecondaryEvent = CEvent::kUnknown;
CEvent::Type IPlatformScreen::s_wheelEvent = CEvent::kUnknown;
CEvent::Type IPlatformScreen::s_ssActivatedEvent = CEvent::kUnknown;
CEvent::Type IPlatformScreen::s_ssDeactivatedEvent = CEvent::kUnknown;
CEvent::Type
IPlatformScreen::getKeyDownEvent()
{
return CEvent::registerTypeOnce(s_keyDownEvent,
"IPlatformScreen::keyDown");
}
CEvent::Type
IPlatformScreen::getKeyUpEvent()
{
return CEvent::registerTypeOnce(s_keyUpEvent,
"IPlatformScreen::keyUp");
}
CEvent::Type
IPlatformScreen::getKeyRepeatEvent()
{
return CEvent::registerTypeOnce(s_keyRepeatEvent,
"IPlatformScreen::keyRepeat");
}
CEvent::Type
IPlatformScreen::getButtonDownEvent()
{
return CEvent::registerTypeOnce(s_buttonDownEvent,
"IPlatformScreen::buttonDown");
}
CEvent::Type
IPlatformScreen::getButtonUpEvent()
{
return CEvent::registerTypeOnce(s_buttonUpEvent,
"IPlatformScreen::buttonUp");
}
CEvent::Type
IPlatformScreen::getMotionOnPrimaryEvent()
{
return CEvent::registerTypeOnce(s_motionPrimaryEvent,
"IPlatformScreen::motionPrimary");
}
CEvent::Type
IPlatformScreen::getMotionOnSecondaryEvent()
{
return CEvent::registerTypeOnce(s_motionSecondaryEvent,
"IPlatformScreen::motionSecondary");
}
CEvent::Type
IPlatformScreen::getWheelEvent()
{
return CEvent::registerTypeOnce(s_wheelEvent,
"IPlatformScreen::wheel");
}
CEvent::Type
IPlatformScreen::getScreensaverActivatedEvent()
{
return CEvent::registerTypeOnce(s_ssActivatedEvent,
"IPlatformScreen::screensaverActivated");
}
CEvent::Type
IPlatformScreen::getScreensaverDeactivatedEvent()
{
return CEvent::registerTypeOnce(s_ssDeactivatedEvent,
"IPlatformScreen::screensaverDeactivated");
}
//
// IPlatformScreen::CKeyInfo
//
IPlatformScreen::CKeyInfo::CKeyInfo(KeyID id,
KeyModifierMask mask, KeyButton button, SInt32 count) :
m_key(id),
m_mask(mask),
m_button(button),
m_count(count)
{
// do nothing
}
//
// IPlatformScreen::CButtonInfo
//
IPlatformScreen::CButtonInfo::CButtonInfo(ButtonID id) :
m_button(id)
{
// do nothing
}
//
// IPlatformScreen::CMotionInfo
//
IPlatformScreen::CMotionInfo::CMotionInfo(SInt32 x, SInt32 y) :
m_x(x),
m_y(y)
{
// do nothing
}
//
// IPlatformScreen::CWheelInfo
//
IPlatformScreen::CWheelInfo::CWheelInfo(SInt32 wheel) :
m_wheel(wheel)
{
// do nothing
}

View File

@ -15,10 +15,12 @@
#ifndef IPLATFORMSCREEN_H #ifndef IPLATFORMSCREEN_H
#define IPLATFORMSCREEN_H #define IPLATFORMSCREEN_H
#include "IScreen.h"
#include "IPrimaryScreen.h" #include "IPrimaryScreen.h"
#include "ISecondaryScreen.h" #include "ISecondaryScreen.h"
#include "ClipboardTypes.h" #include "ClipboardTypes.h"
#include "OptionTypes.h" #include "OptionTypes.h"
#include "CEvent.h"
class IClipboard; class IClipboard;
class IKeyState; class IKeyState;
@ -27,27 +29,60 @@ class IKeyState;
/*! /*!
This interface defines the methods common to all platform dependent This interface defines the methods common to all platform dependent
screen implementations that are used by both primary and secondary screen implementations that are used by both primary and secondary
screens. screens. A platform screen is expected to post the events defined
in \c IScreen when appropriate. It should also post events defined
in \c IPlatformScreen if acting as the primary screen. The target
on the events should be the value returned by \c getEventTarget().
*/ */
class IPlatformScreen : public IPrimaryScreen, public ISecondaryScreen { class IPlatformScreen : public IScreen,
public IPrimaryScreen, public ISecondaryScreen {
public: public:
//! Key event data
class CKeyInfo {
public:
CKeyInfo(KeyID, KeyModifierMask, KeyButton, SInt32 count);
public:
KeyID m_key;
KeyModifierMask m_mask;
KeyButton m_button;
SInt32 m_count;
};
//! Button event data
class CButtonInfo {
public:
CButtonInfo(ButtonID);
public:
ButtonID m_button;
};
//! Motion event data
class CMotionInfo {
public:
CMotionInfo(SInt32 x, SInt32 y);
public:
SInt32 m_x;
SInt32 m_y;
};
//! Wheel motion event data
class CWheelInfo {
public:
CWheelInfo(SInt32);
public:
SInt32 m_wheel;
};
//! @name manipulators //! @name manipulators
//@{ //@{
//! Open screen //! Set the key state
/*! /*!
Called to open and initialize the screen. Throw XScreenUnavailable Sets the key state object. This object tracks keyboard state and
if the screen cannot be opened but retrying later may succeed. the screen is expected to keep it up to date.
Otherwise throw some other XScreenOpenFailure exception.
*/ */
virtual void open(IKeyState*) = 0; virtual void setKeyState(IKeyState*) = 0;
//! Close screen
/*!
Called to close the screen. close() should quietly ignore calls
that don't have a matching successful call to open().
*/
virtual void close() = 0;
//! Enable screen //! Enable screen
/*! /*!
@ -64,21 +99,6 @@ public:
*/ */
virtual void disable() = 0; virtual void disable() = 0;
//! Run event loop
/*!
Run the event loop and return when exitMainLoop() is called.
This must be called between a successful open() and close().
*/
virtual void mainLoop() = 0;
//! Exit event loop
/*!
Force mainLoop() to return. This call can return before
mainLoop() does (i.e. asynchronously). This may only be
called between a successful open() and close().
*/
virtual void exitMainLoop() = 0;
//! Enter screen //! Enter screen
/*! /*!
Called when the user navigates to this screen. Called when the user navigates to this screen.
@ -102,22 +122,19 @@ public:
//! Check clipboard owner //! Check clipboard owner
/*! /*!
Check ownership of all clipboards and notify an IScreenReceiver (set Check ownership of all clipboards and post grab events for any that
through some other interface) if any changed. This is used as a have changed. This is used as a backup in case the system doesn't
backup in case the system doesn't reliably report clipboard ownership reliably report clipboard ownership changes.
changes.
*/ */
virtual void checkClipboards() = 0; virtual void checkClipboards() = 0;
//! Open screen saver //! Open screen saver
/*! /*!
Open the screen saver. If \c notify is true then this object must Open the screen saver. If \c notify is true then this object must
call an IScreenEventHandler's (set through some other interface) send events when the screen saver activates or deactivates until
onScreenSaver() when the screensaver activates or deactivates until \c closeScreensaver() is called. If \c notify is false then the
it's closed. If \c notify is false then the screen saver is screen saver is disabled and restored on \c closeScreensaver().
disabled on open and restored on close.
*/ */
// XXX -- pass an interface pointer, not a notify flag
virtual void openScreensaver(bool notify) = 0; virtual void openScreensaver(bool notify) = 0;
//! Close screen saver //! Close screen saver
@ -154,6 +171,12 @@ public:
*/ */
virtual void updateKeys() = 0; virtual void updateKeys() = 0;
//! Set clipboard sequence number
/*!
Sets the sequence number to use in subsequent clipboard events.
*/
virtual void setSequenceNumber(UInt32) = 0;
//@} //@}
//! @name accessors //! @name accessors
//@{ //@{
@ -164,35 +187,49 @@ public:
*/ */
virtual bool isPrimary() const = 0; virtual bool isPrimary() const = 0;
//! Get clipboard //! Get key down event type. Event data is CKeyInfo*, count == 1.
static CEvent::Type getKeyDownEvent();
//! Get key up event type. Event data is CKeyInfo*, count == 1.
static CEvent::Type getKeyUpEvent();
//! Get key repeat event type. Event data is CKeyInfo*.
static CEvent::Type getKeyRepeatEvent();
//! Get button down event type. Event data is CButtonInfo*.
static CEvent::Type getButtonDownEvent();
//! Get button up event type. Event data is CButtonInfo*.
static CEvent::Type getButtonUpEvent();
//! Get mouse motion on the primary screen event type
/*! /*!
Save the contents of the clipboard indicated by \c id and return Event data is CMotionInfo* and the values are an absolute position.
true iff successful.
*/ */
virtual bool getClipboard(ClipboardID id, IClipboard*) const = 0; static CEvent::Type getMotionOnPrimaryEvent();
//! Get mouse motion on a secondary screen event type
//! Get screen shape
/*! /*!
Return the position of the upper-left corner of the screen in \c x and Event data is CMotionInfo* and the values are motion deltas not
\c y and the size of the screen in \c w (width) and \c h (height). absolute coordinates.
*/ */
virtual void getShape(SInt32& x, SInt32& y, static CEvent::Type getMotionOnSecondaryEvent();
SInt32& w, SInt32& h) const = 0; //! Get mouse wheel event type. Event data is CWheelInfo*.
static CEvent::Type getWheelEvent();
//! Get cursor position //! Get screensaver activated event type
/*! static CEvent::Type getScreensaverActivatedEvent();
Return the current position of the cursor in \c x and \c y. //! Get screensaver deactivated event type
*/ static CEvent::Type getScreensaverDeactivatedEvent();
virtual void getCursorPos(SInt32& x, SInt32& y) const = 0;
//@} //@}
// IScreen overrides
virtual void* getEventTarget() const = 0;
virtual bool getClipboard(ClipboardID id, IClipboard*) const = 0;
virtual void getShape(SInt32& x, SInt32& y,
SInt32& width, SInt32& height) const = 0;
virtual void getCursorPos(SInt32& x, SInt32& y) const = 0;
// IPrimaryScreen overrides // IPrimaryScreen overrides
virtual void reconfigure(UInt32 activeSides) = 0; virtual void reconfigure(UInt32 activeSides) = 0;
virtual void warpCursor(SInt32 x, SInt32 y) = 0; virtual void warpCursor(SInt32 x, SInt32 y) = 0;
virtual UInt32 addOneShotTimer(double timeout) = 0;
virtual SInt32 getJumpZoneSize() const = 0; virtual SInt32 getJumpZoneSize() const = 0;
virtual bool isAnyMouseButtonDown() const = 0; virtual bool isAnyMouseButtonDown() const = 0;
virtual void getCursorCenter(SInt32& x, SInt32& y) const = 0;
virtual const char* getKeyName(KeyButton) const = 0; virtual const char* getKeyName(KeyButton) const = 0;
// ISecondaryScreen overrides // ISecondaryScreen overrides
@ -205,6 +242,18 @@ public:
const IKeyState& keyState, KeyID id, const IKeyState& keyState, KeyID id,
KeyModifierMask desiredMask, KeyModifierMask desiredMask,
bool isAutoRepeat) const = 0; bool isAutoRepeat) const = 0;
private:
static CEvent::Type s_keyDownEvent;
static CEvent::Type s_keyUpEvent;
static CEvent::Type s_keyRepeatEvent;
static CEvent::Type s_buttonDownEvent;
static CEvent::Type s_buttonUpEvent;
static CEvent::Type s_motionPrimaryEvent;
static CEvent::Type s_motionSecondaryEvent;
static CEvent::Type s_wheelEvent;
static CEvent::Type s_ssActivatedEvent;
static CEvent::Type s_ssDeactivatedEvent;
}; };
#endif #endif

View File

@ -25,7 +25,6 @@ primary screen implementations.
*/ */
class IPrimaryScreen : public IInterface { class IPrimaryScreen : public IInterface {
public: public:
// XXX -- may need an interface for sending events
//! @name manipulators //! @name manipulators
//@{ //@{
@ -46,15 +45,6 @@ public:
*/ */
virtual void warpCursor(SInt32 x, SInt32 y) = 0; virtual void warpCursor(SInt32 x, SInt32 y) = 0;
//! Install a one-shot timer
/*!
Installs a one-shot timer for \c timeout seconds and returns the
id of the timer.
*/
// XXX -- need to specify the receiver of the event. or we should
// pass a job. need a method to remove the timer?
virtual UInt32 addOneShotTimer(double timeout) = 0;
//@} //@}
//! @name accessors //! @name accessors
//@{ //@{
@ -72,6 +62,14 @@ public:
*/ */
virtual bool isAnyMouseButtonDown() const = 0; virtual bool isAnyMouseButtonDown() const = 0;
//! Get cursor center position
/*!
Return the cursor center position which 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;
//! Get name of key //! Get name of key
/*! /*!
Return a string describing the given key. Return a string describing the given key.

View File

@ -1,73 +0,0 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2002 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef IPRIMARYSCREENRECEIVER_H
#define IPRIMARYSCREENRECEIVER_H
#include "IInterface.h"
#include "KeyTypes.h"
#include "MouseTypes.h"
//! Primary screen event receiver interface
/*!
The interface for receiving notification of events on the primary
screen. The server implements this interface to handle user input.
Platform dependent primary screen implementation will need to take
an IPrimaryScreenReceiver* and notify it of events.
*/
class IPrimaryScreenReceiver : public IInterface {
public:
//! Notify of screen saver change
/*!
Called when the screensaver is activated or deactivated.
*/
virtual void onScreensaver(bool activated) = 0;
//! Notify of one-shot timer expiration
/*!
Called when a one-shot timer expires.
*/
virtual void onOneShotTimerExpired(UInt32 id) = 0;
// call to notify of events. onMouseMovePrimary() returns
// true iff the mouse enters a jump zone and jumps.
//! Notify of key press
virtual void onKeyDown(KeyID, KeyModifierMask, KeyButton) = 0;
//! Notify of key release
virtual void onKeyUp(KeyID, KeyModifierMask, KeyButton) = 0;
//! Notify of key repeat
virtual void onKeyRepeat(KeyID, KeyModifierMask,
SInt32 count, KeyButton) = 0;
//! Notify of mouse button press
virtual void onMouseDown(ButtonID) = 0;
//! Notify of mouse button release
virtual void onMouseUp(ButtonID) = 0;
//! Notify of mouse motion
/*!
Called when the mouse has moved while on the primary screen. \c x
and \c y are the absolute screen position of the mouse. Return
true iff the mouse enters a jump zone and jumps.
*/
virtual bool onMouseMovePrimary(SInt32 x, SInt32 y) = 0;
//! Notify of mouse motion
/*!
Called when the mouse has moved while on the secondary screen.
\c dx and \c dy are the relative motion from the last position.
*/
virtual void onMouseMoveSecondary(SInt32 dx, SInt32 dy) = 0;
//! Notify of mouse wheen motion
virtual void onMouseWheel(SInt32 delta) = 0;
};
#endif

52
lib/synergy/IScreen.cpp Normal file
View File

@ -0,0 +1,52 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2004 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "IScreen.h"
//
// IScreen
//
CEvent::Type IScreen::s_errorEvent = CEvent::kUnknown;
CEvent::Type IScreen::s_shapeChangedEvent = CEvent::kUnknown;
CEvent::Type IScreen::s_clipboardGrabbedEvent = CEvent::kUnknown;
CEvent::Type IScreen::s_clipboardChangedEvent = CEvent::kUnknown;
CEvent::Type
IScreen::getErrorEvent()
{
return CEvent::registerTypeOnce(s_errorEvent,
"IScreen::error");
}
CEvent::Type
IScreen::getShapeChangedEvent()
{
return CEvent::registerTypeOnce(s_shapeChangedEvent,
"IScreen::shapeChanged");
}
CEvent::Type
IScreen::getClipboardGrabbedEvent()
{
return CEvent::registerTypeOnce(s_clipboardGrabbedEvent,
"IScreen::clipboardGrabbed");
}
CEvent::Type
IScreen::getClipboardChangedEvent()
{
return CEvent::registerTypeOnce(s_clipboardChangedEvent,
"IScreen::clipboardChanged");
}

106
lib/synergy/IScreen.h Normal file
View File

@ -0,0 +1,106 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2003 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef ISCREEN_H
#define ISCREEN_H
#include "IInterface.h"
#include "ClipboardTypes.h"
#include "CEvent.h"
class IClipboard;
//! Screen interface
/*!
This interface defines the methods common to all screens.
*/
class IScreen : public IInterface {
public:
struct CClipboardInfo {
public:
ClipboardID m_id;
UInt32 m_sequenceNumber;
};
//! @name accessors
//@{
//! Get event target
/*!
Returns the target used for events created by this object.
*/
virtual void* getEventTarget() const = 0;
//! Get clipboard
/*!
Save the contents of the clipboard indicated by \c id and return
true iff successful.
*/
virtual bool getClipboard(ClipboardID id, IClipboard*) const = 0;
//! Get screen shape
/*!
Return the position of the upper-left corner of the screen in \c x and
\c y and the size of the screen in \c width and \c height.
*/
virtual void getShape(SInt32& x, SInt32& y,
SInt32& width, SInt32& height) const = 0;
//! Get cursor position
/*!
Return the current position of the cursor in \c x and \c y.
*/
virtual void getCursorPos(SInt32& x, SInt32& y) const = 0;
//! Get error event type
/*!
Returns the error event type. This is sent whenever the screen has
failed for some reason (e.g. the X Windows server died).
*/
static CEvent::Type getErrorEvent();
//! Get shape changed event type
/*!
Returns the shape changed event type. This is sent whenever the
screen's shape changes, the cursor center moves, or the jump zone
size changes.
*/
static CEvent::Type getShapeChangedEvent();
//! Get clipboard grabbed event type
/*!
Returns the clipboard grabbed event type. This is sent whenever the
clipboard is grabbed by some other application so we don't own it
anymore. The data is a pointer to a CClipboardInfo.
*/
static CEvent::Type getClipboardGrabbedEvent();
//! Get clipboard changed event type
/*!
Returns the clipboard changed event type. This is sent whenever the
contents of the clipboard has changed. The data is a pointer to a
CClipboardInfo.
*/
static CEvent::Type getClipboardChangedEvent();
//@}
private:
static CEvent::Type s_errorEvent;
static CEvent::Type s_shapeChangedEvent;
static CEvent::Type s_clipboardGrabbedEvent;
static CEvent::Type s_clipboardChangedEvent;
};
#endif

View File

@ -1,41 +0,0 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2003 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef ISCREENFACTORY_H
#define ISCREENFACTORY_H
#include "IInterface.h"
class IPrimaryScreenReceiver;
class IPlatformScreen;
class IScreenReceiver;
//! Primary screen factory interface
/*!
This interface provides factory methods to create primary and
secondary screens.
*/
class IScreenFactory : public IInterface {
public:
//! Create screen
/*!
Create and return a screen. The caller must delete the returned
object. The screen is a primary screen iff the IPrimaryScreenReceiver
is not NULL.
*/
virtual IPlatformScreen*
create(IScreenReceiver*, IPrimaryScreenReceiver*) = 0;
};
#endif

View File

@ -1,65 +0,0 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2002 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef ISCREENRECEIVER_H
#define ISCREENRECEIVER_H
#include "IInterface.h"
#include "ClipboardTypes.h"
#include "ProtocolTypes.h"
#include "CString.h"
//! Screen event receiver interface
/*!
This interface defines the methods common to most types that receive
events for changes to a screen. Note that the methods in this
interface are similar to the methods in IServer but have different
parameters. This interface is suitable for client-side types.
*/
class IScreenReceiver : public IInterface {
public:
//! Notify of error
/*!
Called when the screen is unexpectedly closing. This implies that
the screen is no longer usable and that the program should close
the screen and probably terminate.
*/
virtual void onError() = 0;
//! Notify of client screen change
/*!
Called when the client's info has changed. For example, when the
screen resolution has changed.
*/
virtual void onInfoChanged(const CClientInfo&) = 0;
//! Notify of clipboad grab
/*!
Called when the clipboard was grabbed by another program and,
therefore, we no longer own it. Returns true if the grab was
honored, false otherwise.
*/
virtual bool onGrabClipboard(ClipboardID) = 0;
//! Notify of new clipboard data
/*!
Called when the data on the clipboard has changed because some
other program has changed it. \c data will have marshalled
clipboard data.
*/
virtual void onClipboardChanged(ClipboardID,
const CString& data) = 0;
};
#endif

View File

@ -16,6 +16,7 @@
#define ISCREENSAVER_H #define ISCREENSAVER_H
#include "IInterface.h" #include "IInterface.h"
#include "CEvent.h"
//! Screen saver interface //! Screen saver interface
/*! /*!

View File

@ -1,75 +0,0 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2002 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef ISERVER_H
#define ISERVER_H
#include "IInterface.h"
#include "ClipboardTypes.h"
#include "CString.h"
class CClientInfo;
//! Server interface
/*!
This interface defines the methods necessary for clients to
communicate with the server. Note that the methods in this
interface are similar to the methods in IScreenReceiver but
include extra parameters. This interface is suitable for
server-side client proxies. Client-side objects should use
the IScreenReceiver interface since the extra parameters are
meaningless on the client-side.
*/
class IServer : public IInterface {
public:
//! @name manipulators
//@{
//! Notify of error
/*!
Called when the screen is unexpectedly closing. This implies that
the screen is no longer usable and that the program should close
the screen and probably terminate.
*/
virtual void onError() = 0;
//! Notify of client screen change
/*!
Called when the client's info has changed.
*/
virtual void onInfoChanged(const CString& clientName,
const CClientInfo&) = 0;
//! Notify of clipboad grab
/*!
Called when the clipboard was grabbed by another program and,
therefore, we no longer own it. Returns true if the grab was
honored, false otherwise.
*/
virtual bool onGrabClipboard(const CString& clientName,
ClipboardID, UInt32 seqNum) = 0;
//! Notify of new clipboard data
/*!
Called when the data on the clipboard has changed because some
other program has changed it. \c data has the marshalled clipboard
data.
*/
virtual void onClipboardChanged(ClipboardID,
UInt32 seqNum, const CString& data) = 0;
//@}
};
#endif

View File

@ -29,6 +29,8 @@ libsynergy_a_SOURCES = \
CPacketStreamFilter.cpp \ CPacketStreamFilter.cpp \
CProtocolUtil.cpp \ CProtocolUtil.cpp \
CScreen.cpp \ CScreen.cpp \
IPlatformScreen.cpp \
IScreen.cpp \
XScreen.cpp \ XScreen.cpp \
XSynergy.cpp \ XSynergy.cpp \
CClipboard.h \ CClipboard.h \
@ -41,12 +43,9 @@ libsynergy_a_SOURCES = \
IKeyState.h \ IKeyState.h \
IPlatformScreen.h \ IPlatformScreen.h \
IPrimaryScreen.h \ IPrimaryScreen.h \
IPrimaryScreenReceiver.h \ IScreen.h \
IScreenFactory.h \
IScreenReceiver.h \
IScreenSaver.h \ IScreenSaver.h \
ISecondaryScreen.h \ ISecondaryScreen.h \
IServer.h \
KeyTypes.h \ KeyTypes.h \
MouseTypes.h \ MouseTypes.h \
OptionTypes.h \ OptionTypes.h \