Checkpoint. synergys now works. Still need to do lib/client and
synergyc.
This commit is contained in:
parent
c44c18bfdc
commit
1861f21fb5
|
@ -14,8 +14,8 @@
|
|||
|
||||
#include "CServerTaskBarReceiver.h"
|
||||
#include "CServer.h"
|
||||
#include "CEventQueue.h"
|
||||
#include "CLock.h"
|
||||
#include "TMethodJob.h"
|
||||
#include "CArch.h"
|
||||
|
||||
//
|
||||
|
@ -23,71 +23,80 @@
|
|||
//
|
||||
|
||||
CServerTaskBarReceiver::CServerTaskBarReceiver() :
|
||||
m_quit(NULL),
|
||||
m_state(kNotRunning),
|
||||
m_server(NULL)
|
||||
m_state(kNotRunning)
|
||||
{
|
||||
// create a job for getting notification when the server's
|
||||
// status changes.
|
||||
m_job = new TMethodJob<CServerTaskBarReceiver>(this,
|
||||
&CServerTaskBarReceiver::statusChanged, NULL);
|
||||
// do nothing
|
||||
}
|
||||
|
||||
CServerTaskBarReceiver::~CServerTaskBarReceiver()
|
||||
{
|
||||
if (m_server != NULL) {
|
||||
m_server->removeStatusJob(m_job);
|
||||
}
|
||||
delete m_job;
|
||||
delete m_quit;
|
||||
// do nothing
|
||||
}
|
||||
|
||||
#include "CLog.h"
|
||||
void
|
||||
CServerTaskBarReceiver::setServer(CServer* server)
|
||||
CServerTaskBarReceiver::updateStatus(CServer* server, const CString& errorMsg)
|
||||
{
|
||||
{
|
||||
// update our status
|
||||
CLock lock(&m_mutex);
|
||||
if (m_server != server) {
|
||||
if (m_server != NULL) {
|
||||
m_server->removeStatusJob(m_job);
|
||||
m_errorMessage = errorMsg;
|
||||
if (server == NULL) {
|
||||
if (m_errorMessage.empty()) {
|
||||
m_state = kNotRunning;
|
||||
}
|
||||
m_server = server;
|
||||
if (m_server != NULL) {
|
||||
m_server->addStatusJob(m_job);
|
||||
else {
|
||||
m_state = kNotWorking;
|
||||
}
|
||||
}
|
||||
else {
|
||||
m_clients.clear();
|
||||
server->getClients(m_clients);
|
||||
if (m_clients.size() <= 1) {
|
||||
m_state = kNotConnected;
|
||||
}
|
||||
else {
|
||||
m_state = kConnected;
|
||||
}
|
||||
}
|
||||
|
||||
// let subclasses have a go
|
||||
onStatusChanged(server);
|
||||
LOG((CLOG_INFO "### status: %s", getToolTip().c_str()));
|
||||
}
|
||||
|
||||
// tell task bar
|
||||
ARCH->updateReceiver(this);
|
||||
}
|
||||
|
||||
void
|
||||
CServerTaskBarReceiver::setState(EState state)
|
||||
{
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
m_state = state;
|
||||
}
|
||||
ARCH->updateReceiver(this);
|
||||
}
|
||||
|
||||
void
|
||||
CServerTaskBarReceiver::setQuitJob(IJob* job)
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
delete m_quit;
|
||||
m_quit = job;
|
||||
}
|
||||
|
||||
CServerTaskBarReceiver::EState
|
||||
CServerTaskBarReceiver::getState() const
|
||||
CServerTaskBarReceiver::getStatus() const
|
||||
{
|
||||
return m_state;
|
||||
}
|
||||
|
||||
CServer*
|
||||
CServerTaskBarReceiver::getServer() const
|
||||
const CString&
|
||||
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
|
||||
|
@ -110,7 +119,7 @@ CServerTaskBarReceiver::getToolTip() const
|
|||
return "Synergy: Not running";
|
||||
|
||||
case kNotWorking:
|
||||
return CString("Synergy: ") + m_errorMessage;
|
||||
return std::string("Synergy: ") + m_errorMessage;
|
||||
|
||||
case kNotConnected:
|
||||
return "Synergy: Waiting for clients";
|
||||
|
@ -122,50 +131,3 @@ CServerTaskBarReceiver::getToolTip() const
|
|||
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();
|
||||
}
|
||||
|
|
|
@ -18,61 +18,24 @@
|
|||
#include "CMutex.h"
|
||||
#include "CString.h"
|
||||
#include "IArchTaskBarReceiver.h"
|
||||
#include "stdvector.h"
|
||||
|
||||
class CServer;
|
||||
class IJob;
|
||||
|
||||
//! Implementation of IArchTaskBarReceiver for the synergy server
|
||||
class CServerTaskBarReceiver : public IArchTaskBarReceiver {
|
||||
public:
|
||||
enum EState {
|
||||
kNotRunning,
|
||||
kNotWorking,
|
||||
kNotConnected,
|
||||
kConnected,
|
||||
kMaxState
|
||||
};
|
||||
|
||||
CServerTaskBarReceiver();
|
||||
virtual ~CServerTaskBarReceiver();
|
||||
|
||||
//! @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*);
|
||||
|
||||
//! 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;
|
||||
void updateStatus(CServer*, const CString& errorMsg);
|
||||
|
||||
//@}
|
||||
|
||||
|
@ -86,6 +49,28 @@ public:
|
|||
virtual std::string getToolTip() const;
|
||||
|
||||
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();
|
||||
|
||||
//! Status change notification
|
||||
|
@ -93,18 +78,13 @@ protected:
|
|||
Called when status changes. The default implementation does
|
||||
nothing.
|
||||
*/
|
||||
virtual void onStatusChanged();
|
||||
|
||||
private:
|
||||
void statusChanged(void*);
|
||||
virtual void onStatusChanged(CServer* server);
|
||||
|
||||
private:
|
||||
CMutex m_mutex;
|
||||
IJob* m_quit;
|
||||
EState m_state;
|
||||
CServer* m_server;
|
||||
IJob* m_job;
|
||||
CString m_errorMessage;
|
||||
CClients m_clients;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -53,9 +53,3 @@ CXWindowsServerTaskBarReceiver::getIcon() const
|
|||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
CXWindowsServerTaskBarReceiver::onStatusChanged()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
|
|
@ -28,10 +28,6 @@ public:
|
|||
virtual void runMenu(int x, int y);
|
||||
virtual void primaryAction();
|
||||
virtual const Icon getIcon() const;
|
||||
|
||||
protected:
|
||||
// CServerTaskBarReceiver overrides
|
||||
virtual void onStatusChanged();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -12,22 +12,25 @@
|
|||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "CServer.h"
|
||||
#include "CClientListener.h"
|
||||
#include "CClientProxy.h"
|
||||
#include "CConfig.h"
|
||||
#include "IScreenFactory.h"
|
||||
#include "CPrimaryClient.h"
|
||||
#include "CServer.h"
|
||||
#include "CScreen.h"
|
||||
#include "ProtocolTypes.h"
|
||||
#include "Version.h"
|
||||
#include "XScreen.h"
|
||||
#include "CSocketMultiplexer.h"
|
||||
#include "CTCPSocketFactory.h"
|
||||
#include "XSocket.h"
|
||||
#include "CLock.h"
|
||||
#include "CMutex.h"
|
||||
#include "CThread.h"
|
||||
#include "XThread.h"
|
||||
#include "CFunctionJob.h"
|
||||
#include "CEventQueue.h"
|
||||
#include "CFunctionEventJob.h"
|
||||
#include "CLog.h"
|
||||
#include "LogOutputters.h"
|
||||
#include "CArch.h"
|
||||
#include "XArch.h"
|
||||
#include "stdfstream.h"
|
||||
#include <cstring>
|
||||
|
||||
|
@ -98,82 +101,243 @@ CArgs* CArgs::s_instance = NULL;
|
|||
// platform dependent factories
|
||||
//
|
||||
|
||||
//! Factory for creating screens
|
||||
/*!
|
||||
Objects of this type create screens appropriate for the platform.
|
||||
*/
|
||||
class CScreenFactory : public IScreenFactory {
|
||||
public:
|
||||
CScreenFactory() { }
|
||||
virtual ~CScreenFactory() { }
|
||||
|
||||
// IScreenFactory overrides
|
||||
virtual IPlatformScreen*
|
||||
create(IScreenReceiver*, IPrimaryScreenReceiver*);
|
||||
};
|
||||
|
||||
IPlatformScreen*
|
||||
CScreenFactory::create(IScreenReceiver* receiver,
|
||||
IPrimaryScreenReceiver* primaryReceiver)
|
||||
static
|
||||
CScreen*
|
||||
createScreen()
|
||||
{
|
||||
#if WINDOWS_LIKE
|
||||
return new CMSWindowsScreen(receiver, primaryReceiver);
|
||||
return new CScreen(new CMSWindowsScreen(true));
|
||||
#elif UNIX_LIKE
|
||||
return new CXWindowsScreen(receiver, primaryReceiver);
|
||||
return new CScreen(new CXWindowsScreen(true));
|
||||
#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
|
||||
//
|
||||
|
||||
static CServer* s_server = NULL;
|
||||
static CPrimaryClient* s_primaryClient = NULL;
|
||||
static CClientListener* s_listener = NULL;
|
||||
static CServerTaskBarReceiver* s_taskBarReceiver = NULL;
|
||||
|
||||
static
|
||||
int
|
||||
realMain(void)
|
||||
void
|
||||
updateStatus()
|
||||
{
|
||||
int result = kExitSuccess;
|
||||
do {
|
||||
bool opened = false;
|
||||
bool locked = true;
|
||||
s_taskBarReceiver->updateStatus(s_server, "");
|
||||
}
|
||||
|
||||
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()) {
|
||||
|
@ -190,74 +354,48 @@ realMain(void)
|
|||
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);
|
||||
// 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;
|
||||
}
|
||||
|
||||
// open server
|
||||
try {
|
||||
s_taskBarReceiver->setServer(s_server);
|
||||
s_server->open();
|
||||
opened = true;
|
||||
// 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 server
|
||||
// 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);
|
||||
locked = false;
|
||||
s_server->mainLoop();
|
||||
CEvent event;
|
||||
EVENTQUEUE->getEvent(event);
|
||||
while (event.getType() != CEvent::kQuit) {
|
||||
EVENTQUEUE->dispatchEvent(event);
|
||||
CEvent::deleteData(event);
|
||||
EVENTQUEUE->getEvent(event);
|
||||
}
|
||||
DAEMON_RUNNING(false);
|
||||
|
||||
// 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);
|
||||
// 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 result;
|
||||
return kExitSuccess;
|
||||
}
|
||||
|
||||
/* XXX
|
||||
static
|
||||
void
|
||||
realMainEntry(void* vresult)
|
||||
|
@ -293,7 +431,7 @@ runMainInThread(void)
|
|||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
//
|
||||
// command line parsing
|
||||
|
@ -666,9 +804,6 @@ daemonStartup(int argc, const char** argv)
|
|||
{
|
||||
CSystemLogger sysLogger(DAEMON_NAME);
|
||||
|
||||
// have to cancel this thread to quit
|
||||
s_taskBarReceiver->setQuitJob(new CQuitJob(CThread::getCurrentThread()));
|
||||
|
||||
// catch errors that would normally exit
|
||||
bye = &byeThrow;
|
||||
|
||||
|
@ -768,7 +903,6 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
|
|||
// through the task bar.
|
||||
s_taskBarReceiver = new CMSWindowsServerTaskBarReceiver(instance,
|
||||
&logBuffer);
|
||||
s_taskBarReceiver->setQuitJob(new CQuitJob(CThread::getCurrentThread()));
|
||||
|
||||
int result;
|
||||
try {
|
||||
|
@ -817,15 +951,20 @@ main(int argc, char** argv)
|
|||
{
|
||||
CArch arch;
|
||||
CLOG;
|
||||
CArgs args;
|
||||
|
||||
// go really fast
|
||||
CThread::getCurrentThread().setPriority(-14);
|
||||
|
||||
CSocketMultiplexer multiplexer;
|
||||
CEventQueue eventQueue;
|
||||
|
||||
// get program name
|
||||
CArgs args;
|
||||
ARG->m_pname = ARCH->getBasename(argv[0]);
|
||||
|
||||
// make the task bar receiver. the user can control this app
|
||||
// through the task bar.
|
||||
s_taskBarReceiver = new CXWindowsServerTaskBarReceiver;
|
||||
s_taskBarReceiver->setQuitJob(new CQuitJob(CThread::getCurrentThread()));
|
||||
|
||||
// parse command line
|
||||
parse(argc, argv);
|
||||
|
|
|
@ -555,6 +555,12 @@ CArch::isAnyAddr(CArchNetAddress addr)
|
|||
return m_net->isAnyAddr(addr);
|
||||
}
|
||||
|
||||
bool
|
||||
CArch::isEqualAddr(CArchNetAddress a, CArchNetAddress b)
|
||||
{
|
||||
return m_net->isEqualAddr(a, b);
|
||||
}
|
||||
|
||||
void
|
||||
CArch::sleep(double timeout)
|
||||
{
|
||||
|
|
|
@ -153,6 +153,7 @@ public:
|
|||
virtual void setAddrPort(CArchNetAddress, int port);
|
||||
virtual int getAddrPort(CArchNetAddress);
|
||||
virtual bool isAnyAddr(CArchNetAddress);
|
||||
virtual bool isEqualAddr(CArchNetAddress, CArchNetAddress);
|
||||
|
||||
// IArchSleep overrides
|
||||
virtual void sleep(double timeout);
|
||||
|
|
|
@ -575,6 +575,7 @@ CArchMultithreadPosix::interrupt()
|
|||
lockMutex(m_threadMutex);
|
||||
if (m_signalFunc != NULL) {
|
||||
m_signalFunc(m_signalUserData);
|
||||
pthread_kill(m_mainThread->m_thread, SIGWAKEUP);
|
||||
}
|
||||
else {
|
||||
ARCH->cancelThread(m_mainThread);
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include <arpa/inet.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#if HAVE_POLL
|
||||
# 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
|
||||
CArchNetworkBSD::throwError(int err)
|
||||
{
|
||||
|
|
|
@ -77,6 +77,7 @@ public:
|
|||
virtual void setAddrPort(CArchNetAddress, int port);
|
||||
virtual int getAddrPort(CArchNetAddress);
|
||||
virtual bool isAnyAddr(CArchNetAddress);
|
||||
virtual bool isEqualAddr(CArchNetAddress, CArchNetAddress);
|
||||
|
||||
private:
|
||||
void throwError(int);
|
||||
|
|
|
@ -265,6 +265,9 @@ public:
|
|||
//! Get the port of an address
|
||||
virtual int getAddrPort(CArchNetAddress) = 0;
|
||||
|
||||
//! Test addresses for equality
|
||||
virtual bool isEqualAddr(CArchNetAddress, CArchNetAddress) = 0;
|
||||
|
||||
//! Test for the "any" address
|
||||
/*!
|
||||
Returns true if \c addr is the "any" address. \c newAnyAddr()
|
||||
|
|
|
@ -56,7 +56,6 @@ ARCH_STRING::vsnprintf(char* str, int size, const char* fmt, va_list ap)
|
|||
|
||||
#else // !HAVE_VSNPRINTF && !UNIX_LIKE
|
||||
|
||||
// FIXME
|
||||
#error vsnprintf not implemented
|
||||
|
||||
#endif // !HAVE_VSNPRINTF
|
||||
|
|
|
@ -13,13 +13,12 @@
|
|||
*/
|
||||
|
||||
#include "CEvent.h"
|
||||
#include "CEventQueue.h"
|
||||
|
||||
//
|
||||
// CEvent
|
||||
//
|
||||
|
||||
CEvent::Type CEvent::s_nextType = kLast;
|
||||
|
||||
CEvent::CEvent() :
|
||||
m_type(kUnknown),
|
||||
m_target(NULL),
|
||||
|
@ -55,20 +54,21 @@ CEvent::getData() const
|
|||
}
|
||||
|
||||
CEvent::Type
|
||||
CEvent::registerType()
|
||||
CEvent::registerType(const char* name)
|
||||
{
|
||||
// FIXME -- lock mutex (need a mutex)
|
||||
return s_nextType++;
|
||||
return EVENTQUEUE->registerType(name);
|
||||
}
|
||||
|
||||
CEvent::Type
|
||||
CEvent::registerTypeOnce(Type& type)
|
||||
CEvent::registerTypeOnce(Type& type, const char* name)
|
||||
{
|
||||
// FIXME -- lock mutex (need a mutex)
|
||||
if (type == CEvent::kUnknown) {
|
||||
type = s_nextType++;
|
||||
return EVENTQUEUE->registerTypeOnce(type, name);
|
||||
}
|
||||
return type;
|
||||
|
||||
const char*
|
||||
CEvent::getTypeName(Type type)
|
||||
{
|
||||
return EVENTQUEUE->getTypeName(type);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#define CEVENT_H
|
||||
|
||||
#include "BasicTypes.h"
|
||||
#include "stdmap.h"
|
||||
|
||||
//! Event
|
||||
/*!
|
||||
|
@ -46,6 +47,33 @@ public:
|
|||
//! @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
|
||||
//@{
|
||||
|
@ -68,33 +96,12 @@ public:
|
|||
*/
|
||||
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:
|
||||
Type m_type;
|
||||
void* m_target;
|
||||
void* m_data;
|
||||
static Type s_nextType;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -13,7 +13,9 @@
|
|||
*/
|
||||
|
||||
#include "CEventQueue.h"
|
||||
#include "CLog.h"
|
||||
#include "CSimpleEventQueueBuffer.h"
|
||||
#include "CStopwatch.h"
|
||||
#include "IEventJob.h"
|
||||
#include "CArch.h"
|
||||
|
||||
|
@ -30,7 +32,8 @@ interrupt(void*)
|
|||
// CEventQueue
|
||||
//
|
||||
|
||||
CEventQueue::CEventQueue()
|
||||
CEventQueue::CEventQueue() :
|
||||
m_nextType(CEvent::kLast)
|
||||
{
|
||||
setInstance(this);
|
||||
m_mutex = ARCH->newMutex();
|
||||
|
@ -46,6 +49,54 @@ CEventQueue::~CEventQueue()
|
|||
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
|
||||
CEventQueue::adoptBuffer(IEventQueueBuffer* buffer)
|
||||
{
|
||||
|
@ -69,34 +120,44 @@ CEventQueue::adoptBuffer(IEventQueueBuffer* buffer)
|
|||
bool
|
||||
CEventQueue::getEvent(CEvent& event, double timeout)
|
||||
{
|
||||
CStopwatch timer(true);
|
||||
retry:
|
||||
// if no events are waiting then handle timers and then wait
|
||||
if (m_buffer->isEmpty()) {
|
||||
while (m_buffer->isEmpty()) {
|
||||
// handle timers first
|
||||
if (hasTimerExpired(event)) {
|
||||
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
|
||||
// and it'll expire before the client's timeout then use
|
||||
// that duration for our timeout instead.
|
||||
double timerTimeout = getNextTimerTimeout();
|
||||
if (timerTimeout >= 0.0 && timerTimeout < timeout) {
|
||||
timeout = timerTimeout;
|
||||
if (timeout < 0.0 || (timerTimeout >= 0.0 && timerTimeout < timeLeft)) {
|
||||
timeLeft = timerTimeout;
|
||||
}
|
||||
|
||||
// wait for an event
|
||||
m_buffer->waitForEvent(timeout);
|
||||
}
|
||||
|
||||
// if no events are pending then do the timers
|
||||
if (m_buffer->isEmpty()) {
|
||||
return hasTimerExpired(event);
|
||||
m_buffer->waitForEvent(timeLeft);
|
||||
}
|
||||
|
||||
// get the event
|
||||
UInt32 dataID;
|
||||
IEventQueueBuffer::Type type = m_buffer->getEvent(event, dataID);
|
||||
switch (type) {
|
||||
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;
|
||||
|
||||
case IEventQueueBuffer::kSystem:
|
||||
|
@ -156,9 +217,16 @@ CEventQueue::newTimer(double duration, void* target)
|
|||
assert(duration > 0.0);
|
||||
|
||||
CEventQueueTimer* timer = m_buffer->newTimer(duration, false);
|
||||
if (target == NULL) {
|
||||
target = timer;
|
||||
}
|
||||
CArchMutexLock lock(m_mutex);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -168,9 +236,16 @@ CEventQueue::newOneShotTimer(double duration, void* target)
|
|||
assert(duration > 0.0);
|
||||
|
||||
CEventQueueTimer* timer = m_buffer->newTimer(duration, true);
|
||||
if (target == NULL) {
|
||||
target = timer;
|
||||
}
|
||||
CArchMutexLock lock(m_mutex);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -401,13 +476,13 @@ CEventQueue::CTypeTarget::operator<(const CTypeTarget& tt) const
|
|||
// CEventQueue::CTimer
|
||||
//
|
||||
|
||||
CEventQueue::CTimer::CTimer(CEventQueueTimer* timer,
|
||||
double timeout, void* target, bool oneShot) :
|
||||
CEventQueue::CTimer::CTimer(CEventQueueTimer* timer, double timeout,
|
||||
double initialTime, void* target, bool oneShot) :
|
||||
m_timer(timer),
|
||||
m_timeout(timeout),
|
||||
m_target(target),
|
||||
m_oneShot(oneShot),
|
||||
m_time(timeout)
|
||||
m_time(initialTime)
|
||||
{
|
||||
assert(m_timeout > 0.0);
|
||||
}
|
||||
|
|
|
@ -39,9 +39,9 @@ public:
|
|||
virtual bool dispatchEvent(const CEvent& event);
|
||||
virtual void addEvent(const CEvent& event);
|
||||
virtual CEventQueueTimer*
|
||||
newTimer(double duration, void* target = NULL);
|
||||
newTimer(double duration, void* target);
|
||||
virtual CEventQueueTimer*
|
||||
newOneShotTimer(double duration, void* target = NULL);
|
||||
newOneShotTimer(double duration, void* target);
|
||||
virtual void deleteTimer(CEventQueueTimer*);
|
||||
virtual void adoptHandler(void* target, IEventJob* dispatcher);
|
||||
virtual void adoptHandler(CEvent::Type type,
|
||||
|
@ -50,8 +50,13 @@ public:
|
|||
virtual IEventJob* orphanHandler(CEvent::Type type, void* target);
|
||||
virtual void removeHandler(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 IEventJob* getHandler(CEvent::Type type, void* target) const;
|
||||
virtual const char* getTypeName(CEvent::Type type);
|
||||
|
||||
private:
|
||||
void doAdoptHandler(CEvent::Type type,
|
||||
|
@ -77,7 +82,8 @@ private:
|
|||
};
|
||||
class CTimer {
|
||||
public:
|
||||
CTimer(CEventQueueTimer*, double timeout, void* target, bool oneShot);
|
||||
CTimer(CEventQueueTimer*, double timeout, double initialTime,
|
||||
void* target, bool oneShot);
|
||||
~CTimer();
|
||||
|
||||
void reset();
|
||||
|
@ -106,19 +112,28 @@ private:
|
|||
typedef std::map<UInt32, CEvent> CEventTable;
|
||||
typedef std::vector<UInt32> CEventIDList;
|
||||
typedef std::map<CTypeTarget, IEventJob*> CHandlerTable;
|
||||
typedef std::map<CEvent::Type, const char*> CTypeMap;
|
||||
|
||||
CArchMutex m_mutex;
|
||||
|
||||
// registered events
|
||||
CEvent::Type m_nextType;
|
||||
CTypeMap m_typeMap;
|
||||
|
||||
// buffer of events
|
||||
IEventQueueBuffer* m_buffer;
|
||||
|
||||
// saved events
|
||||
CEventTable m_events;
|
||||
CEventIDList m_oldEventIDs;
|
||||
|
||||
// timers
|
||||
CStopwatch m_time;
|
||||
CTimers m_timers;
|
||||
CTimerQueue m_timerQueue;
|
||||
CTimerEvent m_timerEvent;
|
||||
|
||||
// event handlers
|
||||
CHandlerTable m_handlers;
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -176,7 +176,7 @@ CStringUtil::CaselessCmp::cmpEqual(
|
|||
const CString::value_type& a,
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -185,7 +185,7 @@ CStringUtil::CaselessCmp::cmpLess(
|
|||
const CString::value_type& a,
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -80,7 +80,8 @@ public:
|
|||
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
|
||||
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
|
||||
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).
|
||||
*/
|
||||
virtual CEventQueueTimer*
|
||||
newTimer(double duration, void* target = NULL) = 0;
|
||||
newTimer(double duration, void* target) = 0;
|
||||
|
||||
//! Create a one-shot timer
|
||||
/*!
|
||||
|
@ -99,11 +100,12 @@ public:
|
|||
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
|
||||
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*
|
||||
newOneShotTimer(double duration,
|
||||
void* target = NULL) = 0;
|
||||
void* target) = 0;
|
||||
|
||||
//! Destroy a timer
|
||||
/*!
|
||||
|
@ -160,6 +162,23 @@ public:
|
|||
*/
|
||||
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
|
||||
//@{
|
||||
|
@ -179,6 +198,13 @@ public:
|
|||
*/
|
||||
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
|
||||
/*!
|
||||
Returns the target to use for dispatching \c CEvent::kSystem events.
|
||||
|
|
|
@ -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
|
|
@ -27,29 +27,34 @@ CEvent::Type IStream::s_outputShutdownEvent = CEvent::kUnknown;
|
|||
CEvent::Type
|
||||
IStream::getInputReadyEvent()
|
||||
{
|
||||
return CEvent::registerTypeOnce(s_inputReadyEvent);
|
||||
return CEvent::registerTypeOnce(s_inputReadyEvent,
|
||||
"IStream::inputReady");
|
||||
}
|
||||
|
||||
CEvent::Type
|
||||
IStream::getOutputFlushedEvent()
|
||||
{
|
||||
return CEvent::registerTypeOnce(s_outputFlushedEvent);
|
||||
return CEvent::registerTypeOnce(s_outputFlushedEvent,
|
||||
"IStream::outputFlushed");
|
||||
}
|
||||
|
||||
CEvent::Type
|
||||
IStream::getOutputErrorEvent()
|
||||
{
|
||||
return CEvent::registerTypeOnce(s_outputErrorEvent);
|
||||
return CEvent::registerTypeOnce(s_outputErrorEvent,
|
||||
"IStream::outputError");
|
||||
}
|
||||
|
||||
CEvent::Type
|
||||
IStream::getInputShutdownEvent()
|
||||
{
|
||||
return CEvent::registerTypeOnce(s_inputShutdownEvent);
|
||||
return CEvent::registerTypeOnce(s_inputShutdownEvent,
|
||||
"IStream::inputShutdown");
|
||||
}
|
||||
|
||||
CEvent::Type
|
||||
IStream::getOutputShutdownEvent()
|
||||
{
|
||||
return CEvent::registerTypeOnce(s_outputShutdownEvent);
|
||||
return CEvent::registerTypeOnce(s_outputShutdownEvent,
|
||||
"IStream::outputShutdown");
|
||||
}
|
||||
|
|
|
@ -141,6 +141,18 @@ CNetworkAddress::operator=(const CNetworkAddress& addr)
|
|||
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
|
||||
CNetworkAddress::isValid() const
|
||||
{
|
||||
|
|
|
@ -55,6 +55,18 @@ public:
|
|||
//! @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
|
||||
/*!
|
||||
Returns true if this is not the invalid address.
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "CLock.h"
|
||||
#include "CMutex.h"
|
||||
#include "CThread.h"
|
||||
#include "CLog.h"
|
||||
#include "TMethodJob.h"
|
||||
#include "CArch.h"
|
||||
#include "XArch.h"
|
||||
|
@ -207,8 +208,8 @@ CSocketMultiplexer::serviceThread(void*)
|
|||
// check for status
|
||||
status = ARCH->pollSocket(&pfds[0], pfds.size(), -1);
|
||||
}
|
||||
catch (XArchNetwork&) {
|
||||
// FIXME -- uh oh
|
||||
catch (XArchNetwork& e) {
|
||||
LOG((CLOG_WARN "error in socket multiplexer: %s", e.what().c_str()));
|
||||
status = 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -62,6 +62,7 @@ CTCPListenSocket::bind(const CNetworkAddress& addr)
|
|||
CLock lock(m_mutex);
|
||||
ARCH->bindSocket(m_socket, addr.getAddress());
|
||||
ARCH->listenOnSocket(m_socket);
|
||||
ARCH->setBlockingOnSocket(m_socket, false);
|
||||
CSocketMultiplexer::getInstance()->addSocket(this,
|
||||
new TSocketMultiplexerMethodJob<CTCPListenSocket>(
|
||||
this, &CTCPListenSocket::serviceListening,
|
||||
|
@ -102,11 +103,13 @@ IDataSocket*
|
|||
CTCPListenSocket::accept()
|
||||
{
|
||||
try {
|
||||
IDataSocket* socket =
|
||||
new CTCPSocket(ARCH->acceptSocket(m_socket, NULL));
|
||||
CSocketMultiplexer::getInstance()->addSocket(this,
|
||||
new TSocketMultiplexerMethodJob<CTCPListenSocket>(
|
||||
this, &CTCPListenSocket::serviceListening,
|
||||
m_socket, true, false));
|
||||
return new CTCPSocket(ARCH->acceptSocket(m_socket, NULL));
|
||||
return socket;
|
||||
}
|
||||
catch (XArchNetwork&) {
|
||||
return NULL;
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "XSocket.h"
|
||||
#include "CLock.h"
|
||||
#include "CEventQueue.h"
|
||||
#include "CLog.h"
|
||||
#include "IEventJob.h"
|
||||
#include "CArch.h"
|
||||
#include "XArch.h"
|
||||
|
@ -102,8 +103,8 @@ CTCPSocket::close()
|
|||
ARCH->closeSocket(socket);
|
||||
}
|
||||
catch (XArchNetwork& e) {
|
||||
// FIXME -- just discard this for now
|
||||
//throw XSocketIOClose(e.what());
|
||||
// ignore, there's not much we can do
|
||||
LOG((CLOG_WARN "error closing socket: %s", e.what().c_str()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -257,7 +258,6 @@ CTCPSocket::connect(const CNetworkAddress& addr)
|
|||
}
|
||||
|
||||
try {
|
||||
// FIXME -- don't throw if in progress, just return that info
|
||||
ARCH->connectSocket(m_socket, addr.getAddress());
|
||||
sendSocketEvent(getConnectedEvent());
|
||||
onConnected();
|
||||
|
@ -281,15 +281,13 @@ CTCPSocket::init()
|
|||
m_readable = false;
|
||||
m_writable = false;
|
||||
|
||||
try {
|
||||
// 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 {
|
||||
ARCH->setNoDelayOnSocket(m_socket, true);
|
||||
}
|
||||
catch (XArchNetwork& e) {
|
||||
|
|
|
@ -24,11 +24,13 @@ CEvent::Type IDataSocket::s_failedEvent = CEvent::kUnknown;
|
|||
CEvent::Type
|
||||
IDataSocket::getConnectedEvent()
|
||||
{
|
||||
return CEvent::registerTypeOnce(s_connectedEvent);
|
||||
return CEvent::registerTypeOnce(s_connectedEvent,
|
||||
"IDataSocket::connected");
|
||||
}
|
||||
|
||||
CEvent::Type
|
||||
IDataSocket::getConnectionFailedEvent()
|
||||
{
|
||||
return CEvent::registerTypeOnce(s_failedEvent);
|
||||
return CEvent::registerTypeOnce(s_failedEvent,
|
||||
"IDataSocket::failed");
|
||||
}
|
||||
|
|
|
@ -23,5 +23,6 @@ CEvent::Type IListenSocket::s_connectingEvent = CEvent::kUnknown;
|
|||
CEvent::Type
|
||||
IListenSocket::getConnectingEvent()
|
||||
{
|
||||
return CEvent::registerTypeOnce(s_connectingEvent);
|
||||
return CEvent::registerTypeOnce(s_connectingEvent,
|
||||
"IListenSocket::connecting");
|
||||
}
|
||||
|
|
|
@ -23,5 +23,6 @@ CEvent::Type ISocket::s_disconnectedEvent = CEvent::kUnknown;
|
|||
CEvent::Type
|
||||
ISocket::getDisconnectedEvent()
|
||||
{
|
||||
return CEvent::registerTypeOnce(s_disconnectedEvent);
|
||||
return CEvent::registerTypeOnce(s_disconnectedEvent,
|
||||
"ISocket::disconnected");
|
||||
}
|
||||
|
|
|
@ -12,9 +12,10 @@
|
|||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "CXWindowsEventQueue.h"
|
||||
#include "CEvent.h"
|
||||
#include "CXWindowsEventQueueBuffer.h"
|
||||
#include "CThread.h"
|
||||
#include "CEvent.h"
|
||||
#include "IEventQueue.h"
|
||||
#if UNIX_LIKE
|
||||
# if HAVE_POLL
|
||||
# include <sys/poll.h>
|
||||
|
@ -42,52 +43,27 @@ class CEventQueueTimer { };
|
|||
|
||||
|
||||
//
|
||||
// CXWindowsEventQueue
|
||||
// CXWindowsEventQueueBuffer
|
||||
//
|
||||
|
||||
CXWindowsEventQueue::CXWindowsEventQueue(Display* display) :
|
||||
m_display(display)
|
||||
CXWindowsEventQueueBuffer::CXWindowsEventQueueBuffer(
|
||||
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);
|
||||
|
||||
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
|
||||
CXWindowsEventQueue::processSystemEvent(CEvent& event)
|
||||
{
|
||||
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)
|
||||
CXWindowsEventQueueBuffer::waitForEvent(double dtimeout)
|
||||
{
|
||||
// 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.
|
||||
|
@ -132,25 +108,27 @@ CXWindowsEventQueue::waitForEvent(double dtimeout)
|
|||
CThread::testCancel();
|
||||
}
|
||||
|
||||
bool
|
||||
CXWindowsEventQueue::doGetEvent(CEvent& event)
|
||||
IEventQueueBuffer::Type
|
||||
CXWindowsEventQueueBuffer::getEvent(CEvent& event, UInt32& dataID)
|
||||
{
|
||||
// get next event
|
||||
XNextEvent(m_display, &m_event);
|
||||
|
||||
// process event
|
||||
if (m_event.xany.type == ClientMessage) {
|
||||
processClientMessage(event);
|
||||
if (m_event.xany.type == ClientMessage &&
|
||||
m_event.xclient.message_type == m_userEvent) {
|
||||
dataID = static_cast<UInt32>(m_event.xclient.data.l[0]);
|
||||
return kUser;
|
||||
}
|
||||
else {
|
||||
processSystemEvent(event);
|
||||
event = CEvent(CEvent::kSystem,
|
||||
IEventQueue::getSystemTarget(), &m_event);
|
||||
return kSystem;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CXWindowsEventQueue::doAddEvent(CEvent::Type type, UInt32 dataID)
|
||||
CXWindowsEventQueueBuffer::addEvent(UInt32 dataID)
|
||||
{
|
||||
// send ourself a message
|
||||
XEvent xevent;
|
||||
|
@ -158,25 +136,29 @@ CXWindowsEventQueue::doAddEvent(CEvent::Type type, UInt32 dataID)
|
|||
xevent.xclient.window = m_window;
|
||||
xevent.xclient.message_type = m_userEvent;
|
||||
xevent.xclient.format = 32;
|
||||
xevent.xclient.data.l[0] = static_cast<long>(type);
|
||||
xevent.xclient.data.l[1] = static_cast<long>(dataID);
|
||||
return (XSendEvent(m_display, m_window, False, 0, &xevent) != 0);
|
||||
xevent.xclient.data.l[0] = static_cast<long>(dataID);
|
||||
if (XSendEvent(m_display, m_window, False, 0, &xevent) == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// force waitForEvent() to return
|
||||
XFlush(m_display);
|
||||
}
|
||||
|
||||
bool
|
||||
CXWindowsEventQueue::doIsEmpty() const
|
||||
CXWindowsEventQueueBuffer::isEmpty() const
|
||||
{
|
||||
return (XPending(m_display) == 0);
|
||||
}
|
||||
|
||||
CEventQueueTimer*
|
||||
CXWindowsEventQueue::doNewTimer(double, bool) const
|
||||
CXWindowsEventQueueBuffer::newTimer(double, bool) const
|
||||
{
|
||||
return new CEventQueueTimer();
|
||||
}
|
||||
|
||||
void
|
||||
CXWindowsEventQueue::doDeleteTimer(CEventQueueTimer* timer) const
|
||||
CXWindowsEventQueueBuffer::deleteTimer(CEventQueueTimer* timer) const
|
||||
{
|
||||
delete timer;
|
||||
}
|
|
@ -12,44 +12,30 @@
|
|||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef CXWINDOWSEVENTQUEUE_H
|
||||
#define CXWINDOWSEVENTQUEUE_H
|
||||
#ifndef CXWINDOWSEVENTQUEUEBUFFER_H
|
||||
#define CXWINDOWSEVENTQUEUEBUFFER_H
|
||||
|
||||
#include "CEventQueue.h"
|
||||
#include "IEventQueueBuffer.h"
|
||||
#if defined(X_DISPLAY_MISSING)
|
||||
# error X11 is required to build synergy
|
||||
#else
|
||||
# include <X11/Xlib.h>
|
||||
#endif
|
||||
|
||||
//! Event queue for X11
|
||||
class CXWindowsEventQueue : public CEventQueue {
|
||||
//! Event queue buffer for X11
|
||||
class CXWindowsEventQueueBuffer : public IEventQueueBuffer {
|
||||
public:
|
||||
CXWindowsEventQueue(Display*);
|
||||
virtual ~CXWindowsEventQueue();
|
||||
CXWindowsEventQueueBuffer(Display*, Window);
|
||||
virtual ~CXWindowsEventQueueBuffer();
|
||||
|
||||
//! @name manipulators
|
||||
//@{
|
||||
|
||||
//@}
|
||||
//! @name accessors
|
||||
//@{
|
||||
|
||||
//@}
|
||||
|
||||
protected:
|
||||
// CEventQueue overrides
|
||||
// IEventQueueBuffer overrides
|
||||
virtual void waitForEvent(double timeout);
|
||||
virtual bool doGetEvent(CEvent& event);
|
||||
virtual bool doAddEvent(CEvent::Type type, UInt32 dataID);
|
||||
virtual bool doIsEmpty() const;
|
||||
virtual Type getEvent(CEvent& event, UInt32& dataID);
|
||||
virtual bool addEvent(UInt32 dataID);
|
||||
virtual bool isEmpty() const;
|
||||
virtual CEventQueueTimer*
|
||||
doNewTimer(double duration, bool oneShot) const;
|
||||
virtual void doDeleteTimer(CEventQueueTimer*) const;
|
||||
|
||||
private:
|
||||
void processSystemEvent(CEvent& event);
|
||||
void processClientMessage(CEvent& event);
|
||||
newTimer(double duration, bool oneShot) const;
|
||||
virtual void deleteTimer(CEventQueueTimer*) const;
|
||||
|
||||
private:
|
||||
Display* m_display;
|
File diff suppressed because it is too large
Load Diff
|
@ -17,9 +17,6 @@
|
|||
|
||||
#include "IPlatformScreen.h"
|
||||
#include "CXWindowsKeyMapper.h"
|
||||
#include "CMutex.h"
|
||||
#include "CStopwatch.h"
|
||||
#include "CPriorityQueue.h"
|
||||
#include "stdvector.h"
|
||||
#if defined(X_DISPLAY_MISSING)
|
||||
# error X11 is required to build synergy
|
||||
|
@ -29,43 +26,22 @@
|
|||
|
||||
class CXWindowsClipboard;
|
||||
class CXWindowsScreenSaver;
|
||||
class IJob;
|
||||
class IScreenReceiver;
|
||||
class IPrimaryScreenReceiver;
|
||||
|
||||
//! Implementation of IPlatformScreen for X11
|
||||
class CXWindowsScreen : public IPlatformScreen {
|
||||
public:
|
||||
CXWindowsScreen(IScreenReceiver*, IPrimaryScreenReceiver*);
|
||||
CXWindowsScreen(bool isPrimary);
|
||||
virtual ~CXWindowsScreen();
|
||||
|
||||
//! @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
|
||||
virtual void open(IKeyState*);
|
||||
virtual void close();
|
||||
virtual void setKeyState(IKeyState*);
|
||||
virtual void enable();
|
||||
virtual void disable();
|
||||
virtual void mainLoop();
|
||||
virtual void exitMainLoop();
|
||||
virtual void enter();
|
||||
virtual bool leave();
|
||||
virtual bool setClipboard(ClipboardID, const IClipboard*);
|
||||
|
@ -76,17 +52,22 @@ public:
|
|||
virtual void resetOptions();
|
||||
virtual void setOptions(const COptionsList& options);
|
||||
virtual void updateKeys();
|
||||
virtual void setSequenceNumber(UInt32);
|
||||
virtual bool isPrimary() const;
|
||||
virtual bool getClipboard(ClipboardID, IClipboard*) const;
|
||||
virtual void getShape(SInt32&, SInt32&, SInt32&, SInt32&) const;
|
||||
virtual void getCursorPos(SInt32&, SInt32&) 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;
|
||||
|
||||
// IPrimaryScreen overrides
|
||||
virtual void reconfigure(UInt32 activeSides);
|
||||
virtual void warpCursor(SInt32 x, SInt32 y);
|
||||
virtual UInt32 addOneShotTimer(double timeout);
|
||||
virtual SInt32 getJumpZoneSize() const;
|
||||
virtual bool isAnyMouseButtonDown() const;
|
||||
virtual void getCursorCenter(SInt32& x, SInt32& y) const;
|
||||
virtual const char* getKeyName(KeyButton) const;
|
||||
|
||||
// ISecondaryScreen overrides
|
||||
|
@ -101,18 +82,16 @@ public:
|
|||
bool isAutoRepeat) const;
|
||||
|
||||
private:
|
||||
// process events before dispatching to receiver
|
||||
void onEvent(XEvent* event);
|
||||
// event sending
|
||||
void sendEvent(CEvent::Type, void* = NULL);
|
||||
void sendClipboardEvent(CEvent::Type, ClipboardID);
|
||||
|
||||
// event handling
|
||||
void handleSystemEvent(const CEvent&, void*);
|
||||
|
||||
// create the transparent cursor
|
||||
Cursor createBlankCursor() const;
|
||||
|
||||
// remove a timer without locking
|
||||
void removeTimerNoLock(IJob*);
|
||||
|
||||
// process timers
|
||||
bool processTimers();
|
||||
|
||||
// determine the clipboard from the X selection. returns
|
||||
// kClipboardEnd if no such clipboard.
|
||||
ClipboardID getClipboardID(Atom selection) const;
|
||||
|
@ -125,40 +104,10 @@ private:
|
|||
void destroyClipboardRequest(Window window);
|
||||
|
||||
// X I/O error handler
|
||||
void onError();
|
||||
static int ioErrorHandler(Display*);
|
||||
|
||||
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 {
|
||||
public:
|
||||
int m_event;
|
||||
|
@ -167,9 +116,9 @@ private:
|
|||
KeyCode m_keycode;
|
||||
};
|
||||
|
||||
bool isQuitEvent(XEvent*) const;
|
||||
|
||||
Window createWindow() const;
|
||||
Display* openDisplay() const;
|
||||
void saveShape();
|
||||
Window openWindow() const;
|
||||
void openIM();
|
||||
|
||||
bool grabMouseAndKeyboard();
|
||||
|
@ -193,21 +142,13 @@ private:
|
|||
static Bool findKeyEvent(Display*, XEvent* xevent, XPointer arg);
|
||||
|
||||
private:
|
||||
typedef CPriorityQueue<CTimer> CTimerPriorityQueue;
|
||||
|
||||
// true if screen is being used as a primary screen, false otherwise
|
||||
bool m_isPrimary;
|
||||
|
||||
// X is not thread safe
|
||||
CMutex m_mutex;
|
||||
|
||||
Display* m_display;
|
||||
Window m_root;
|
||||
Window m_window;
|
||||
|
||||
IScreenReceiver* m_receiver;
|
||||
IPrimaryScreenReceiver* m_primaryReceiver;
|
||||
|
||||
// true if mouse has entered the screen
|
||||
bool m_isOnScreen;
|
||||
|
||||
|
@ -230,20 +171,11 @@ private:
|
|||
|
||||
// clipboards
|
||||
CXWindowsClipboard* m_clipboard[kClipboardEnd];
|
||||
|
||||
// the quit message
|
||||
Atom m_atomQuit;
|
||||
UInt32 m_sequenceNumber;
|
||||
|
||||
// screen saver stuff
|
||||
CXWindowsScreenSaver* m_screensaver;
|
||||
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
|
||||
// physical button for logical button i+1.
|
||||
|
|
|
@ -13,10 +13,12 @@
|
|||
*/
|
||||
|
||||
#include "CXWindowsScreenSaver.h"
|
||||
#include "CXWindowsScreen.h"
|
||||
#include "CXWindowsUtil.h"
|
||||
#include "IPlatformScreen.h"
|
||||
#include "CLog.h"
|
||||
#include "TMethodJob.h"
|
||||
#include "CEvent.h"
|
||||
#include "IEventQueue.h"
|
||||
#include "TMethodEventJob.h"
|
||||
#include <X11/Xatom.h>
|
||||
#if defined(HAVE_X11_EXTENSIONS_XTEST_H)
|
||||
# include <X11/extensions/XTest.h>
|
||||
|
@ -29,20 +31,16 @@
|
|||
//
|
||||
|
||||
CXWindowsScreenSaver::CXWindowsScreenSaver(
|
||||
CXWindowsScreen* screen, Display* display) :
|
||||
m_screen(screen),
|
||||
Display* display, Window window, void* eventTarget) :
|
||||
m_display(display),
|
||||
m_notify(None),
|
||||
m_xscreensaverSink(window),
|
||||
m_eventTarget(eventTarget),
|
||||
m_xscreensaver(None),
|
||||
m_xscreensaverActive(false),
|
||||
m_disabled(false),
|
||||
m_suppressDisable(false),
|
||||
m_disableJobInstalled(false)
|
||||
m_disableTimer(NULL)
|
||||
{
|
||||
// screen saver disable callback
|
||||
m_disableJob = new TMethodJob<CXWindowsScreenSaver>(this,
|
||||
&CXWindowsScreenSaver::disableCallback);
|
||||
|
||||
// get atoms
|
||||
m_atomScreenSaver = XInternAtom(m_display,
|
||||
"SCREENSAVER", False);
|
||||
|
@ -52,24 +50,6 @@ CXWindowsScreenSaver::CXWindowsScreenSaver(
|
|||
"ACTIVATE", False);
|
||||
m_atomScreenSaverDeactivate = XInternAtom(m_display,
|
||||
"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
|
||||
{
|
||||
|
@ -94,28 +74,39 @@ CXWindowsScreenSaver::CXWindowsScreenSaver(
|
|||
// get the built-in settings
|
||||
XGetScreenSaver(m_display, &m_timeout, &m_interval,
|
||||
&m_preferBlanking, &m_allowExposures);
|
||||
|
||||
// install disable timer event handler
|
||||
EVENTQUEUE->adoptHandler(CEvent::kTimer, this,
|
||||
new TMethodEventJob<CXWindowsScreenSaver>(this,
|
||||
&CXWindowsScreenSaver::handleDisableTimer));
|
||||
}
|
||||
|
||||
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
|
||||
m_screen->removeTimer(m_disableJob);
|
||||
delete m_disableJob;
|
||||
if (m_disableTimer != NULL) {
|
||||
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
|
||||
CXWindowsScreenSaver::onPreDispatch(const XEvent* xevent)
|
||||
CXWindowsScreenSaver::handleXEvent(const XEvent* xevent)
|
||||
{
|
||||
switch (xevent->type) {
|
||||
case CreateNotify:
|
||||
|
@ -175,18 +166,12 @@ CXWindowsScreenSaver::onPreDispatch(const XEvent* xevent)
|
|||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
CXWindowsScreenSaver::setNotify(Window notify)
|
||||
{
|
||||
m_notify = notify;
|
||||
}
|
||||
|
||||
void
|
||||
CXWindowsScreenSaver::enable()
|
||||
{
|
||||
// for xscreensaver
|
||||
m_disabled = false;
|
||||
updateDisableJob();
|
||||
updateDisableTimer();
|
||||
|
||||
// for built-in X screen saver
|
||||
XSetScreenSaver(m_display, m_timeout, m_interval,
|
||||
|
@ -198,7 +183,7 @@ CXWindowsScreenSaver::disable()
|
|||
{
|
||||
// for xscreensaver
|
||||
m_disabled = true;
|
||||
updateDisableJob();
|
||||
updateDisableTimer();
|
||||
|
||||
// use built-in X screen saver
|
||||
XGetScreenSaver(m_display, &m_timeout, &m_interval,
|
||||
|
@ -213,7 +198,7 @@ CXWindowsScreenSaver::activate()
|
|||
{
|
||||
// remove disable job timer
|
||||
m_suppressDisable = true;
|
||||
updateDisableJob();
|
||||
updateDisableTimer();
|
||||
|
||||
// try xscreensaver
|
||||
findXScreenSaver();
|
||||
|
@ -231,7 +216,7 @@ CXWindowsScreenSaver::deactivate()
|
|||
{
|
||||
// reinstall disable job timer
|
||||
m_suppressDisable = false;
|
||||
updateDisableJob();
|
||||
updateDisableTimer();
|
||||
|
||||
// try xscreensaver
|
||||
findXScreenSaver();
|
||||
|
@ -256,27 +241,6 @@ CXWindowsScreenSaver::isActive() const
|
|||
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
|
||||
CXWindowsScreenSaver::findXScreenSaver()
|
||||
{
|
||||
|
@ -351,9 +315,18 @@ CXWindowsScreenSaver::setXScreenSaverActive(bool activated)
|
|||
// from activating since that'll just pop up the password
|
||||
// dialog if locking is enabled.
|
||||
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
|
||||
CXWindowsScreenSaver::updateDisableJob()
|
||||
CXWindowsScreenSaver::updateDisableTimer()
|
||||
{
|
||||
assert(m_disableJob != NULL);
|
||||
|
||||
if (m_disabled && !m_suppressDisable && !m_disableJobInstalled) {
|
||||
if (m_disabled && !m_suppressDisable && m_disableTimer == NULL) {
|
||||
// 5 seconds should be plenty often to suppress the screen saver
|
||||
m_disableJobInstalled = true;
|
||||
m_screen->addTimer(m_disableJob, 5.0);
|
||||
m_disableTimer = EVENTQUEUE->newTimer(5.0, this);
|
||||
}
|
||||
else if ((!m_disabled || m_suppressDisable) && m_disableJobInstalled) {
|
||||
m_disableJobInstalled = false;
|
||||
m_screen->removeTimer(m_disableJob);
|
||||
else if ((!m_disabled || m_suppressDisable) && m_disableTimer != NULL) {
|
||||
EVENTQUEUE->deleteTimer(m_disableTimer);
|
||||
m_disableTimer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CXWindowsScreenSaver::disableCallback(void*)
|
||||
CXWindowsScreenSaver::handleDisableTimer(const CEvent&, void*)
|
||||
{
|
||||
// send fake mouse motion directly to xscreensaver
|
||||
if (m_xscreensaver != None) {
|
||||
|
|
|
@ -23,16 +23,13 @@
|
|||
# include <X11/Xlib.h>
|
||||
#endif
|
||||
|
||||
class IJob;
|
||||
class CXWindowsScreen;
|
||||
class CEvent;
|
||||
class CEventQueueTimer;
|
||||
|
||||
//! X11 screen saver implementation
|
||||
class CXWindowsScreenSaver : public IScreenSaver {
|
||||
public:
|
||||
// note -- the caller must ensure that Display* passed to c'tor isn't
|
||||
// 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*);
|
||||
CXWindowsScreenSaver(Display*, Window, void* eventTarget);
|
||||
virtual ~CXWindowsScreenSaver();
|
||||
|
||||
//! @name manipulators
|
||||
|
@ -40,22 +37,17 @@ public:
|
|||
|
||||
//! Event filtering
|
||||
/*!
|
||||
Called for each event before event translation and dispatch. Return
|
||||
true to skip translation and dispatch. Subclasses should call the
|
||||
superclass's version first and return true if it returns true.
|
||||
Should be called for each system event before event translation and
|
||||
dispatch. Returns true to skip translation and dispatch.
|
||||
*/
|
||||
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
|
||||
when the screen saver activates or deactivates. Only one window
|
||||
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.
|
||||
Tells this object to delete itself without using the X11 display.
|
||||
It may leak some resources as a result.
|
||||
*/
|
||||
void setNotify(Window);
|
||||
void destroy();
|
||||
|
||||
//@}
|
||||
|
||||
|
@ -67,9 +59,6 @@ public:
|
|||
virtual bool isActive() const;
|
||||
|
||||
private:
|
||||
// send a notification
|
||||
void sendNotify(bool activated);
|
||||
|
||||
// find and set the running xscreensaver's window. returns true iff
|
||||
// found.
|
||||
bool findXScreenSaver();
|
||||
|
@ -98,25 +87,22 @@ private:
|
|||
void addWatchXScreenSaver(Window window);
|
||||
|
||||
// install/uninstall the job used to suppress the screensaver
|
||||
void updateDisableJob();
|
||||
void updateDisableTimer();
|
||||
|
||||
// called periodically to prevent the screen saver from starting
|
||||
void disableCallback(void*);
|
||||
void handleDisableTimer(const CEvent&, void*);
|
||||
|
||||
private:
|
||||
typedef std::map<Window, long> CWatchList;
|
||||
|
||||
// the event loop object
|
||||
CXWindowsScreen* m_screen;
|
||||
|
||||
// the X display
|
||||
Display* m_display;
|
||||
|
||||
// old event mask on root window
|
||||
long m_rootEventMask;
|
||||
// window to receive xscreensaver repsonses
|
||||
Window m_xscreensaverSink;
|
||||
|
||||
// window to notify on screen saver activation/deactivation
|
||||
Window m_notify;
|
||||
// the target for the events we generate
|
||||
void* m_eventTarget;
|
||||
|
||||
// xscreensaver's window
|
||||
Window m_xscreensaver;
|
||||
|
@ -124,8 +110,8 @@ private:
|
|||
// xscreensaver activation state
|
||||
bool m_xscreensaverActive;
|
||||
|
||||
// dummy window to receive xscreensaver repsonses
|
||||
Window m_xscreensaverSink;
|
||||
// old event mask on root window
|
||||
long m_rootEventMask;
|
||||
|
||||
// potential xscreensaver windows being watched
|
||||
CWatchList m_watchWindows;
|
||||
|
@ -135,7 +121,6 @@ private:
|
|||
Atom m_atomScreenSaverVersion;
|
||||
Atom m_atomScreenSaverActivate;
|
||||
Atom m_atomScreenSaverDeactivate;
|
||||
Atom m_atomSynergyScreenSaver;
|
||||
|
||||
// built-in screen saver settings
|
||||
int m_timeout;
|
||||
|
@ -151,11 +136,8 @@ private:
|
|||
// to activate the screen saver even if disabled.
|
||||
bool m_suppressDisable;
|
||||
|
||||
// true iff the disabled job timer is installed
|
||||
bool m_disableJobInstalled;
|
||||
|
||||
// the job used to invoke disableCallback
|
||||
IJob* m_disableJob;
|
||||
// the disable timer (NULL if not installed)
|
||||
CEventQueueTimer* m_disableTimer;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -49,7 +49,7 @@ libplatform_a_SOURCES = \
|
|||
CXWindowsClipboardTextConverter.cpp \
|
||||
CXWindowsClipboardUCS2Converter.cpp \
|
||||
CXWindowsClipboardUTF8Converter.cpp \
|
||||
CXWindowsEventQueue.cpp \
|
||||
CXWindowsEventQueueBuffer.cpp \
|
||||
CXWindowsKeyMapper.cpp \
|
||||
CXWindowsScreen.cpp \
|
||||
CXWindowsScreenSaver.cpp \
|
||||
|
@ -58,7 +58,7 @@ libplatform_a_SOURCES = \
|
|||
CXWindowsClipboardTextConverter.h \
|
||||
CXWindowsClipboardUCS2Converter.h \
|
||||
CXWindowsClipboardUTF8Converter.h \
|
||||
CXWindowsEventQueue.h \
|
||||
CXWindowsEventQueueBuffer.h \
|
||||
CXWindowsKeyMapper.h \
|
||||
CXWindowsScreen.h \
|
||||
CXWindowsScreenSaver.h \
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -13,15 +13,18 @@
|
|||
*/
|
||||
|
||||
#include "CClientProxy.h"
|
||||
#include "CProtocolUtil.h"
|
||||
#include "IStream.h"
|
||||
#include "CLog.h"
|
||||
|
||||
//
|
||||
// CClientProxy
|
||||
//
|
||||
|
||||
CClientProxy::CClientProxy(IServer* server,
|
||||
const CString& name, IStream* stream) :
|
||||
m_server(server),
|
||||
CEvent::Type CClientProxy::s_readyEvent = CEvent::kUnknown;
|
||||
CEvent::Type CClientProxy::s_disconnectedEvent = CEvent::kUnknown;
|
||||
|
||||
CClientProxy::CClientProxy(const CString& name, IStream* stream) :
|
||||
m_name(name),
|
||||
m_stream(stream)
|
||||
{
|
||||
|
@ -33,10 +36,14 @@ CClientProxy::~CClientProxy()
|
|||
delete m_stream;
|
||||
}
|
||||
|
||||
IServer*
|
||||
CClientProxy::getServer() const
|
||||
void
|
||||
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*
|
||||
|
@ -51,8 +58,22 @@ CClientProxy::getName() const
|
|||
return m_name;
|
||||
}
|
||||
|
||||
const CMutex*
|
||||
CClientProxy::getMutex() const
|
||||
CEvent::Type
|
||||
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));
|
||||
}
|
||||
|
|
|
@ -16,11 +16,10 @@
|
|||
#define CCLIENTPROXY_H
|
||||
|
||||
#include "IClient.h"
|
||||
#include "CMutex.h"
|
||||
#include "CEvent.h"
|
||||
#include "CString.h"
|
||||
|
||||
class IStream;
|
||||
class IServer;
|
||||
|
||||
//! Generic proxy for client
|
||||
class CClientProxy : public IClient {
|
||||
|
@ -28,17 +27,21 @@ public:
|
|||
/*!
|
||||
\c name is the name of the client.
|
||||
*/
|
||||
CClientProxy(IServer* server, const CString& name, IStream* adoptedStream);
|
||||
CClientProxy(const CString& name, IStream* adoptedStream);
|
||||
~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
|
||||
/*!
|
||||
|
@ -46,12 +49,31 @@ public:
|
|||
*/
|
||||
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
|
||||
virtual void open() = 0;
|
||||
virtual void mainLoop() = 0;
|
||||
virtual void close() = 0;
|
||||
virtual void enter(SInt32 xAbs, SInt32 yAbs,
|
||||
UInt32 seqNum, KeyModifierMask mask,
|
||||
bool forScreensaver) = 0;
|
||||
|
@ -71,25 +93,13 @@ public:
|
|||
virtual void resetOptions() = 0;
|
||||
virtual void setOptions(const COptionsList& options) = 0;
|
||||
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:
|
||||
CMutex m_mutex;
|
||||
IServer* m_server;
|
||||
CString m_name;
|
||||
IStream* m_stream;
|
||||
|
||||
static CEvent::Type s_readyEvent;
|
||||
static CEvent::Type s_disconnectedEvent;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -13,12 +13,9 @@
|
|||
*/
|
||||
|
||||
#include "CClientProxy1_0.h"
|
||||
#include "CServer.h"
|
||||
#include "CClipboard.h"
|
||||
#include "CProtocolUtil.h"
|
||||
#include "XSynergy.h"
|
||||
#include "IStream.h"
|
||||
#include "CLock.h"
|
||||
#include "CLog.h"
|
||||
#include "IEventQueue.h"
|
||||
#include "TMethodEventJob.h"
|
||||
|
@ -28,16 +25,12 @@
|
|||
// CClientProxy1_0
|
||||
//
|
||||
|
||||
CClientProxy1_0::CClientProxy1_0(IServer* server,
|
||||
const CString& name, IStream* stream) :
|
||||
CClientProxy(server, name, stream),
|
||||
CClientProxy1_0::CClientProxy1_0(const CString& name, IStream* stream) :
|
||||
CClientProxy(name, stream),
|
||||
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
|
||||
EVENTQUEUE->adoptHandler(IStream::getInputReadyEvent(),
|
||||
stream->getEventTarget(),
|
||||
|
@ -59,7 +52,8 @@ CClientProxy1_0::CClientProxy1_0(IServer* server,
|
|||
new TMethodEventJob<CClientProxy1_0>(this,
|
||||
&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()
|
||||
|
@ -70,11 +64,9 @@ CClientProxy1_0::~CClientProxy1_0()
|
|||
void
|
||||
CClientProxy1_0::disconnect()
|
||||
{
|
||||
CLock lock(getMutex());
|
||||
removeHandlers();
|
||||
// FIXME -- send disconnect event (server should be listening for this)
|
||||
getStream()->flush();
|
||||
getStream()->close();
|
||||
EVENTQUEUE->addEvent(CEvent(getDisconnectedEvent(), getEventTarget()));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -98,7 +90,6 @@ CClientProxy1_0::removeHandlers()
|
|||
void
|
||||
CClientProxy1_0::addHeartbeatTimer()
|
||||
{
|
||||
CLock lock(getMutex());
|
||||
if (m_heartbeatAlarm > 0.0) {
|
||||
m_heartbeatTimer = EVENTQUEUE->newOneShotTimer(m_heartbeatAlarm, this);
|
||||
}
|
||||
|
@ -107,7 +98,6 @@ CClientProxy1_0::addHeartbeatTimer()
|
|||
void
|
||||
CClientProxy1_0::removeHeartbeatTimer()
|
||||
{
|
||||
CLock lock(getMutex());
|
||||
if (m_heartbeatTimer != NULL) {
|
||||
EVENTQUEUE->deleteTimer(m_heartbeatTimer);
|
||||
m_heartbeatTimer = NULL;
|
||||
|
@ -130,7 +120,7 @@ CClientProxy1_0::handleData(const CEvent&, void*)
|
|||
|
||||
// parse message
|
||||
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()));
|
||||
disconnect();
|
||||
return;
|
||||
|
@ -145,11 +135,35 @@ CClientProxy1_0::handleData(const CEvent&, void*)
|
|||
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
|
||||
CClientProxy1_0::parseMessage(const UInt8* code)
|
||||
{
|
||||
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) {
|
||||
// discard no-ops
|
||||
|
@ -168,14 +182,14 @@ CClientProxy1_0::parseMessage(const UInt8* code)
|
|||
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();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -187,44 +201,28 @@ CClientProxy1_0::handleFlatline(const CEvent&, void*)
|
|||
disconnect();
|
||||
}
|
||||
|
||||
// FIXME -- replace this
|
||||
void
|
||||
CClientProxy1_0::open()
|
||||
bool
|
||||
CClientProxy1_0::getClipboard(ClipboardID id, IClipboard* clipboard) const
|
||||
{
|
||||
// send request
|
||||
LOG((CLOG_DEBUG1 "querying client \"%s\" info", getName().c_str()));
|
||||
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();
|
||||
CClipboard::copy(clipboard, &m_clipboard[id].m_clipboard);
|
||||
return true;
|
||||
}
|
||||
|
||||
// handle reply
|
||||
recvInfo(false);
|
||||
}
|
||||
|
||||
// FIXME -- replace this
|
||||
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()));
|
||||
CProtocolUtil::writef(getStream(), kMsgCClose);
|
||||
x = m_info.m_x;
|
||||
y = m_info.m_y;
|
||||
w = m_info.m_w;
|
||||
h = m_info.m_h;
|
||||
}
|
||||
|
||||
// force the close to be sent before we return
|
||||
getStream()->flush();
|
||||
void
|
||||
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
|
||||
|
@ -250,10 +248,9 @@ void
|
|||
CClientProxy1_0::setClipboard(ClipboardID id, const CString& data)
|
||||
{
|
||||
// ignore if this clipboard is already clean
|
||||
CLock lock(getMutex());
|
||||
if (m_clipboardDirty[id]) {
|
||||
if (m_clipboard[id].m_dirty) {
|
||||
// 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()));
|
||||
CProtocolUtil::writef(getStream(), kMsgDClipboard, id, 0, &data);
|
||||
|
@ -267,15 +264,13 @@ CClientProxy1_0::grabClipboard(ClipboardID id)
|
|||
CProtocolUtil::writef(getStream(), kMsgCClipboard, id, 0);
|
||||
|
||||
// this clipboard is now dirty
|
||||
CLock lock(getMutex());
|
||||
m_clipboardDirty[id] = true;
|
||||
m_clipboard[id].m_dirty = true;
|
||||
}
|
||||
|
||||
void
|
||||
CClientProxy1_0::setClipboardDirty(ClipboardID id, bool dirty)
|
||||
{
|
||||
CLock lock(getMutex());
|
||||
m_clipboardDirty[id] = dirty;
|
||||
m_clipboard[id].m_dirty = dirty;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -342,7 +337,6 @@ CClientProxy1_0::resetOptions()
|
|||
CProtocolUtil::writef(getStream(), kMsgCResetOptions);
|
||||
|
||||
// reset heart rate and death
|
||||
CLock lock(getMutex());
|
||||
m_heartbeatAlarm = kHeartRate * kHeartBeatsUntilDeath;
|
||||
removeHeartbeatTimer();
|
||||
addHeartbeatTimer();
|
||||
|
@ -355,7 +349,6 @@ CClientProxy1_0::setOptions(const COptionsList& options)
|
|||
CProtocolUtil::writef(getStream(), kMsgDSetOptions, &options);
|
||||
|
||||
// check options
|
||||
CLock lock(getMutex());
|
||||
for (UInt32 i = 0, n = options.size(); i < n; i += 2) {
|
||||
if (options[i] == kOptionHeartbeat) {
|
||||
double rate = 1.0e-3 * static_cast<double>(options[i + 1]);
|
||||
|
@ -369,43 +362,9 @@ 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
|
||||
CClientProxy1_0::recvInfo(bool notify)
|
||||
CClientProxy1_0::recvInfo()
|
||||
{
|
||||
{
|
||||
CLock lock(getMutex());
|
||||
|
||||
// parse the message
|
||||
SInt16 x, y, w, h, zoneSize, mx, my;
|
||||
if (!CProtocolUtil::readf(getStream(), kMsgDInfo + 4,
|
||||
|
@ -430,12 +389,6 @@ CClientProxy1_0::recvInfo(bool notify)
|
|||
m_info.m_zoneSize = zoneSize;
|
||||
m_info.m_mx = mx;
|
||||
m_info.m_my = my;
|
||||
}
|
||||
|
||||
// tell server of change
|
||||
if (notify) {
|
||||
getServer()->onInfoChanged(getName(), m_info);
|
||||
}
|
||||
|
||||
// acknowledge receipt
|
||||
LOG((CLOG_DEBUG1 "send info ack to \"%s\"", getName().c_str()));
|
||||
|
@ -461,9 +414,17 @@ CClientProxy1_0::recvClipboard()
|
|||
return false;
|
||||
}
|
||||
|
||||
// send update. this calls us back to reset our clipboard dirty flag
|
||||
// so don't hold a lock during the call.
|
||||
getServer()->onClipboardChanged(id, seqNum, data);
|
||||
// save clipboard
|
||||
m_clipboard[id].m_clipboard.unmarshall(data, 0);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -483,8 +444,25 @@ CClientProxy1_0::recvGrabClipboard()
|
|||
return false;
|
||||
}
|
||||
|
||||
// send update. this calls us back to reset our clipboard dirty flag
|
||||
// so don't hold a lock during the call.
|
||||
getServer()->onGrabClipboard(getName(), id, seqNum);
|
||||
// notify
|
||||
CClipboardInfo* info = new CClipboardInfo;
|
||||
info->m_id = id;
|
||||
info->m_sequenceNumber = seqNum;
|
||||
EVENTQUEUE->addEvent(CEvent(getClipboardGrabbedEvent(),
|
||||
getEventTarget(), info));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// CClientProxy1_0::CClientClipboard
|
||||
//
|
||||
|
||||
CClientProxy1_0::CClientClipboard::CClientClipboard() :
|
||||
m_clipboard(),
|
||||
m_sequenceNumber(0),
|
||||
m_dirty(true)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#define CCLIENTPROXY1_0_H
|
||||
|
||||
#include "CClientProxy.h"
|
||||
#include "CClipboard.h"
|
||||
#include "ProtocolTypes.h"
|
||||
|
||||
class CEvent;
|
||||
|
@ -24,14 +25,16 @@ class CEventQueueTimer;
|
|||
//! Proxy for client implementing protocol version 1.0
|
||||
class CClientProxy1_0 : public CClientProxy {
|
||||
public:
|
||||
CClientProxy1_0(IServer* server, const CString& name,
|
||||
IStream* adoptedStream);
|
||||
CClientProxy1_0(const CString& name, IStream* adoptedStream);
|
||||
~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
|
||||
virtual void open();
|
||||
virtual void mainLoop();
|
||||
virtual void close();
|
||||
virtual void enter(SInt32 xAbs, SInt32 yAbs,
|
||||
UInt32 seqNum, KeyModifierMask mask,
|
||||
bool forScreensaver);
|
||||
|
@ -50,13 +53,9 @@ public:
|
|||
virtual void screensaver(bool activate);
|
||||
virtual void resetOptions();
|
||||
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:
|
||||
virtual bool parseHandshakeMessage(const UInt8* code);
|
||||
virtual bool parseMessage(const UInt8* code);
|
||||
|
||||
private:
|
||||
|
@ -70,15 +69,27 @@ private:
|
|||
void handleWriteError(const CEvent&, void*);
|
||||
void handleFlatline(const CEvent&, void*);
|
||||
|
||||
bool recvInfo(bool notify);
|
||||
bool recvInfo();
|
||||
bool recvClipboard();
|
||||
bool recvGrabClipboard();
|
||||
|
||||
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;
|
||||
bool m_clipboardDirty[kClipboardEnd];
|
||||
CClientClipboard m_clipboard[kClipboardEnd];
|
||||
double m_heartbeatAlarm;
|
||||
CEventQueueTimer* m_heartbeatTimer;
|
||||
MessageParser m_parser;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -21,9 +21,8 @@
|
|||
// CClientProxy1_1
|
||||
//
|
||||
|
||||
CClientProxy1_1::CClientProxy1_1(IServer* server,
|
||||
const CString& name, IStream* stream) :
|
||||
CClientProxy1_0(server, name, stream)
|
||||
CClientProxy1_1::CClientProxy1_1(const CString& name, IStream* stream) :
|
||||
CClientProxy1_0(name, stream)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
|
|
@ -20,8 +20,7 @@
|
|||
//! Proxy for client implementing protocol version 1.1
|
||||
class CClientProxy1_1 : public CClientProxy1_0 {
|
||||
public:
|
||||
CClientProxy1_1(IServer* server, const CString& name,
|
||||
IStream* adoptedStream);
|
||||
CClientProxy1_1(const CString& name, IStream* adoptedStream);
|
||||
~CClientProxy1_1();
|
||||
|
||||
// IClient overrides
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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
|
|
@ -446,11 +446,9 @@ CConfig::getOptions(const CString& name) const
|
|||
bool
|
||||
CConfig::operator==(const CConfig& x) const
|
||||
{
|
||||
/* FIXME -- no compare available for CNetworkAddress
|
||||
if (m_synergyAddress != x.m_synergyAddress) {
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
if (m_map.size() != x.m_map.size()) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -14,10 +14,6 @@
|
|||
|
||||
#include "CPrimaryClient.h"
|
||||
#include "CScreen.h"
|
||||
#include "IScreenFactory.h"
|
||||
#include "IServer.h"
|
||||
#include "XScreen.h"
|
||||
#include "XSynergy.h"
|
||||
#include "CClipboard.h"
|
||||
#include "CLog.h"
|
||||
|
||||
|
@ -25,66 +21,31 @@
|
|||
// CPrimaryClient
|
||||
//
|
||||
|
||||
CPrimaryClient::CPrimaryClient(IScreenFactory* screenFactory,
|
||||
IServer* server,
|
||||
IPrimaryScreenReceiver* receiver,
|
||||
const CString& name) :
|
||||
m_server(server),
|
||||
CPrimaryClient::CPrimaryClient(const CString& name, CScreen* screen) :
|
||||
m_name(name),
|
||||
m_seqNum(0)
|
||||
m_screen(screen)
|
||||
{
|
||||
assert(m_server != NULL);
|
||||
|
||||
// create screen
|
||||
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();
|
||||
// all clipboards are clean
|
||||
for (UInt32 i = 0; i < kClipboardEnd; ++i) {
|
||||
m_clipboardDirty[i] = false;
|
||||
}
|
||||
}
|
||||
|
||||
CPrimaryClient::~CPrimaryClient()
|
||||
{
|
||||
LOG((CLOG_DEBUG1 "destroying primary screen"));
|
||||
delete m_screen;
|
||||
}
|
||||
|
||||
void
|
||||
CPrimaryClient::exitMainLoop()
|
||||
{
|
||||
m_screen->exitMainLoop();
|
||||
}
|
||||
|
||||
void
|
||||
CPrimaryClient::reconfigure(UInt32 activeSides)
|
||||
{
|
||||
m_screen->reconfigure(activeSides);
|
||||
}
|
||||
|
||||
UInt32
|
||||
CPrimaryClient::addOneShotTimer(double timeout)
|
||||
{
|
||||
return m_screen->addOneShotTimer(timeout);
|
||||
}
|
||||
|
||||
void
|
||||
CPrimaryClient::getClipboard(ClipboardID id, CString& data) const
|
||||
CPrimaryClient::getCursorCenter(SInt32& x, SInt32& y) const
|
||||
{
|
||||
CClipboard clipboard;
|
||||
m_screen->getClipboard(id, &clipboard);
|
||||
data = clipboard.marshall();
|
||||
}
|
||||
|
||||
bool
|
||||
CPrimaryClient::isLockedToScreen() const
|
||||
{
|
||||
return m_screen->isLockedToScreen();
|
||||
m_screen->getCursorCenter(x, y);
|
||||
}
|
||||
|
||||
KeyModifierMask
|
||||
|
@ -93,64 +54,41 @@ CPrimaryClient::getToggleMask() const
|
|||
return m_screen->getActiveModifiers();
|
||||
}
|
||||
|
||||
void
|
||||
CPrimaryClient::onError()
|
||||
bool
|
||||
CPrimaryClient::isLockedToScreen() const
|
||||
{
|
||||
// forward to server
|
||||
m_server->onError();
|
||||
return m_screen->isLockedToScreen();
|
||||
}
|
||||
|
||||
void
|
||||
CPrimaryClient::onInfoChanged(const CClientInfo& info)
|
||||
void*
|
||||
CPrimaryClient::getEventTarget() const
|
||||
{
|
||||
m_info = info;
|
||||
try {
|
||||
m_server->onInfoChanged(getName(), m_info);
|
||||
}
|
||||
catch (XBadClient&) {
|
||||
// ignore
|
||||
}
|
||||
return m_screen->getEventTarget();
|
||||
}
|
||||
|
||||
bool
|
||||
CPrimaryClient::onGrabClipboard(ClipboardID id)
|
||||
CPrimaryClient::getClipboard(ClipboardID id, IClipboard* clipboard) const
|
||||
{
|
||||
try {
|
||||
return m_server->onGrabClipboard(getName(), id, m_seqNum);
|
||||
}
|
||||
catch (XBadClient&) {
|
||||
return false;
|
||||
return m_screen->getClipboard(id, clipboard);
|
||||
}
|
||||
|
||||
SInt32
|
||||
CPrimaryClient::getJumpZoneSize() const
|
||||
{
|
||||
return m_screen->getJumpZoneSize();
|
||||
}
|
||||
|
||||
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
|
||||
CPrimaryClient::open()
|
||||
CPrimaryClient::getCursorPos(SInt32& x, SInt32& y) const
|
||||
{
|
||||
// all clipboards are clean
|
||||
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();
|
||||
m_screen->getCursorPos(x, y);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -169,8 +107,7 @@ void
|
|||
CPrimaryClient::enter(SInt32 xAbs, SInt32 yAbs,
|
||||
UInt32 seqNum, KeyModifierMask, bool screensaver)
|
||||
{
|
||||
// note -- we must not call any server methods except onError().
|
||||
m_seqNum = seqNum;
|
||||
m_screen->setSequenceNumber(seqNum);
|
||||
if (!screensaver) {
|
||||
m_screen->warpCursor(xAbs, yAbs);
|
||||
}
|
||||
|
@ -180,15 +117,12 @@ CPrimaryClient::enter(SInt32 xAbs, SInt32 yAbs,
|
|||
bool
|
||||
CPrimaryClient::leave()
|
||||
{
|
||||
// note -- we must not call any server methods except onError().
|
||||
return m_screen->leave();
|
||||
}
|
||||
|
||||
void
|
||||
CPrimaryClient::setClipboard(ClipboardID id, const CString& data)
|
||||
{
|
||||
// note -- we must not call any server methods except onError().
|
||||
|
||||
// ignore if this clipboard is already clean
|
||||
if (m_clipboardDirty[id]) {
|
||||
// this clipboard is now clean
|
||||
|
@ -284,31 +218,3 @@ CPrimaryClient::getName() const
|
|||
{
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -16,14 +16,9 @@
|
|||
#define CPRIMARYCLIENT_H
|
||||
|
||||
#include "IClient.h"
|
||||
#include "IScreenReceiver.h"
|
||||
#include "ProtocolTypes.h"
|
||||
|
||||
class CScreen;
|
||||
class IClipboard;
|
||||
class IScreenFactory;
|
||||
class IPrimaryScreenReceiver;
|
||||
class IServer;
|
||||
|
||||
//! 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
|
||||
treated as if it was on a client.
|
||||
*/
|
||||
class CPrimaryClient : public IScreenReceiver, public IClient {
|
||||
class CPrimaryClient : public IClient {
|
||||
public:
|
||||
/*!
|
||||
\c name is the name of the server. The caller retains ownership of
|
||||
\c factory. Throws XScreenOpenFailure or whatever the factory can
|
||||
throw if the screen cannot be created.
|
||||
\c name is the name of the server. \p screen is adopted.
|
||||
*/
|
||||
CPrimaryClient(IScreenFactory* factory, IServer*,
|
||||
IPrimaryScreenReceiver*, const CString& name);
|
||||
CPrimaryClient(const CString& name, CScreen* screen);
|
||||
~CPrimaryClient();
|
||||
|
||||
//! @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
|
||||
/*!
|
||||
Handles reconfiguration of jump zones.
|
||||
*/
|
||||
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
|
||||
//@{
|
||||
|
||||
//! 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
|
||||
/*!
|
||||
|
@ -90,19 +69,19 @@ public:
|
|||
|
||||
//@}
|
||||
|
||||
// IScreenReceiver overrides
|
||||
virtual void onError();
|
||||
virtual void onInfoChanged(const CClientInfo&);
|
||||
virtual bool onGrabClipboard(ClipboardID);
|
||||
virtual void onClipboardChanged(ClipboardID, const CString&);
|
||||
|
||||
// XXX -- these go in IClient
|
||||
// FIXME -- these probably belong on IScreen
|
||||
virtual void enable();
|
||||
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
|
||||
virtual void open();
|
||||
virtual void mainLoop();
|
||||
virtual void close();
|
||||
virtual void enter(SInt32 xAbs, SInt32 yAbs,
|
||||
UInt32 seqNum, KeyModifierMask mask,
|
||||
bool forScreensaver);
|
||||
|
@ -122,18 +101,10 @@ public:
|
|||
virtual void resetOptions();
|
||||
virtual void setOptions(const COptionsList& options);
|
||||
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:
|
||||
IServer* m_server;
|
||||
CScreen* m_screen;
|
||||
CString m_name;
|
||||
UInt32 m_seqNum;
|
||||
CClientInfo m_info;
|
||||
CScreen* m_screen;
|
||||
bool m_clipboardDirty[kClipboardEnd];
|
||||
};
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -15,84 +15,40 @@
|
|||
#ifndef CSERVER_H
|
||||
#define CSERVER_H
|
||||
|
||||
#include "IServer.h"
|
||||
#include "IPrimaryScreenReceiver.h"
|
||||
#include "CConfig.h"
|
||||
#include "CClipboard.h"
|
||||
#include "CCondVar.h"
|
||||
#include "CMutex.h"
|
||||
#include "CThread.h"
|
||||
#include "CJobList.h"
|
||||
#include "ClipboardTypes.h"
|
||||
#include "KeyTypes.h"
|
||||
#include "MouseTypes.h"
|
||||
#include "CEvent.h"
|
||||
#include "CStopwatch.h"
|
||||
#include "stdlist.h"
|
||||
#include "stdmap.h"
|
||||
#include "stdset.h"
|
||||
#include "stdvector.h"
|
||||
|
||||
class CClientProxy;
|
||||
class CClientProxyUnknown;
|
||||
class CEventQueueTimer;
|
||||
class CPrimaryClient;
|
||||
class IClient;
|
||||
class IDataSocket;
|
||||
class IScreenFactory;
|
||||
class IServerProtocol;
|
||||
class ISocketFactory;
|
||||
class IStreamFilterFactory;
|
||||
|
||||
//! Synergy server
|
||||
/*!
|
||||
This class implements the top-level server algorithms for synergy.
|
||||
*/
|
||||
class CServer : public IServer, public IPrimaryScreenReceiver {
|
||||
class CServer {
|
||||
public:
|
||||
enum EStatus {
|
||||
kNotRunning,
|
||||
kRunning,
|
||||
kServerNameUnknown,
|
||||
kError,
|
||||
kMaxStatus
|
||||
};
|
||||
|
||||
/*!
|
||||
The server will look itself up in the configuration using \c serverName
|
||||
as its name.
|
||||
Start the server with the configuration \p config and the primary
|
||||
client (local screen) \p primaryClient. The client retains
|
||||
ownership of \p primaryClient.
|
||||
*/
|
||||
CServer(const CString& serverName);
|
||||
CServer(const CConfig& config, CPrimaryClient* primaryClient);
|
||||
~CServer();
|
||||
|
||||
//! @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
|
||||
/*!
|
||||
Change the server's configuration. Returns true iff the new
|
||||
|
@ -101,67 +57,26 @@ public:
|
|||
*/
|
||||
bool setConfig(const CConfig&);
|
||||
|
||||
//! Set screen factory
|
||||
//! Add a client
|
||||
/*!
|
||||
Sets the factory for creating screens. This must be set before
|
||||
calling open(). This object takes ownership of the factory.
|
||||
Adds \p client to the server. The client is adopted and will be
|
||||
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.
|
||||
This must be set before calling mainLoop(). This object takes
|
||||
ownership of the factory.
|
||||
Disconnect clients. This tells them to disconnect but does not wait
|
||||
for them to actually do so. The server sends the disconnected event
|
||||
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*);
|
||||
|
||||
//! 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*);
|
||||
void disconnect();
|
||||
|
||||
//@}
|
||||
//! @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
|
||||
/*!
|
||||
Returns the number of connected clients, including the server itself.
|
||||
|
@ -174,33 +89,22 @@ public:
|
|||
*/
|
||||
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:
|
||||
//! Handle special keys
|
||||
/*!
|
||||
|
@ -208,36 +112,18 @@ protected:
|
|||
*/
|
||||
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:
|
||||
typedef std::list<CThread> CThreadList;
|
||||
|
||||
// notify status jobs of a change
|
||||
void runStatusJobs() const;
|
||||
|
||||
// set new status
|
||||
void setStatus(EStatus, const char* msg = NULL);
|
||||
// get canonical name of client
|
||||
CString getName(const IClient*) const;
|
||||
|
||||
// get the sides of the primary screen that have neighbors
|
||||
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
|
||||
bool isLockedToScreenNoLock() const;
|
||||
bool isLockedToScreen() const;
|
||||
|
||||
// returns the jump zone of the client
|
||||
SInt32 getJumpZoneSize(IClient*) const;
|
||||
|
||||
// change the active screen
|
||||
void switchScreen(IClient*,
|
||||
|
@ -260,57 +146,98 @@ private:
|
|||
bool isSwitchOkay(IClient* dst, EDirection,
|
||||
SInt32 x, SInt32 y);
|
||||
|
||||
// update switch state due to a mouse move that doesn't try to
|
||||
// switch screens.
|
||||
void onNoSwitch(bool inTapZone);
|
||||
// update switch state due to a mouse move at \p x, \p y that
|
||||
// doesn't switch screens.
|
||||
void noSwitch(SInt32 x, SInt32 y);
|
||||
|
||||
// reset switch wait state
|
||||
void clearSwitchState();
|
||||
// stop switch timers
|
||||
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
|
||||
void sendOptions(IClient* client) const;
|
||||
|
||||
// open/close the primary screen
|
||||
void openPrimaryScreen();
|
||||
void closePrimaryScreen();
|
||||
// process options from configuration
|
||||
void processOptions();
|
||||
|
||||
// update the clipboard if owned by the primary screen
|
||||
void updatePrimaryClipboard(ClipboardID);
|
||||
// event handlers
|
||||
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
|
||||
// primary client.
|
||||
// event processing
|
||||
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);
|
||||
|
||||
// start a thread, adding it to the list of threads
|
||||
CThread startThread(IJob* adopted);
|
||||
// close all clients whether they've completed the handshake or not,
|
||||
// except the primary client
|
||||
void closeAllClients();
|
||||
|
||||
// cancel running threads, waiting at most timeout seconds for
|
||||
// them to finish.
|
||||
void stopThreads(double timeout = -1.0);
|
||||
// remove clients from internal state
|
||||
void removeActiveClient(IClient*);
|
||||
void removeOldClient(IClient*);
|
||||
|
||||
// reap threads, clearing finished threads from the thread list.
|
||||
// doReapThreads does the work on the given thread list.
|
||||
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);
|
||||
// force the cursor off of \p client
|
||||
void forceLeaveClient(IClient* client);
|
||||
|
||||
private:
|
||||
class XServerRethrow : public XBase {
|
||||
protected:
|
||||
// XBase overrides
|
||||
virtual CString getWhat() const throw();
|
||||
};
|
||||
|
||||
class CClipboardInfo {
|
||||
public:
|
||||
CClipboardInfo();
|
||||
|
@ -322,52 +249,27 @@ private:
|
|||
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
|
||||
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
|
||||
IClient* m_active;
|
||||
|
||||
// the sequence number of enter messages
|
||||
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;
|
||||
|
||||
// current configuration
|
||||
|
@ -387,8 +289,7 @@ private:
|
|||
|
||||
// state for delayed screen switching
|
||||
double m_switchWaitDelay;
|
||||
UInt32 m_switchWaitTimer;
|
||||
bool m_switchWaitEngaged;
|
||||
CEventQueueTimer* m_switchWaitTimer;
|
||||
SInt32 m_switchWaitX, m_switchWaitY;
|
||||
|
||||
// state for double-tap screen switching
|
||||
|
@ -398,19 +299,8 @@ private:
|
|||
bool m_switchTwoTapArmed;
|
||||
SInt32 m_switchTwoTapZone;
|
||||
|
||||
// the status change jobs and status
|
||||
CJobList m_statusJobs;
|
||||
EStatus m_status;
|
||||
CString m_statusMessage;
|
||||
|
||||
//---
|
||||
/*
|
||||
IListenSocket* m_listen;
|
||||
|
||||
typedef std::map<CProvisionalClient*,
|
||||
CEventQueueTimer*> CProvisionalClients;
|
||||
CProvisionalClients m_provisional;
|
||||
*/
|
||||
static CEvent::Type s_errorEvent;
|
||||
static CEvent::Type s_disconnectedEvent;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -25,19 +25,21 @@ MAINTAINERCLEANFILES = \
|
|||
|
||||
noinst_LIBRARIES = libserver.a
|
||||
libserver_a_SOURCES = \
|
||||
CClientListener.cpp \
|
||||
CClientProxy.cpp \
|
||||
CClientProxy1_0.cpp \
|
||||
CClientProxy1_1.cpp \
|
||||
CClientProxyUnknown.cpp \
|
||||
CConfig.cpp \
|
||||
CPrimaryClient.cpp \
|
||||
CProvisionalClient.cpp \
|
||||
CServer.cpp \
|
||||
CClientListener.h \
|
||||
CClientProxy.h \
|
||||
CClientProxy1_0.h \
|
||||
CClientProxy1_1.h \
|
||||
CClientProxyUnknown.h \
|
||||
CConfig.h \
|
||||
CPrimaryClient.h \
|
||||
CProvisionalClient.h \
|
||||
CServer.h \
|
||||
$(NULL)
|
||||
INCLUDES = \
|
||||
|
|
|
@ -73,7 +73,6 @@ CProtocolUtil::vwritef(IStream* stream,
|
|||
}
|
||||
|
||||
// fill buffer
|
||||
// FIXME -- can we use alloca?
|
||||
UInt8* buffer = new UInt8[size];
|
||||
writef(buffer, fmt, args);
|
||||
|
||||
|
|
|
@ -14,41 +14,26 @@
|
|||
|
||||
#include "CScreen.h"
|
||||
#include "IPlatformScreen.h"
|
||||
#include "IScreenReceiver.h"
|
||||
#include "ISecondaryScreen.h"
|
||||
#include "ProtocolTypes.h"
|
||||
#include "CLock.h"
|
||||
#include "CThread.h"
|
||||
#include "CLog.h"
|
||||
#include "IEventQueue.h"
|
||||
|
||||
//
|
||||
// CScreen
|
||||
//
|
||||
|
||||
CScreen::CScreen(IPlatformScreen* platformScreen, IScreenReceiver* receiver) :
|
||||
CScreen::CScreen(IPlatformScreen* platformScreen) :
|
||||
m_screen(platformScreen),
|
||||
m_receiver(receiver),
|
||||
m_isPrimary(platformScreen->isPrimary()),
|
||||
m_enabled(false),
|
||||
m_entered(m_isPrimary),
|
||||
m_toggleKeys(0),
|
||||
m_screenSaverSync(true)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
CScreen::~CScreen()
|
||||
{
|
||||
delete m_screen;
|
||||
}
|
||||
|
||||
void
|
||||
CScreen::open()
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
assert(m_screen != NULL);
|
||||
|
||||
// open screen
|
||||
m_screen->open(this);
|
||||
m_screen->setKeyState(this);
|
||||
|
||||
// reset options
|
||||
resetOptions();
|
||||
|
@ -56,23 +41,20 @@ CScreen::open()
|
|||
LOG((CLOG_DEBUG "opened display"));
|
||||
}
|
||||
|
||||
void
|
||||
CScreen::close()
|
||||
CScreen::~CScreen()
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
if (m_enabled) {
|
||||
disable();
|
||||
}
|
||||
assert(!m_enabled);
|
||||
assert(m_entered == m_isPrimary);
|
||||
|
||||
// close screen
|
||||
m_screen->close();
|
||||
|
||||
delete m_screen;
|
||||
LOG((CLOG_DEBUG "closed display"));
|
||||
}
|
||||
|
||||
void
|
||||
CScreen::enable()
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
assert(!m_enabled);
|
||||
|
||||
m_screen->enable();
|
||||
|
@ -90,7 +72,6 @@ CScreen::enable()
|
|||
void
|
||||
CScreen::disable()
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
assert(m_enabled);
|
||||
|
||||
if (!m_isPrimary && m_entered) {
|
||||
|
@ -111,34 +92,9 @@ CScreen::disable()
|
|||
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
|
||||
CScreen::enter()
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
assert(m_entered == false);
|
||||
LOG((CLOG_INFO "entering screen"));
|
||||
|
||||
|
@ -157,7 +113,6 @@ CScreen::enter()
|
|||
bool
|
||||
CScreen::leave()
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
assert(m_entered == true);
|
||||
LOG((CLOG_INFO "leaving screen"));
|
||||
|
||||
|
@ -209,8 +164,6 @@ CScreen::grabClipboard(ClipboardID id)
|
|||
void
|
||||
CScreen::screensaver(bool activate)
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
|
||||
if (!m_isPrimary) {
|
||||
// activate/deactivation screen saver iff synchronization enabled
|
||||
if (m_screenSaverSync) {
|
||||
|
@ -222,7 +175,6 @@ CScreen::screensaver(bool activate)
|
|||
void
|
||||
CScreen::keyDown(KeyID id, KeyModifierMask mask, KeyButton button)
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
assert(!m_isPrimary);
|
||||
|
||||
// check for ctrl+alt+del emulation
|
||||
|
@ -256,7 +208,6 @@ void
|
|||
CScreen::keyRepeat(KeyID id,
|
||||
KeyModifierMask mask, SInt32 count, KeyButton button)
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
assert(!m_isPrimary);
|
||||
|
||||
// if we haven't seen this button go down then ignore it
|
||||
|
@ -316,7 +267,6 @@ CScreen::keyRepeat(KeyID id,
|
|||
void
|
||||
CScreen::keyUp(KeyID, KeyModifierMask, KeyButton button)
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
assert(!m_isPrimary);
|
||||
|
||||
// if we haven't seen this button go down then ignore it
|
||||
|
@ -372,8 +322,6 @@ CScreen::mouseWheel(SInt32 delta)
|
|||
void
|
||||
CScreen::resetOptions()
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
|
||||
// reset options
|
||||
m_numLockHalfDuplex = false;
|
||||
m_capsLockHalfDuplex = false;
|
||||
|
@ -394,8 +342,6 @@ CScreen::resetOptions()
|
|||
void
|
||||
CScreen::setOptions(const COptionsList& options)
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
|
||||
// update options
|
||||
bool oldScreenSaverSync = m_screenSaverSync;
|
||||
for (UInt32 i = 0, n = options.size(); i < n; i += 2) {
|
||||
|
@ -427,37 +373,18 @@ CScreen::setOptions(const COptionsList& options)
|
|||
m_screen->setOptions(options);
|
||||
}
|
||||
|
||||
UInt32
|
||||
CScreen::addOneShotTimer(double timeout)
|
||||
void
|
||||
CScreen::setSequenceNumber(UInt32 seqNum)
|
||||
{
|
||||
return m_screen->addOneShotTimer(timeout);
|
||||
return m_screen->setSequenceNumber(seqNum);
|
||||
}
|
||||
|
||||
bool
|
||||
CScreen::isOnScreen() const
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
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
|
||||
CScreen::isLockedToScreen() const
|
||||
{
|
||||
|
@ -488,6 +415,35 @@ CScreen::isLockedToScreen() const
|
|||
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
|
||||
CScreen::getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) const
|
||||
{
|
||||
|
@ -503,8 +459,6 @@ CScreen::getCursorPos(SInt32& x, SInt32& y) const
|
|||
void
|
||||
CScreen::updateKeys()
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
|
||||
// clear key state
|
||||
memset(m_keys, 0, sizeof(m_keys));
|
||||
memset(m_fakeKeys, 0, sizeof(m_fakeKeys));
|
||||
|
@ -522,8 +476,6 @@ CScreen::updateKeys()
|
|||
void
|
||||
CScreen::releaseKeys()
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
|
||||
// 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
|
||||
// is still physically pressing.
|
||||
|
@ -539,16 +491,12 @@ CScreen::releaseKeys()
|
|||
void
|
||||
CScreen::setKeyDown(KeyButton key)
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
|
||||
m_keys[key & 0xffu] |= kDown;
|
||||
}
|
||||
|
||||
void
|
||||
CScreen::setToggled(KeyModifierMask mask)
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
|
||||
if (!isToggle(mask)) {
|
||||
return;
|
||||
}
|
||||
|
@ -565,8 +513,6 @@ CScreen::setToggled(KeyModifierMask mask)
|
|||
void
|
||||
CScreen::addModifier(KeyModifierMask mask, KeyButtons& keys)
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
|
||||
// the modifier must have associated keys
|
||||
if (keys.empty()) {
|
||||
return;
|
||||
|
@ -608,8 +554,6 @@ CScreen::setToggleState(KeyModifierMask mask)
|
|||
KeyButton
|
||||
CScreen::isAnyKeyDown() const
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
|
||||
for (UInt32 i = 1; i < 256; ++i) {
|
||||
if ((m_keys[i] & kDown) != 0) {
|
||||
return static_cast<KeyButton>(i);
|
||||
|
@ -621,8 +565,6 @@ CScreen::isAnyKeyDown() const
|
|||
bool
|
||||
CScreen::isKeyDown(KeyButton key) const
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
|
||||
key &= 0xffu;
|
||||
return (key != 0 && ((m_keys[key] & kDown) != 0));
|
||||
}
|
||||
|
@ -638,8 +580,6 @@ CScreen::isToggle(KeyModifierMask mask) const
|
|||
bool
|
||||
CScreen::isHalfDuplex(KeyModifierMask mask) const
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
|
||||
return ((mask == KeyModifierCapsLock && m_capsLockHalfDuplex) ||
|
||||
(mask == KeyModifierNumLock && m_numLockHalfDuplex));
|
||||
}
|
||||
|
@ -647,8 +587,6 @@ CScreen::isHalfDuplex(KeyModifierMask mask) const
|
|||
bool
|
||||
CScreen::isModifierActive(KeyModifierMask mask) const
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
|
||||
MaskToKeys::const_iterator i = m_maskToKeys.find(mask);
|
||||
if (i == m_maskToKeys.end()) {
|
||||
return false;
|
||||
|
@ -675,7 +613,6 @@ CScreen::isModifierActive(KeyModifierMask mask) const
|
|||
KeyModifierMask
|
||||
CScreen::getActiveModifiers() const
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
if (m_isPrimary) {
|
||||
// we don't keep primary key state up to date so get the
|
||||
// current state.
|
||||
|
@ -688,8 +625,6 @@ bool
|
|||
CScreen::mapModifier(Keystrokes& keys, Keystrokes& undo,
|
||||
KeyModifierMask mask, bool desireActive) const
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
|
||||
// look up modifier
|
||||
MaskToKeys::const_iterator i = m_maskToKeys.find(mask);
|
||||
if (i == m_maskToKeys.end()) {
|
||||
|
@ -751,7 +686,6 @@ CScreen::mapModifier(Keystrokes& keys, Keystrokes& undo,
|
|||
KeyModifierMask
|
||||
CScreen::getMaskForKey(KeyButton key) const
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
KeyToMask::const_iterator i = m_keyToMask.find(key);
|
||||
if (i == m_keyToMask.end()) {
|
||||
return 0;
|
||||
|
@ -767,12 +701,8 @@ CScreen::enablePrimary()
|
|||
// get notified of screen saver activation/deactivation
|
||||
m_screen->openScreensaver(true);
|
||||
|
||||
// collect and send screen info
|
||||
CClientInfo info;
|
||||
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);
|
||||
// claim screen changed size
|
||||
EVENTQUEUE->addEvent(CEvent(getShapeChangedEvent(), getEventTarget()));
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -12,45 +12,32 @@
|
|||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef CSECONDARYSCREEN_H
|
||||
#define CSECONDARYSCREEN_H
|
||||
#ifndef CSCREEN_H
|
||||
#define CSCREEN_H
|
||||
|
||||
#include "IKeyState.h"
|
||||
#include "IScreen.h"
|
||||
#include "ClipboardTypes.h"
|
||||
#include "MouseTypes.h"
|
||||
#include "OptionTypes.h"
|
||||
#include "CMutex.h"
|
||||
#include "stdmap.h"
|
||||
|
||||
class IClipboard;
|
||||
class IPlatformScreen;
|
||||
class IScreenReceiver;
|
||||
|
||||
//! Platform independent screen
|
||||
/*!
|
||||
This is a platform independent screen. It can work as either a
|
||||
primary or secondary screen.
|
||||
*/
|
||||
class CScreen : public IKeyState {
|
||||
class CScreen : public IScreen, public IKeyState {
|
||||
public:
|
||||
CScreen(IPlatformScreen* platformScreen, IScreenReceiver*);
|
||||
CScreen(IPlatformScreen* platformScreen);
|
||||
virtual ~CScreen();
|
||||
|
||||
//! @name manipulators
|
||||
//@{
|
||||
|
||||
//! Open screen
|
||||
/*!
|
||||
Opens the screen.
|
||||
*/
|
||||
void open();
|
||||
|
||||
//! Close screen
|
||||
/*!
|
||||
Closes the screen.
|
||||
*/
|
||||
void close();
|
||||
|
||||
//! Activate screen
|
||||
/*!
|
||||
Activate the screen, preparing it to report system and user events.
|
||||
|
@ -66,21 +53,6 @@ public:
|
|||
*/
|
||||
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
|
||||
/*!
|
||||
Called when the user navigates to this screen.
|
||||
|
@ -196,12 +168,11 @@ public:
|
|||
*/
|
||||
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
|
||||
id of the timer.
|
||||
Sets the sequence number to use in subsequent clipboard events.
|
||||
*/
|
||||
UInt32 addOneShotTimer(double timeout);
|
||||
void setSequenceNumber(UInt32);
|
||||
|
||||
//@}
|
||||
//! @name accessors
|
||||
|
@ -213,19 +184,6 @@ public:
|
|||
*/
|
||||
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
|
||||
/*!
|
||||
Returns true if there's any reason that the user should not be
|
||||
|
@ -236,22 +194,30 @@ public:
|
|||
*/
|
||||
bool isLockedToScreen() const;
|
||||
|
||||
//! Get screen shape
|
||||
//! Get jump zone size
|
||||
/*!
|
||||
Returns 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.
|
||||
Return the jump zone size, the size of the regions on the edges of
|
||||
the screen that cause the cursor to jump to another screen.
|
||||
*/
|
||||
void getShape(SInt32& x, SInt32& y,
|
||||
SInt32& width, SInt32& height) const;
|
||||
SInt32 getJumpZoneSize() 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
|
||||
virtual void updateKeys();
|
||||
virtual void releaseKeys();
|
||||
|
@ -307,14 +273,9 @@ private:
|
|||
typedef std::map<KeyModifierMask, KeyButtons> MaskToKeys;
|
||||
typedef std::map<KeyButton, KeyModifierMask> KeyToMask;
|
||||
|
||||
CMutex m_mutex;
|
||||
|
||||
// our platform dependent screen
|
||||
IPlatformScreen* m_screen;
|
||||
|
||||
// our screen receiver
|
||||
IScreenReceiver* m_receiver;
|
||||
|
||||
// true if screen is being used as a primary screen, false otherwise
|
||||
bool m_isPrimary;
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#ifndef ICLIENT_H
|
||||
#define ICLIENT_H
|
||||
|
||||
#include "IInterface.h"
|
||||
#include "IScreen.h"
|
||||
#include "ClipboardTypes.h"
|
||||
#include "KeyTypes.h"
|
||||
#include "MouseTypes.h"
|
||||
|
@ -27,43 +27,18 @@
|
|||
This interface defines the methods necessary for the server to
|
||||
communicate with a client.
|
||||
*/
|
||||
class IClient : public IInterface {
|
||||
class IClient : public IScreen {
|
||||
public:
|
||||
//! @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 the screen. The cursor should be warped to \c xAbs,yAbs.
|
||||
The client should record seqNum for future reporting of
|
||||
clipboard changes. \c mask is the expected toggle button state
|
||||
and the client should update its state to match. \c forScreensaver
|
||||
is true iff the screen is being entered because the screen saver is
|
||||
starting.
|
||||
Enter the screen. The cursor should be warped to \p xAbs,yAbs.
|
||||
\p mask is the expected toggle button state and the client should
|
||||
update its state to match. \p forScreensaver is true iff the
|
||||
screen is being entered because the screen saver is starting.
|
||||
Subsequent clipboard events should report \p seqNum.
|
||||
*/
|
||||
virtual void enter(SInt32 xAbs, SInt32 yAbs,
|
||||
UInt32 seqNum, KeyModifierMask mask,
|
||||
|
@ -180,35 +155,14 @@ public:
|
|||
*/
|
||||
virtual CString getName() const = 0;
|
||||
|
||||
//! Get jump zone size
|
||||
/*!
|
||||
Called to get the jump zone size.
|
||||
*/
|
||||
virtual SInt32 getJumpZoneSize() 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.
|
||||
*/
|
||||
// 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;
|
||||
|
||||
//! 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 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
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -15,10 +15,12 @@
|
|||
#ifndef IPLATFORMSCREEN_H
|
||||
#define IPLATFORMSCREEN_H
|
||||
|
||||
#include "IScreen.h"
|
||||
#include "IPrimaryScreen.h"
|
||||
#include "ISecondaryScreen.h"
|
||||
#include "ClipboardTypes.h"
|
||||
#include "OptionTypes.h"
|
||||
#include "CEvent.h"
|
||||
|
||||
class IClipboard;
|
||||
class IKeyState;
|
||||
|
@ -27,27 +29,60 @@ class IKeyState;
|
|||
/*!
|
||||
This interface defines the methods common to all platform dependent
|
||||
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:
|
||||
//! 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
|
||||
//@{
|
||||
|
||||
//! Open screen
|
||||
//! Set the key state
|
||||
/*!
|
||||
Called to open and initialize the screen. Throw XScreenUnavailable
|
||||
if the screen cannot be opened but retrying later may succeed.
|
||||
Otherwise throw some other XScreenOpenFailure exception.
|
||||
Sets the key state object. This object tracks keyboard state and
|
||||
the screen is expected to keep it up to date.
|
||||
*/
|
||||
virtual void open(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;
|
||||
virtual void setKeyState(IKeyState*) = 0;
|
||||
|
||||
//! Enable screen
|
||||
/*!
|
||||
|
@ -64,21 +99,6 @@ public:
|
|||
*/
|
||||
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
|
||||
/*!
|
||||
Called when the user navigates to this screen.
|
||||
|
@ -102,22 +122,19 @@ public:
|
|||
|
||||
//! Check clipboard owner
|
||||
/*!
|
||||
Check ownership of all clipboards and notify an IScreenReceiver (set
|
||||
through some other interface) if any changed. This is used as a
|
||||
backup in case the system doesn't reliably report clipboard ownership
|
||||
changes.
|
||||
Check ownership of all clipboards and post grab events for any that
|
||||
have changed. This is used as a backup in case the system doesn't
|
||||
reliably report clipboard ownership changes.
|
||||
*/
|
||||
virtual void checkClipboards() = 0;
|
||||
|
||||
//! Open screen saver
|
||||
/*!
|
||||
Open the screen saver. If \c notify is true then this object must
|
||||
call an IScreenEventHandler's (set through some other interface)
|
||||
onScreenSaver() when the screensaver activates or deactivates until
|
||||
it's closed. If \c notify is false then the screen saver is
|
||||
disabled on open and restored on close.
|
||||
send events when the screen saver activates or deactivates until
|
||||
\c closeScreensaver() is called. If \c notify is false then the
|
||||
screen saver is disabled and restored on \c closeScreensaver().
|
||||
*/
|
||||
// XXX -- pass an interface pointer, not a notify flag
|
||||
virtual void openScreensaver(bool notify) = 0;
|
||||
|
||||
//! Close screen saver
|
||||
|
@ -154,6 +171,12 @@ public:
|
|||
*/
|
||||
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
|
||||
//@{
|
||||
|
@ -164,35 +187,49 @@ public:
|
|||
*/
|
||||
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
|
||||
true iff successful.
|
||||
Event data is CMotionInfo* and the values are an absolute position.
|
||||
*/
|
||||
virtual bool getClipboard(ClipboardID id, IClipboard*) const = 0;
|
||||
|
||||
//! Get screen shape
|
||||
static CEvent::Type getMotionOnPrimaryEvent();
|
||||
//! Get mouse motion on a secondary screen event type
|
||||
/*!
|
||||
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 w (width) and \c h (height).
|
||||
Event data is CMotionInfo* and the values are motion deltas not
|
||||
absolute coordinates.
|
||||
*/
|
||||
virtual void getShape(SInt32& x, SInt32& y,
|
||||
SInt32& w, SInt32& h) 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;
|
||||
static CEvent::Type getMotionOnSecondaryEvent();
|
||||
//! Get mouse wheel event type. Event data is CWheelInfo*.
|
||||
static CEvent::Type getWheelEvent();
|
||||
//! Get screensaver activated event type
|
||||
static CEvent::Type getScreensaverActivatedEvent();
|
||||
//! Get screensaver deactivated event type
|
||||
static CEvent::Type getScreensaverDeactivatedEvent();
|
||||
|
||||
//@}
|
||||
|
||||
// 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
|
||||
virtual void reconfigure(UInt32 activeSides) = 0;
|
||||
virtual void warpCursor(SInt32 x, SInt32 y) = 0;
|
||||
virtual UInt32 addOneShotTimer(double timeout) = 0;
|
||||
virtual SInt32 getJumpZoneSize() const = 0;
|
||||
virtual bool isAnyMouseButtonDown() const = 0;
|
||||
virtual void getCursorCenter(SInt32& x, SInt32& y) const = 0;
|
||||
virtual const char* getKeyName(KeyButton) const = 0;
|
||||
|
||||
// ISecondaryScreen overrides
|
||||
|
@ -205,6 +242,18 @@ public:
|
|||
const IKeyState& keyState, KeyID id,
|
||||
KeyModifierMask desiredMask,
|
||||
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
|
||||
|
|
|
@ -25,7 +25,6 @@ primary screen implementations.
|
|||
*/
|
||||
class IPrimaryScreen : public IInterface {
|
||||
public:
|
||||
// XXX -- may need an interface for sending events
|
||||
//! @name manipulators
|
||||
//@{
|
||||
|
||||
|
@ -46,15 +45,6 @@ public:
|
|||
*/
|
||||
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
|
||||
//@{
|
||||
|
@ -72,6 +62,14 @@ public:
|
|||
*/
|
||||
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
|
||||
/*!
|
||||
Return a string describing the given key.
|
||||
|
|
|
@ -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
|
|
@ -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");
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -16,6 +16,7 @@
|
|||
#define ISCREENSAVER_H
|
||||
|
||||
#include "IInterface.h"
|
||||
#include "CEvent.h"
|
||||
|
||||
//! Screen saver interface
|
||||
/*!
|
||||
|
|
|
@ -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
|
|
@ -29,6 +29,8 @@ libsynergy_a_SOURCES = \
|
|||
CPacketStreamFilter.cpp \
|
||||
CProtocolUtil.cpp \
|
||||
CScreen.cpp \
|
||||
IPlatformScreen.cpp \
|
||||
IScreen.cpp \
|
||||
XScreen.cpp \
|
||||
XSynergy.cpp \
|
||||
CClipboard.h \
|
||||
|
@ -41,12 +43,9 @@ libsynergy_a_SOURCES = \
|
|||
IKeyState.h \
|
||||
IPlatformScreen.h \
|
||||
IPrimaryScreen.h \
|
||||
IPrimaryScreenReceiver.h \
|
||||
IScreenFactory.h \
|
||||
IScreenReceiver.h \
|
||||
IScreen.h \
|
||||
IScreenSaver.h \
|
||||
ISecondaryScreen.h \
|
||||
IServer.h \
|
||||
KeyTypes.h \
|
||||
MouseTypes.h \
|
||||
OptionTypes.h \
|
||||
|
|
Loading…
Reference in New Issue