Checkpoint. Conversion to event driven system complete for Unix.
Still need to convert win32 platform specific files.
This commit is contained in:
parent
901a76df0d
commit
48908242d2
|
@ -15,7 +15,7 @@
|
||||||
#include "CClientTaskBarReceiver.h"
|
#include "CClientTaskBarReceiver.h"
|
||||||
#include "CClient.h"
|
#include "CClient.h"
|
||||||
#include "CLock.h"
|
#include "CLock.h"
|
||||||
#include "TMethodJob.h"
|
#include "IEventQueue.h"
|
||||||
#include "CArch.h"
|
#include "CArch.h"
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -23,71 +23,73 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
CClientTaskBarReceiver::CClientTaskBarReceiver() :
|
CClientTaskBarReceiver::CClientTaskBarReceiver() :
|
||||||
m_quit(NULL),
|
m_state(kNotRunning)
|
||||||
m_state(kNotRunning),
|
|
||||||
m_client(NULL)
|
|
||||||
{
|
{
|
||||||
// create a job for getting notification when the client's
|
// do nothing
|
||||||
// status changes.
|
|
||||||
m_job = new TMethodJob<CClientTaskBarReceiver>(this,
|
|
||||||
&CClientTaskBarReceiver::statusChanged, NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CClientTaskBarReceiver::~CClientTaskBarReceiver()
|
CClientTaskBarReceiver::~CClientTaskBarReceiver()
|
||||||
{
|
{
|
||||||
if (m_client != NULL) {
|
// do nothing
|
||||||
m_client->removeStatusJob(m_job);
|
|
||||||
}
|
|
||||||
delete m_job;
|
|
||||||
delete m_quit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CClientTaskBarReceiver::setClient(CClient* client)
|
CClientTaskBarReceiver::updateStatus(CClient* client, const CString& errorMsg)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
|
// update our status
|
||||||
CLock lock(&m_mutex);
|
CLock lock(&m_mutex);
|
||||||
if (m_client != client) {
|
m_errorMessage = errorMsg;
|
||||||
if (m_client != NULL) {
|
if (client == NULL) {
|
||||||
m_client->removeStatusJob(m_job);
|
if (m_errorMessage.empty()) {
|
||||||
|
m_state = kNotRunning;
|
||||||
}
|
}
|
||||||
m_client = client;
|
else {
|
||||||
if (m_client != NULL) {
|
m_state = kNotWorking;
|
||||||
m_client->addStatusJob(m_job);
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (client->isConnected()) {
|
||||||
|
m_state = kConnected;
|
||||||
|
}
|
||||||
|
else if (client->isConnecting()) {
|
||||||
|
m_state = kConnecting;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_state = kNotConnected;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
ARCH->updateReceiver(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
// let subclasses have a go
|
||||||
CClientTaskBarReceiver::setState(EState state)
|
onStatusChanged(client);
|
||||||
{
|
|
||||||
{
|
|
||||||
CLock lock(&m_mutex);
|
|
||||||
m_state = state;
|
|
||||||
}
|
}
|
||||||
ARCH->updateReceiver(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
// tell task bar
|
||||||
CClientTaskBarReceiver::setQuitJob(IJob* job)
|
ARCH->updateReceiver(this);
|
||||||
{
|
|
||||||
CLock lock(&m_mutex);
|
|
||||||
delete m_quit;
|
|
||||||
m_quit = job;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CClientTaskBarReceiver::EState
|
CClientTaskBarReceiver::EState
|
||||||
CClientTaskBarReceiver::getState() const
|
CClientTaskBarReceiver::getStatus() const
|
||||||
{
|
{
|
||||||
return m_state;
|
return m_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
CClient*
|
const CString&
|
||||||
CClientTaskBarReceiver::getClient() const
|
CClientTaskBarReceiver::getErrorMessage() const
|
||||||
{
|
{
|
||||||
return m_client;
|
return m_errorMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CClientTaskBarReceiver::quit()
|
||||||
|
{
|
||||||
|
EVENTQUEUE->addEvent(CEvent(CEvent::kQuit));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CClientTaskBarReceiver::onStatusChanged(CClient*)
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -113,7 +115,10 @@ CClientTaskBarReceiver::getToolTip() const
|
||||||
return CString("Synergy: ") + m_errorMessage;
|
return CString("Synergy: ") + m_errorMessage;
|
||||||
|
|
||||||
case kNotConnected:
|
case kNotConnected:
|
||||||
return "Synergy: Waiting for clients";
|
return CString("Synergy: Not connected: ") + m_errorMessage;
|
||||||
|
|
||||||
|
case kConnecting:
|
||||||
|
return "Synergy: Connecting...";
|
||||||
|
|
||||||
case kConnected:
|
case kConnected:
|
||||||
return "Synergy: Connected";
|
return "Synergy: Connected";
|
||||||
|
@ -122,42 +127,3 @@ CClientTaskBarReceiver::getToolTip() const
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
CClientTaskBarReceiver::quit()
|
|
||||||
{
|
|
||||||
if (m_quit != NULL) {
|
|
||||||
m_quit->run();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CClientTaskBarReceiver::onStatusChanged()
|
|
||||||
{
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CClientTaskBarReceiver::statusChanged(void*)
|
|
||||||
{
|
|
||||||
// update our status
|
|
||||||
switch (m_client->getStatus(&m_errorMessage)) {
|
|
||||||
case CClient::kNotRunning:
|
|
||||||
setState(kNotRunning);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CClient::kRunning:
|
|
||||||
setState(kConnected);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CClient::kError:
|
|
||||||
setState(kNotWorking);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// let subclasses have a go
|
|
||||||
onStatusChanged();
|
|
||||||
}
|
|
||||||
|
|
|
@ -20,59 +20,21 @@
|
||||||
#include "IArchTaskBarReceiver.h"
|
#include "IArchTaskBarReceiver.h"
|
||||||
|
|
||||||
class CClient;
|
class CClient;
|
||||||
class IJob;
|
|
||||||
|
|
||||||
//! Implementation of IArchTaskBarReceiver for the synergy server
|
//! Implementation of IArchTaskBarReceiver for the synergy server
|
||||||
class CClientTaskBarReceiver : public IArchTaskBarReceiver {
|
class CClientTaskBarReceiver : public IArchTaskBarReceiver {
|
||||||
public:
|
public:
|
||||||
enum EState {
|
|
||||||
kNotRunning,
|
|
||||||
kNotWorking,
|
|
||||||
kNotConnected,
|
|
||||||
kConnected,
|
|
||||||
kMaxState
|
|
||||||
};
|
|
||||||
|
|
||||||
CClientTaskBarReceiver();
|
CClientTaskBarReceiver();
|
||||||
virtual ~CClientTaskBarReceiver();
|
virtual ~CClientTaskBarReceiver();
|
||||||
|
|
||||||
//! @name manipulators
|
//! @name manipulators
|
||||||
//@{
|
//@{
|
||||||
|
|
||||||
//! Set server
|
//! Update status
|
||||||
/*!
|
/*!
|
||||||
Sets the server. The receiver will query state from this server.
|
Determine the status and query required information from the client.
|
||||||
*/
|
*/
|
||||||
void setClient(CClient*);
|
void updateStatus(CClient*, const CString& errorMsg);
|
||||||
|
|
||||||
//! Set state
|
|
||||||
/*!
|
|
||||||
Sets the current server state.
|
|
||||||
*/
|
|
||||||
void setState(EState);
|
|
||||||
|
|
||||||
//! Set the quit job that causes the server to quit
|
|
||||||
/*!
|
|
||||||
Set the job that causes the server to quit.
|
|
||||||
*/
|
|
||||||
void setQuitJob(IJob* adopted);
|
|
||||||
|
|
||||||
//@}
|
|
||||||
//! @name accessors
|
|
||||||
//@{
|
|
||||||
|
|
||||||
//! Get state
|
|
||||||
/*!
|
|
||||||
Returns the current server state. The receiver is not locked
|
|
||||||
by this call; the caller must do the locking.
|
|
||||||
*/
|
|
||||||
EState getState() const;
|
|
||||||
|
|
||||||
//! Get server
|
|
||||||
/*!
|
|
||||||
Returns the server set by \c setClient().
|
|
||||||
*/
|
|
||||||
CClient* getClient() const;
|
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
|
@ -86,24 +48,36 @@ public:
|
||||||
virtual std::string getToolTip() const;
|
virtual std::string getToolTip() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
enum EState {
|
||||||
|
kNotRunning,
|
||||||
|
kNotWorking,
|
||||||
|
kNotConnected,
|
||||||
|
kConnecting,
|
||||||
|
kConnected,
|
||||||
|
kMaxState
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Get status
|
||||||
|
EState getStatus() const;
|
||||||
|
|
||||||
|
//! Get error message
|
||||||
|
const CString& getErrorMessage() const;
|
||||||
|
|
||||||
|
//! Quit app
|
||||||
|
/*!
|
||||||
|
Causes the application to quit gracefully
|
||||||
|
*/
|
||||||
void quit();
|
void quit();
|
||||||
|
|
||||||
//! Status change notification
|
//! Status change notification
|
||||||
/*!
|
/*!
|
||||||
Called when status changes. The default implementation does
|
Called when status changes. The default implementation does nothing.
|
||||||
nothing.
|
|
||||||
*/
|
*/
|
||||||
virtual void onStatusChanged();
|
virtual void onStatusChanged(CClient* client);
|
||||||
|
|
||||||
private:
|
|
||||||
void statusChanged(void*);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CMutex m_mutex;
|
CMutex m_mutex;
|
||||||
IJob* m_quit;
|
|
||||||
EState m_state;
|
EState m_state;
|
||||||
CClient* m_client;
|
|
||||||
IJob* m_job;
|
|
||||||
CString m_errorMessage;
|
CString m_errorMessage;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -53,9 +53,3 @@ CXWindowsClientTaskBarReceiver::getIcon() const
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
CXWindowsClientTaskBarReceiver::onStatusChanged()
|
|
||||||
{
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
|
@ -28,10 +28,6 @@ public:
|
||||||
virtual void runMenu(int x, int y);
|
virtual void runMenu(int x, int y);
|
||||||
virtual void primaryAction();
|
virtual void primaryAction();
|
||||||
virtual const Icon getIcon() const;
|
virtual const Icon getIcon() const;
|
||||||
|
|
||||||
protected:
|
|
||||||
// CClientTaskBarReceiver overrides
|
|
||||||
virtual void onStatusChanged();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -13,23 +13,22 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "CClient.h"
|
#include "CClient.h"
|
||||||
#include "IScreenFactory.h"
|
#include "CScreen.h"
|
||||||
#include "ProtocolTypes.h"
|
#include "ProtocolTypes.h"
|
||||||
#include "Version.h"
|
#include "Version.h"
|
||||||
#include "XScreen.h"
|
#include "XScreen.h"
|
||||||
#include "CNetworkAddress.h"
|
#include "CNetworkAddress.h"
|
||||||
|
#include "CSocketMultiplexer.h"
|
||||||
#include "CTCPSocketFactory.h"
|
#include "CTCPSocketFactory.h"
|
||||||
#include "XSocket.h"
|
#include "XSocket.h"
|
||||||
#include "CCondVar.h"
|
|
||||||
#include "CLock.h"
|
|
||||||
#include "CMutex.h"
|
|
||||||
#include "CThread.h"
|
#include "CThread.h"
|
||||||
#include "XThread.h"
|
#include "CEventQueue.h"
|
||||||
#include "CFunctionJob.h"
|
#include "CFunctionEventJob.h"
|
||||||
#include "CLog.h"
|
#include "CLog.h"
|
||||||
#include "LogOutputters.h"
|
|
||||||
#include "CString.h"
|
#include "CString.h"
|
||||||
|
#include "LogOutputters.h"
|
||||||
#include "CArch.h"
|
#include "CArch.h"
|
||||||
|
#include "XArch.h"
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
#define DAEMON_RUNNING(running_)
|
#define DAEMON_RUNNING(running_)
|
||||||
|
@ -87,160 +86,290 @@ CArgs* CArgs::s_instance = NULL;
|
||||||
// platform dependent factories
|
// platform dependent factories
|
||||||
//
|
//
|
||||||
|
|
||||||
//! Factory for creating screens
|
static
|
||||||
/*!
|
CScreen*
|
||||||
Objects of this type create screens appropriate for the platform.
|
createScreen()
|
||||||
*/
|
|
||||||
class CScreenFactory : public IScreenFactory {
|
|
||||||
public:
|
|
||||||
CScreenFactory() { }
|
|
||||||
virtual ~CScreenFactory() { }
|
|
||||||
|
|
||||||
// IScreenFactory overrides
|
|
||||||
virtual IPlatformScreen*
|
|
||||||
create(IScreenReceiver*, IPrimaryScreenReceiver*);
|
|
||||||
};
|
|
||||||
|
|
||||||
IPlatformScreen*
|
|
||||||
CScreenFactory::create(IScreenReceiver* receiver,
|
|
||||||
IPrimaryScreenReceiver* primaryReceiver)
|
|
||||||
{
|
{
|
||||||
#if WINDOWS_LIKE
|
#if WINDOWS_LIKE
|
||||||
return new CMSWindowsScreen(receiver, primaryReceiver);
|
return new CScreen(new CMSWindowsScreen(false));
|
||||||
#elif UNIX_LIKE
|
#elif UNIX_LIKE
|
||||||
return new CXWindowsScreen(receiver, primaryReceiver);
|
return new CScreen(new CXWindowsScreen(false));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//! CQuitJob
|
|
||||||
/*!
|
|
||||||
A job that cancels a given thread.
|
|
||||||
*/
|
|
||||||
class CQuitJob : public IJob {
|
|
||||||
public:
|
|
||||||
CQuitJob(const CThread& thread);
|
|
||||||
~CQuitJob();
|
|
||||||
|
|
||||||
// IJob overrides
|
|
||||||
virtual void run();
|
|
||||||
|
|
||||||
private:
|
|
||||||
CThread m_thread;
|
|
||||||
};
|
|
||||||
|
|
||||||
CQuitJob::CQuitJob(const CThread& thread) :
|
|
||||||
m_thread(thread)
|
|
||||||
{
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
CQuitJob::~CQuitJob()
|
|
||||||
{
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CQuitJob::run()
|
|
||||||
{
|
|
||||||
m_thread.cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// platform independent main
|
// platform independent main
|
||||||
//
|
//
|
||||||
|
|
||||||
static CClient* s_client = NULL;
|
static CClient* s_client = NULL;
|
||||||
|
static CScreen* s_clientScreen = NULL;
|
||||||
static CClientTaskBarReceiver* s_taskBarReceiver = NULL;
|
static CClientTaskBarReceiver* s_taskBarReceiver = NULL;
|
||||||
|
static double s_retryTime = 0.0;
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
updateStatus()
|
||||||
|
{
|
||||||
|
s_taskBarReceiver->updateStatus(s_client, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
updateStatus(const CString& msg)
|
||||||
|
{
|
||||||
|
s_taskBarReceiver->updateStatus(s_client, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
resetRestartTimeout()
|
||||||
|
{
|
||||||
|
s_retryTime = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
double
|
||||||
|
nextRestartTimeout()
|
||||||
|
{
|
||||||
|
// choose next restart timeout. we start with rapid retries
|
||||||
|
// then slow down.
|
||||||
|
if (s_retryTime < 1.0) {
|
||||||
|
s_retryTime = 1.0;
|
||||||
|
}
|
||||||
|
else if (s_retryTime < 3.0) {
|
||||||
|
s_retryTime = 3.0;
|
||||||
|
}
|
||||||
|
else if (s_retryTime < 5.0) {
|
||||||
|
s_retryTime = 5.0;
|
||||||
|
}
|
||||||
|
else if (s_retryTime < 15.0) {
|
||||||
|
s_retryTime = 15.0;
|
||||||
|
}
|
||||||
|
else if (s_retryTime < 30.0) {
|
||||||
|
s_retryTime = 30.0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
s_retryTime = 60.0;
|
||||||
|
}
|
||||||
|
return s_retryTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
handleScreenError(const CEvent&, void*)
|
||||||
|
{
|
||||||
|
LOG((CLOG_CRIT "error on screen"));
|
||||||
|
EVENTQUEUE->addEvent(CEvent(CEvent::kQuit));
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
CScreen*
|
||||||
|
openClientScreen()
|
||||||
|
{
|
||||||
|
CScreen* screen = createScreen();
|
||||||
|
EVENTQUEUE->adoptHandler(IScreen::getErrorEvent(),
|
||||||
|
screen->getEventTarget(),
|
||||||
|
new CFunctionEventJob(
|
||||||
|
&handleScreenError));
|
||||||
|
return screen;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
closeClientScreen(CScreen* screen)
|
||||||
|
{
|
||||||
|
if (screen != NULL) {
|
||||||
|
EVENTQUEUE->removeHandler(IScreen::getErrorEvent(),
|
||||||
|
screen->getEventTarget());
|
||||||
|
delete screen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
handleClientRestart(const CEvent&, void* vtimer)
|
||||||
|
{
|
||||||
|
// discard old timer
|
||||||
|
CEventQueueTimer* timer = reinterpret_cast<CEventQueueTimer*>(vtimer);
|
||||||
|
EVENTQUEUE->deleteTimer(timer);
|
||||||
|
EVENTQUEUE->removeHandler(CEvent::kTimer, NULL);
|
||||||
|
|
||||||
|
// reconnect
|
||||||
|
s_client->connect();
|
||||||
|
updateStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
scheduleClientRestart(double retryTime)
|
||||||
|
{
|
||||||
|
// 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(&handleClientRestart, timer));
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
handleClientConnected(const CEvent&, void*)
|
||||||
|
{
|
||||||
|
LOG((CLOG_DEBUG "connected to server"));
|
||||||
|
resetRestartTimeout();
|
||||||
|
updateStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
handleClientFailed(const CEvent& e, void*)
|
||||||
|
{
|
||||||
|
CClient::CFailInfo* info =
|
||||||
|
reinterpret_cast<CClient::CFailInfo*>(e.getData());
|
||||||
|
|
||||||
|
updateStatus(CString("Failed to connect to server: ") + info->m_what);
|
||||||
|
if (!ARG->m_restartable || !info->m_retry) {
|
||||||
|
LOG((CLOG_ERR "failed to connect to server: %s", info->m_what));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LOG((CLOG_WARN "failed to connect to server: %s", info->m_what));
|
||||||
|
scheduleClientRestart(nextRestartTimeout());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
handleClientDisconnected(const CEvent&, void*)
|
||||||
|
{
|
||||||
|
LOG((CLOG_NOTE "disconnected from server"));
|
||||||
|
if (!ARG->m_restartable) {
|
||||||
|
EVENTQUEUE->addEvent(CEvent(CEvent::kQuit));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
s_client->connect();
|
||||||
|
}
|
||||||
|
updateStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
CClient*
|
||||||
|
openClient(const CString& name, const CNetworkAddress& address, CScreen* screen)
|
||||||
|
{
|
||||||
|
CClient* client = new CClient(name, address,
|
||||||
|
new CTCPSocketFactory, NULL, screen);
|
||||||
|
EVENTQUEUE->adoptHandler(CClient::getConnectedEvent(),
|
||||||
|
client->getEventTarget(),
|
||||||
|
new CFunctionEventJob(handleClientConnected));
|
||||||
|
EVENTQUEUE->adoptHandler(CClient::getConnectionFailedEvent(),
|
||||||
|
client->getEventTarget(),
|
||||||
|
new CFunctionEventJob(handleClientFailed));
|
||||||
|
EVENTQUEUE->adoptHandler(CClient::getDisconnectedEvent(),
|
||||||
|
client->getEventTarget(),
|
||||||
|
new CFunctionEventJob(handleClientDisconnected));
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
closeClient(CClient* client)
|
||||||
|
{
|
||||||
|
if (client == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
EVENTQUEUE->removeHandler(CClient::getConnectedEvent(), client);
|
||||||
|
EVENTQUEUE->removeHandler(CClient::getConnectionFailedEvent(), client);
|
||||||
|
EVENTQUEUE->removeHandler(CClient::getDisconnectedEvent(), client);
|
||||||
|
delete client;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
bool
|
||||||
|
startClient()
|
||||||
|
{
|
||||||
|
double retryTime;
|
||||||
|
CScreen* clientScreen = NULL;
|
||||||
|
try {
|
||||||
|
clientScreen = openClientScreen();
|
||||||
|
s_client = openClient(ARG->m_name,
|
||||||
|
ARG->m_serverAddress, clientScreen);
|
||||||
|
s_clientScreen = clientScreen;
|
||||||
|
LOG((CLOG_NOTE "started client"));
|
||||||
|
s_client->connect();
|
||||||
|
updateStatus();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (XScreenUnavailable& e) {
|
||||||
|
LOG((CLOG_WARN "cannot open secondary screen: %s", e.what()));
|
||||||
|
closeClientScreen(clientScreen);
|
||||||
|
updateStatus(CString("Cannot open secondary screen: ") + e.what());
|
||||||
|
retryTime = e.getRetryTime();
|
||||||
|
}
|
||||||
|
catch (XScreenOpenFailure& e) {
|
||||||
|
LOG((CLOG_CRIT "cannot open secondary screen: %s", e.what()));
|
||||||
|
closeClientScreen(clientScreen);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
catch (XBase& e) {
|
||||||
|
LOG((CLOG_CRIT "failed to start client: %s", e.what()));
|
||||||
|
closeClientScreen(clientScreen);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ARG->m_restartable) {
|
||||||
|
scheduleClientRestart(retryTime);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// don't try again
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
stopClient()
|
||||||
|
{
|
||||||
|
closeClient(s_client);
|
||||||
|
closeClientScreen(s_clientScreen);
|
||||||
|
s_client = NULL;
|
||||||
|
s_clientScreen = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
int
|
int
|
||||||
realMain(void)
|
realMain()
|
||||||
{
|
{
|
||||||
int result = kExitSuccess;
|
// start the client. if this return false then we've failed and
|
||||||
do {
|
// we shouldn't retry.
|
||||||
bool opened = false;
|
LOG((CLOG_DEBUG1 "starting client"));
|
||||||
bool locked = true;
|
if (!startClient()) {
|
||||||
try {
|
return kExitFailed;
|
||||||
// create client
|
}
|
||||||
s_client = new CClient(ARG->m_name);
|
|
||||||
s_client->setAddress(ARG->m_serverAddress);
|
|
||||||
s_client->setScreenFactory(new CScreenFactory);
|
|
||||||
s_client->setSocketFactory(new CTCPSocketFactory);
|
|
||||||
s_client->setStreamFilterFactory(NULL);
|
|
||||||
|
|
||||||
// open client
|
// run event loop. if startClient() failed we're supposed to retry
|
||||||
try {
|
// later. the timer installed by startClient() will take care of
|
||||||
s_taskBarReceiver->setClient(s_client);
|
// that.
|
||||||
s_client->open();
|
DAEMON_RUNNING(true);
|
||||||
opened = true;
|
CEvent event;
|
||||||
|
EVENTQUEUE->getEvent(event);
|
||||||
|
while (event.getType() != CEvent::kQuit) {
|
||||||
|
EVENTQUEUE->dispatchEvent(event);
|
||||||
|
CEvent::deleteData(event);
|
||||||
|
EVENTQUEUE->getEvent(event);
|
||||||
|
}
|
||||||
|
DAEMON_RUNNING(false);
|
||||||
|
|
||||||
// run client
|
// close down
|
||||||
DAEMON_RUNNING(true);
|
LOG((CLOG_DEBUG1 "stopping client"));
|
||||||
locked = false;
|
stopClient();
|
||||||
s_client->mainLoop();
|
updateStatus();
|
||||||
locked = true;
|
LOG((CLOG_NOTE "stopped client"));
|
||||||
DAEMON_RUNNING(false);
|
|
||||||
|
|
||||||
// get client status
|
return kExitSuccess;
|
||||||
if (s_client->wasRejected()) {
|
|
||||||
// try again later. we don't want to bother
|
|
||||||
// the server very often if it doesn't want us.
|
|
||||||
throw XScreenUnavailable(60.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// clean up
|
|
||||||
#define FINALLY do { \
|
|
||||||
if (!locked) { \
|
|
||||||
DAEMON_RUNNING(false); \
|
|
||||||
locked = true; \
|
|
||||||
} \
|
|
||||||
if (opened) { \
|
|
||||||
s_client->close(); \
|
|
||||||
} \
|
|
||||||
s_taskBarReceiver->setClient(NULL); \
|
|
||||||
delete s_client; \
|
|
||||||
s_client = NULL; \
|
|
||||||
} while (false)
|
|
||||||
FINALLY;
|
|
||||||
}
|
|
||||||
catch (XScreenUnavailable& e) {
|
|
||||||
// wait before retrying if we're going to retry
|
|
||||||
if (ARG->m_restartable) {
|
|
||||||
LOG((CLOG_DEBUG "waiting %.0f seconds to retry", e.getRetryTime()));
|
|
||||||
ARCH->sleep(e.getRetryTime());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
result = kExitFailed;
|
|
||||||
}
|
|
||||||
FINALLY;
|
|
||||||
}
|
|
||||||
catch (XThread&) {
|
|
||||||
FINALLY;
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
catch (...) {
|
|
||||||
// don't try to restart and fail
|
|
||||||
ARG->m_restartable = false;
|
|
||||||
result = kExitFailed;
|
|
||||||
FINALLY;
|
|
||||||
}
|
|
||||||
#undef FINALLY
|
|
||||||
}
|
|
||||||
catch (XBase& e) {
|
|
||||||
LOG((CLOG_CRIT "failed: %s", e.what()));
|
|
||||||
}
|
|
||||||
catch (XThread&) {
|
|
||||||
// terminated
|
|
||||||
ARG->m_restartable = false;
|
|
||||||
result = kExitTerminated;
|
|
||||||
}
|
|
||||||
} while (ARG->m_restartable);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
static
|
static
|
||||||
void
|
void
|
||||||
realMainEntry(void* vresult)
|
realMainEntry(void* vresult)
|
||||||
|
@ -278,6 +407,7 @@ runMainInThread(void)
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -292,14 +422,12 @@ static
|
||||||
void
|
void
|
||||||
version()
|
version()
|
||||||
{
|
{
|
||||||
LOG((CLOG_PRINT
|
LOG((CLOG_PRINT "%s %s, protocol version %d.%d\n%s",
|
||||||
"%s %s, protocol version %d.%d\n"
|
ARG->m_pname,
|
||||||
"%s",
|
kVersion,
|
||||||
ARG->m_pname,
|
kProtocolMajorVersion,
|
||||||
kVersion,
|
kProtocolMinorVersion,
|
||||||
kProtocolMajorVersion,
|
kCopyright));
|
||||||
kProtocolMinorVersion,
|
|
||||||
kCopyright));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
|
@ -697,15 +825,20 @@ main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
CArch arch;
|
CArch arch;
|
||||||
CLOG;
|
CLOG;
|
||||||
CArgs args;
|
|
||||||
|
// go really fast
|
||||||
|
CThread::getCurrentThread().setPriority(-14);
|
||||||
|
|
||||||
|
CSocketMultiplexer multiplexer;
|
||||||
|
CEventQueue eventQueue;
|
||||||
|
|
||||||
// get program name
|
// get program name
|
||||||
|
CArgs args;
|
||||||
ARG->m_pname = ARCH->getBasename(argv[0]);
|
ARG->m_pname = ARCH->getBasename(argv[0]);
|
||||||
|
|
||||||
// make the task bar receiver. the user can control this app
|
// make the task bar receiver. the user can control this app
|
||||||
// through the task bar.
|
// through the task bar.
|
||||||
s_taskBarReceiver = new CXWindowsClientTaskBarReceiver;
|
s_taskBarReceiver = new CXWindowsClientTaskBarReceiver;
|
||||||
s_taskBarReceiver->setQuitJob(new CQuitJob(CThread::getCurrentThread()));
|
|
||||||
|
|
||||||
// parse command line
|
// parse command line
|
||||||
parse(argc, argv);
|
parse(argc, argv);
|
||||||
|
|
|
@ -14,8 +14,8 @@
|
||||||
|
|
||||||
#include "CServerTaskBarReceiver.h"
|
#include "CServerTaskBarReceiver.h"
|
||||||
#include "CServer.h"
|
#include "CServer.h"
|
||||||
#include "CEventQueue.h"
|
|
||||||
#include "CLock.h"
|
#include "CLock.h"
|
||||||
|
#include "IEventQueue.h"
|
||||||
#include "CArch.h"
|
#include "CArch.h"
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
|
@ -171,25 +171,35 @@ closeClientListener(CClientListener* listen)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
handleScreenError(const CEvent&, void*)
|
||||||
|
{
|
||||||
|
LOG((CLOG_CRIT "error on screen"));
|
||||||
|
EVENTQUEUE->addEvent(CEvent(CEvent::kQuit));
|
||||||
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
CScreen*
|
CScreen*
|
||||||
openServerScreen()
|
openServerScreen()
|
||||||
{
|
{
|
||||||
return createScreen();
|
CScreen* screen = createScreen();
|
||||||
|
EVENTQUEUE->adoptHandler(IScreen::getErrorEvent(),
|
||||||
|
screen->getEventTarget(),
|
||||||
|
new CFunctionEventJob(
|
||||||
|
&handleScreenError));
|
||||||
|
return screen;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
void
|
void
|
||||||
closeServerScreen(CScreen* screen)
|
closeServerScreen(CScreen* screen)
|
||||||
{
|
{
|
||||||
delete screen;
|
if (screen != NULL) {
|
||||||
}
|
EVENTQUEUE->removeHandler(IScreen::getErrorEvent(),
|
||||||
|
screen->getEventTarget());
|
||||||
static
|
delete screen;
|
||||||
void
|
}
|
||||||
handleScreenError(const CEvent&, void*)
|
|
||||||
{
|
|
||||||
EVENTQUEUE->addEvent(CEvent(CEvent::kQuit));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
|
@ -197,23 +207,14 @@ CPrimaryClient*
|
||||||
openPrimaryClient(const CString& name, CScreen* screen)
|
openPrimaryClient(const CString& name, CScreen* screen)
|
||||||
{
|
{
|
||||||
LOG((CLOG_DEBUG1 "creating primary screen"));
|
LOG((CLOG_DEBUG1 "creating primary screen"));
|
||||||
CPrimaryClient* primaryClient = new CPrimaryClient(name, screen);
|
return new CPrimaryClient(name, screen);
|
||||||
EVENTQUEUE->adoptHandler(IScreen::getErrorEvent(),
|
|
||||||
primaryClient->getEventTarget(),
|
|
||||||
new CFunctionEventJob(
|
|
||||||
&handleScreenError));
|
|
||||||
return primaryClient;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
void
|
void
|
||||||
closePrimaryClient(CPrimaryClient* primaryClient)
|
closePrimaryClient(CPrimaryClient* primaryClient)
|
||||||
{
|
{
|
||||||
if (primaryClient != NULL) {
|
delete primaryClient;
|
||||||
EVENTQUEUE->removeHandler(IScreen::getErrorEvent(),
|
|
||||||
primaryClient->getEventTarget());
|
|
||||||
delete primaryClient;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
|
@ -711,7 +712,7 @@ parse(int argc, const char* const* argv)
|
||||||
|
|
||||||
static
|
static
|
||||||
bool
|
bool
|
||||||
loadConfig(const char* pathname, bool require)
|
loadConfig(const char* pathname)
|
||||||
{
|
{
|
||||||
assert(pathname != NULL);
|
assert(pathname != NULL);
|
||||||
|
|
||||||
|
@ -727,15 +728,8 @@ loadConfig(const char* pathname, bool require)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch (XConfigRead& e) {
|
catch (XConfigRead& e) {
|
||||||
if (require) {
|
LOG((CLOG_DEBUG "cannot read configuration \"%s\": %s",
|
||||||
LOG((CLOG_PRINT "%s: cannot read configuration '%s': %s",
|
|
||||||
ARG->m_pname, pathname, e.what()));
|
|
||||||
bye(kExitConfig);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
LOG((CLOG_DEBUG "cannot read configuration \"%s\": %s",
|
|
||||||
pathname, e.what()));
|
pathname, e.what()));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -744,34 +738,38 @@ static
|
||||||
void
|
void
|
||||||
loadConfig()
|
loadConfig()
|
||||||
{
|
{
|
||||||
|
bool loaded = false;
|
||||||
|
|
||||||
// load the config file, if specified
|
// load the config file, if specified
|
||||||
if (ARG->m_configFile != NULL) {
|
if (ARG->m_configFile != NULL) {
|
||||||
// require the user specified file to load correctly
|
loaded = loadConfig(ARG->m_configFile);
|
||||||
loadConfig(ARG->m_configFile, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// load the default configuration if no explicit file given
|
// load the default configuration if no explicit file given
|
||||||
else {
|
else {
|
||||||
// get the user's home directory. use the effective user id
|
// get the user's home directory
|
||||||
// so a user can't get a setuid root program to load his file.
|
|
||||||
bool loaded = false;
|
|
||||||
CString path = ARCH->getUserDirectory();
|
CString path = ARCH->getUserDirectory();
|
||||||
if (!path.empty()) {
|
if (!path.empty()) {
|
||||||
// complete path
|
// complete path
|
||||||
path = ARCH->concatPath(path, USR_CONFIG_NAME);
|
path = ARCH->concatPath(path, USR_CONFIG_NAME);
|
||||||
|
|
||||||
// now try loading the user's configuration
|
// now try loading the user's configuration
|
||||||
loaded = loadConfig(path.c_str(), false);
|
loaded = loadConfig(path.c_str());
|
||||||
}
|
}
|
||||||
if (!loaded) {
|
if (!loaded) {
|
||||||
// try the system-wide config file
|
// try the system-wide config file
|
||||||
path = ARCH->getSystemDirectory();
|
path = ARCH->getSystemDirectory();
|
||||||
if (!path.empty()) {
|
if (!path.empty()) {
|
||||||
path = ARCH->concatPath(path, SYS_CONFIG_NAME);
|
path = ARCH->concatPath(path, SYS_CONFIG_NAME);
|
||||||
loadConfig(path.c_str(), false);
|
loaded = loadConfig(path.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!loaded) {
|
||||||
|
LOG((CLOG_PRINT "%s: no configuration available", ARG->m_pname));
|
||||||
|
bye(kExitConfig);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -620,6 +620,13 @@ CArchNetworkBSD::nameToAddr(const std::string& name)
|
||||||
sizeof(inaddr.sin_addr));
|
sizeof(inaddr.sin_addr));
|
||||||
memcpy(&addr->m_addr, &inaddr, addr->m_len);
|
memcpy(&addr->m_addr, &inaddr, addr->m_len);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
ARCH->unlockMutex(m_mutex);
|
||||||
|
delete addr;
|
||||||
|
throw XArchNetworkNameUnsupported(
|
||||||
|
"The requested name is valid but "
|
||||||
|
"does not have a supported address family");
|
||||||
|
}
|
||||||
|
|
||||||
// done with static buffer
|
// done with static buffer
|
||||||
ARCH->unlockMutex(m_mutex);
|
ARCH->unlockMutex(m_mutex);
|
||||||
|
|
|
@ -64,7 +64,8 @@ class XArch {
|
||||||
public:
|
public:
|
||||||
XArch(XArchEval* adoptedEvaluator) : m_eval(adoptedEvaluator) { }
|
XArch(XArchEval* adoptedEvaluator) : m_eval(adoptedEvaluator) { }
|
||||||
XArch(const std::string& msg) : m_eval(NULL), m_what(msg) { }
|
XArch(const std::string& msg) : m_eval(NULL), m_what(msg) { }
|
||||||
XArch(const XArch& e) : m_eval(e.m_eval->clone()), m_what(e.m_what) { }
|
XArch(const XArch& e) : m_eval(e.m_eval != NULL ? e.m_eval->clone() : NULL),
|
||||||
|
m_what(e.m_what) { }
|
||||||
~XArch() { delete m_eval; }
|
~XArch() { delete m_eval; }
|
||||||
|
|
||||||
std::string what() const throw();
|
std::string what() const throw();
|
||||||
|
@ -137,7 +138,7 @@ XARCH_SUBCLASS(XArchNetworkName, XArchNetwork);
|
||||||
//! The named host is unknown
|
//! The named host is unknown
|
||||||
XARCH_SUBCLASS(XArchNetworkNameUnknown, XArchNetworkName);
|
XARCH_SUBCLASS(XArchNetworkNameUnknown, XArchNetworkName);
|
||||||
|
|
||||||
//! The named host is known but has to address
|
//! The named host is known but has no address
|
||||||
XARCH_SUBCLASS(XArchNetworkNameNoAddress, XArchNetworkName);
|
XARCH_SUBCLASS(XArchNetworkNameNoAddress, XArchNetworkName);
|
||||||
|
|
||||||
//! Non-recoverable name server error
|
//! Non-recoverable name server error
|
||||||
|
@ -146,6 +147,9 @@ XARCH_SUBCLASS(XArchNetworkNameFailure, XArchNetworkName);
|
||||||
//! Temporary name server error
|
//! Temporary name server error
|
||||||
XARCH_SUBCLASS(XArchNetworkNameUnavailable, XArchNetworkName);
|
XARCH_SUBCLASS(XArchNetworkNameUnavailable, XArchNetworkName);
|
||||||
|
|
||||||
|
//! The named host is known but no supported address
|
||||||
|
XARCH_SUBCLASS(XArchNetworkNameUnsupported, XArchNetworkName);
|
||||||
|
|
||||||
//! Generic daemon exception
|
//! Generic daemon exception
|
||||||
/*!
|
/*!
|
||||||
Exceptions derived from this class are used by the daemon
|
Exceptions derived from this class are used by the daemon
|
||||||
|
|
|
@ -82,8 +82,7 @@ CEvent::deleteData(const CEvent& event)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// yes, really delete void*
|
free(event.getData());
|
||||||
delete event.getData();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,9 +38,10 @@ public:
|
||||||
//! Create \c CEvent with data
|
//! Create \c CEvent with data
|
||||||
/*!
|
/*!
|
||||||
The \p type must have been registered using \c registerType().
|
The \p type must have been registered using \c registerType().
|
||||||
The \p data must be POD (plain old data) which means it cannot
|
The \p data must be POD (plain old data) allocated by malloc(),
|
||||||
have a destructor or be composed of any types that do. \p target
|
which means it cannot have a constructor, destructor or be
|
||||||
is the intended recipient of the event.
|
composed of any types that do. \p target is the intended
|
||||||
|
recipient of the event.
|
||||||
*/
|
*/
|
||||||
CEvent(Type type, void* target = NULL, void* data = NULL);
|
CEvent(Type type, void* target = NULL, void* data = NULL);
|
||||||
|
|
||||||
|
@ -70,7 +71,7 @@ public:
|
||||||
|
|
||||||
//! Release event data
|
//! Release event data
|
||||||
/*!
|
/*!
|
||||||
Deletes event data for the given event.
|
Deletes event data for the given event (using free()).
|
||||||
*/
|
*/
|
||||||
static void deleteData(const CEvent&);
|
static void deleteData(const CEvent&);
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -15,133 +15,113 @@
|
||||||
#ifndef CCLIENT_H
|
#ifndef CCLIENT_H
|
||||||
#define CCLIENT_H
|
#define CCLIENT_H
|
||||||
|
|
||||||
#include "IScreenReceiver.h"
|
|
||||||
#include "IClient.h"
|
#include "IClient.h"
|
||||||
#include "IClipboard.h"
|
#include "IClipboard.h"
|
||||||
#include "CNetworkAddress.h"
|
#include "CNetworkAddress.h"
|
||||||
#include "CMutex.h"
|
|
||||||
#include "CJobList.h"
|
|
||||||
|
|
||||||
|
class CEventQueueTimer;
|
||||||
class CScreen;
|
class CScreen;
|
||||||
class CServerProxy;
|
class CServerProxy;
|
||||||
class CThread;
|
|
||||||
class IDataSocket;
|
class IDataSocket;
|
||||||
class IScreenReceiver;
|
|
||||||
class IScreenFactory;
|
|
||||||
class ISocketFactory;
|
class ISocketFactory;
|
||||||
|
class IStream;
|
||||||
class IStreamFilterFactory;
|
class IStreamFilterFactory;
|
||||||
|
|
||||||
//! Synergy client
|
//! Synergy client
|
||||||
/*!
|
/*!
|
||||||
This class implements the top-level client algorithms for synergy.
|
This class implements the top-level client algorithms for synergy.
|
||||||
*/
|
*/
|
||||||
class CClient : public IScreenReceiver, public IClient {
|
class CClient : public IClient {
|
||||||
public:
|
public:
|
||||||
enum EStatus {
|
class CFailInfo {
|
||||||
kNotRunning,
|
public:
|
||||||
kRunning,
|
bool m_retry;
|
||||||
kError,
|
char m_what[1];
|
||||||
kMaxStatus
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
This client will attempt to connect the server using \c clientName
|
This client will attempt to connect to the server using \p name
|
||||||
as its name.
|
as its name and \p address as the server's address and \p factory
|
||||||
|
to create the socket. \p screen is the local screen.
|
||||||
*/
|
*/
|
||||||
CClient(const CString& clientName);
|
CClient(const CString& name, const CNetworkAddress& address,
|
||||||
|
ISocketFactory* socketFactory,
|
||||||
|
IStreamFilterFactory* streamFilterFactory,
|
||||||
|
CScreen* screen);
|
||||||
~CClient();
|
~CClient();
|
||||||
|
|
||||||
//! @name manipulators
|
//! @name manipulators
|
||||||
//@{
|
//@{
|
||||||
|
|
||||||
//! Set server address
|
//! Connect to server
|
||||||
/*!
|
/*!
|
||||||
Sets the server's address that the client should connect to.
|
Starts an attempt to connect to the server. This is ignored if
|
||||||
|
the client is trying to connect or is already connected.
|
||||||
*/
|
*/
|
||||||
void setAddress(const CNetworkAddress& serverAddress);
|
void connect();
|
||||||
|
|
||||||
//! Set screen factory
|
//! Disconnect
|
||||||
/*!
|
/*!
|
||||||
Sets the factory for creating screens. This must be set before
|
Disconnects from the server with an optional error message.
|
||||||
calling open(). This object takes ownership of the factory.
|
|
||||||
*/
|
*/
|
||||||
void setScreenFactory(IScreenFactory*);
|
void disconnect(const char* msg);
|
||||||
|
|
||||||
//! Set socket factory
|
|
||||||
/*!
|
|
||||||
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.
|
|
||||||
*/
|
|
||||||
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*);
|
|
||||||
|
|
||||||
//! 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();
|
|
||||||
|
|
||||||
//! Add a job to notify of status changes
|
|
||||||
/*!
|
|
||||||
The added job is run whenever the server's status changes in
|
|
||||||
certain externally visible ways. The client keeps ownership
|
|
||||||
of the job.
|
|
||||||
*/
|
|
||||||
void addStatusJob(IJob*);
|
|
||||||
|
|
||||||
//! Remove a job to notify of status changes
|
|
||||||
/*!
|
|
||||||
Removes a previously added status notification job. A job can
|
|
||||||
remove itself when called but must not remove any other jobs.
|
|
||||||
The client keeps ownership of the job.
|
|
||||||
*/
|
|
||||||
void removeStatusJob(IJob*);
|
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
//! @name accessors
|
//! @name accessors
|
||||||
//@{
|
//@{
|
||||||
|
|
||||||
//!
|
//! Test if connected
|
||||||
/*!
|
/*!
|
||||||
Returns true if the server rejected our connection.
|
Returns true iff the client is successfully connected to the server.
|
||||||
*/
|
*/
|
||||||
bool wasRejected() const;
|
bool isConnected() const;
|
||||||
|
|
||||||
//! Get the status
|
//! Test if connecting
|
||||||
/*!
|
/*!
|
||||||
Returns the current status and status message.
|
Returns true iff the client is currently attempting to connect to
|
||||||
|
the server.
|
||||||
*/
|
*/
|
||||||
EStatus getStatus(CString* = NULL) const;
|
bool isConnecting() const;
|
||||||
|
|
||||||
|
//! Get connected event type
|
||||||
|
/*!
|
||||||
|
Returns the connected event type. This is sent when the client has
|
||||||
|
successfully connected to the server.
|
||||||
|
*/
|
||||||
|
static CEvent::Type getConnectedEvent();
|
||||||
|
|
||||||
|
//! Get connection failed event type
|
||||||
|
/*!
|
||||||
|
Returns the connection failed event type. This is sent when the
|
||||||
|
server fails for some reason. The event data is a CFailInfo*.
|
||||||
|
*/
|
||||||
|
static CEvent::Type getConnectionFailedEvent();
|
||||||
|
|
||||||
|
//! Get disconnected event type
|
||||||
|
/*!
|
||||||
|
Returns the disconnected event type. This is sent when the client
|
||||||
|
has disconnected from the server (and only after having successfully
|
||||||
|
connected).
|
||||||
|
*/
|
||||||
|
static CEvent::Type getDisconnectedEvent();
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
// IScreenReceiver overrides
|
// IScreen overrides
|
||||||
virtual void onError();
|
virtual void* getEventTarget() const;
|
||||||
virtual void onInfoChanged(const CClientInfo&);
|
virtual bool getClipboard(ClipboardID id, IClipboard*) const;
|
||||||
virtual bool onGrabClipboard(ClipboardID);
|
virtual void getShape(SInt32& x, SInt32& y,
|
||||||
virtual void onClipboardChanged(ClipboardID, const CString&);
|
SInt32& width, SInt32& height) const;
|
||||||
|
virtual void getCursorPos(SInt32& x, SInt32& y) const;
|
||||||
|
|
||||||
// IClient overrides
|
// IClient overrides
|
||||||
virtual void open();
|
|
||||||
virtual void mainLoop();
|
|
||||||
virtual void close();
|
|
||||||
virtual void enter(SInt32 xAbs, SInt32 yAbs,
|
virtual void enter(SInt32 xAbs, SInt32 yAbs,
|
||||||
UInt32 seqNum, KeyModifierMask mask,
|
UInt32 seqNum, KeyModifierMask mask,
|
||||||
bool forScreensaver);
|
bool forScreensaver);
|
||||||
virtual bool leave();
|
virtual bool leave();
|
||||||
virtual void setClipboard(ClipboardID, const CString&);
|
virtual void setClipboard(ClipboardID, const IClipboard*);
|
||||||
virtual void grabClipboard(ClipboardID);
|
virtual void grabClipboard(ClipboardID);
|
||||||
virtual void setClipboardDirty(ClipboardID, bool dirty);
|
virtual void setClipboardDirty(ClipboardID, bool);
|
||||||
virtual void keyDown(KeyID, KeyModifierMask, KeyButton);
|
virtual void keyDown(KeyID, KeyModifierMask, KeyButton);
|
||||||
virtual void keyRepeat(KeyID, KeyModifierMask,
|
virtual void keyRepeat(KeyID, KeyModifierMask,
|
||||||
SInt32 count, KeyButton);
|
SInt32 count, KeyButton);
|
||||||
|
@ -154,52 +134,48 @@ public:
|
||||||
virtual void resetOptions();
|
virtual void resetOptions();
|
||||||
virtual void setOptions(const COptionsList& options);
|
virtual void setOptions(const COptionsList& options);
|
||||||
virtual CString getName() const;
|
virtual CString getName() const;
|
||||||
virtual SInt32 getJumpZoneSize() const;
|
|
||||||
virtual void getShape(SInt32& x, SInt32& y,
|
|
||||||
SInt32& width, SInt32& height) const;
|
|
||||||
virtual void getCursorPos(SInt32& x, SInt32& y) const;
|
|
||||||
virtual void getCursorCenter(SInt32& x, SInt32& y) const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// notify status jobs of a change
|
|
||||||
void runStatusJobs() const;
|
|
||||||
|
|
||||||
// set new status
|
|
||||||
void setStatus(EStatus, const char* msg = NULL);
|
|
||||||
|
|
||||||
// open/close the secondary screen
|
|
||||||
void openSecondaryScreen();
|
|
||||||
void closeSecondaryScreen();
|
|
||||||
|
|
||||||
// send the clipboard to the server
|
|
||||||
void sendClipboard(ClipboardID);
|
void sendClipboard(ClipboardID);
|
||||||
|
void sendEvent(CEvent::Type, void*);
|
||||||
// handle server messaging
|
void sendConnectionFailedEvent(const char* msg);
|
||||||
void runSession(void*);
|
void setupConnecting();
|
||||||
void deleteSession(double timeout = -1.0);
|
void setupConnection();
|
||||||
void runServer();
|
void setupScreen();
|
||||||
CServerProxy* handshakeServer(IDataSocket*);
|
void setupTimer();
|
||||||
|
void cleanupConnecting();
|
||||||
|
void cleanupConnection();
|
||||||
|
void cleanupScreen();
|
||||||
|
void cleanupTimer();
|
||||||
|
void handleConnected(const CEvent&, void*);
|
||||||
|
void handleConnectionFailed(const CEvent&, void*);
|
||||||
|
void handleConnectTimeout(const CEvent&, void*);
|
||||||
|
void handleOutputError(const CEvent&, void*);
|
||||||
|
void handleDisconnected(const CEvent&, void*);
|
||||||
|
void handleHandshakeComplete(const CEvent&, void*);
|
||||||
|
void handleShapeChanged(const CEvent&, void*);
|
||||||
|
void handleClipboardGrabbed(const CEvent&, void*);
|
||||||
|
void handleClipboardChanged(const CEvent&, void*);
|
||||||
|
void handleHello(const CEvent&, void*);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CMutex m_mutex;
|
CString m_name;
|
||||||
CString m_name;
|
CNetworkAddress m_serverAddress;
|
||||||
CScreen* m_screen;
|
ISocketFactory* m_socketFactory;
|
||||||
IScreenReceiver* m_server;
|
|
||||||
CNetworkAddress m_serverAddress;
|
|
||||||
IScreenFactory* m_screenFactory;
|
|
||||||
ISocketFactory* m_socketFactory;
|
|
||||||
IStreamFilterFactory* m_streamFilterFactory;
|
IStreamFilterFactory* m_streamFilterFactory;
|
||||||
CThread* m_session;
|
CScreen* m_screen;
|
||||||
bool m_active;
|
IStream* m_stream;
|
||||||
bool m_rejected;
|
CEventQueueTimer* m_timer;
|
||||||
|
CServerProxy* m_server;
|
||||||
|
bool m_ready;
|
||||||
|
bool m_active;
|
||||||
bool m_ownClipboard[kClipboardEnd];
|
bool m_ownClipboard[kClipboardEnd];
|
||||||
IClipboard::Time m_timeClipboard[kClipboardEnd];
|
IClipboard::Time m_timeClipboard[kClipboardEnd];
|
||||||
CString m_dataClipboard[kClipboardEnd];
|
CString m_dataClipboard[kClipboardEnd];
|
||||||
|
|
||||||
// the status change jobs and status
|
static CEvent::Type s_connectedEvent;
|
||||||
CJobList m_statusJobs;
|
static CEvent::Type s_connectionFailedEvent;
|
||||||
EStatus m_status;
|
static CEvent::Type s_disconnectedEvent;
|
||||||
CString m_statusMessage;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -13,15 +13,15 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "CServerProxy.h"
|
#include "CServerProxy.h"
|
||||||
|
#include "CClient.h"
|
||||||
|
#include "CClipboard.h"
|
||||||
#include "CProtocolUtil.h"
|
#include "CProtocolUtil.h"
|
||||||
#include "IClient.h"
|
|
||||||
#include "OptionTypes.h"
|
#include "OptionTypes.h"
|
||||||
#include "ProtocolTypes.h"
|
#include "ProtocolTypes.h"
|
||||||
#include "IInputStream.h"
|
#include "IStream.h"
|
||||||
#include "IOutputStream.h"
|
|
||||||
#include "CLock.h"
|
|
||||||
#include "CLog.h"
|
#include "CLog.h"
|
||||||
#include "CStopwatch.h"
|
#include "IEventQueue.h"
|
||||||
|
#include "TMethodEventJob.h"
|
||||||
#include "XBase.h"
|
#include "XBase.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
@ -29,293 +29,243 @@
|
||||||
// CServerProxy
|
// CServerProxy
|
||||||
//
|
//
|
||||||
|
|
||||||
CServerProxy::CServerProxy(IClient* client,
|
CEvent::Type CServerProxy::s_handshakeCompleteEvent =
|
||||||
IInputStream* adoptedInput, IOutputStream* adoptedOutput) :
|
CEvent::kUnknown;
|
||||||
|
|
||||||
|
CServerProxy::CServerProxy(CClient* client, IStream* stream) :
|
||||||
m_client(client),
|
m_client(client),
|
||||||
m_input(adoptedInput),
|
m_stream(stream),
|
||||||
m_output(adoptedOutput),
|
m_timer(NULL),
|
||||||
m_seqNum(0),
|
m_seqNum(0),
|
||||||
m_heartRate(kHeartRate)
|
m_compressMouse(false),
|
||||||
|
m_ignoreMouse(false),
|
||||||
|
m_heartRate(0.0)
|
||||||
{
|
{
|
||||||
assert(m_client != NULL);
|
assert(m_client != NULL);
|
||||||
assert(m_input != NULL);
|
assert(m_stream != NULL);
|
||||||
assert(m_output != NULL);
|
|
||||||
|
|
||||||
// initialize modifier translation table
|
// initialize modifier translation table
|
||||||
for (KeyModifierID id = 0; id < kKeyModifierIDLast; ++id)
|
for (KeyModifierID id = 0; id < kKeyModifierIDLast; ++id)
|
||||||
m_modifierTranslationTable[id] = id;
|
m_modifierTranslationTable[id] = id;
|
||||||
|
|
||||||
|
// handle data on stream
|
||||||
|
EVENTQUEUE->adoptHandler(IStream::getInputReadyEvent(),
|
||||||
|
m_stream->getEventTarget(),
|
||||||
|
new TMethodEventJob<CServerProxy>(this,
|
||||||
|
&CServerProxy::handleMessage));
|
||||||
|
|
||||||
|
// send heartbeat
|
||||||
|
installHeartBeat(kHeartRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
CServerProxy::~CServerProxy()
|
CServerProxy::~CServerProxy()
|
||||||
{
|
{
|
||||||
delete m_input;
|
installHeartBeat(-1.0);
|
||||||
delete m_output;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
CEvent::Type
|
||||||
CServerProxy::mainLoop()
|
CServerProxy::getHandshakeCompleteEvent()
|
||||||
{
|
{
|
||||||
bool failedToConnect = false;
|
return CEvent::registerTypeOnce(s_handshakeCompleteEvent,
|
||||||
try {
|
"CServerProxy::handshakeComplete");
|
||||||
// no compressed mouse motion yet
|
}
|
||||||
m_compressMouse = false;
|
|
||||||
|
|
||||||
// not ignoring mouse motions
|
void
|
||||||
m_ignoreMouse = false;
|
CServerProxy::installHeartBeat(double heartRate)
|
||||||
|
{
|
||||||
|
if (m_timer != NULL) {
|
||||||
|
EVENTQUEUE->removeHandler(CEvent::kTimer, m_timer);
|
||||||
|
EVENTQUEUE->deleteTimer(m_timer);
|
||||||
|
}
|
||||||
|
m_heartRate = heartRate;
|
||||||
|
if (m_heartRate > 0.0) {
|
||||||
|
m_timer = EVENTQUEUE->newTimer(m_heartRate, NULL);
|
||||||
|
EVENTQUEUE->adoptHandler(CEvent::kTimer, m_timer,
|
||||||
|
new TMethodEventJob<CServerProxy>(this,
|
||||||
|
&CServerProxy::handleHeartBeat));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// reset sequence number
|
void
|
||||||
m_seqNum = 0;
|
CServerProxy::handleMessage(const CEvent&, void*)
|
||||||
|
{
|
||||||
|
while (m_stream->isReady()) {
|
||||||
|
// read next code
|
||||||
|
UInt8 code[4];
|
||||||
|
UInt32 n = m_stream->read(code, sizeof(code));
|
||||||
|
if (n == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (n != 4) {
|
||||||
|
// client sent an incomplete message
|
||||||
|
LOG((CLOG_ERR "incomplete message from server"));
|
||||||
|
m_client->disconnect("incomplete message from server");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// handle messages from server
|
// parse message
|
||||||
CStopwatch heartbeat;
|
LOG((CLOG_DEBUG2 "msg from server: %c%c%c%c", code[0], code[1], code[2], code[3]));
|
||||||
for (;;) {
|
if (memcmp(code, kMsgDMouseMove, 4) == 0) {
|
||||||
// if no input is pending then flush compressed mouse motion
|
mouseMove();
|
||||||
if (getInputStream()->getSize() == 0) {
|
}
|
||||||
flushCompressedMouse();
|
|
||||||
}
|
|
||||||
|
|
||||||
// wait for a message
|
else if (memcmp(code, kMsgDMouseWheel, 4) == 0) {
|
||||||
LOG((CLOG_DEBUG2 "waiting for message"));
|
mouseWheel();
|
||||||
UInt8 code[4];
|
}
|
||||||
UInt32 n = getInputStream()->read(code, 4, m_heartRate);
|
|
||||||
|
|
||||||
// check if server hungup
|
else if (memcmp(code, kMsgDKeyDown, 4) == 0) {
|
||||||
if (n == 0) {
|
keyDown();
|
||||||
LOG((CLOG_NOTE "server disconnected"));
|
}
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check for time out
|
else if (memcmp(code, kMsgDKeyUp, 4) == 0) {
|
||||||
if (n == (UInt32)-1 ||
|
keyUp();
|
||||||
(m_heartRate >= 0.0 && heartbeat.getTime() > m_heartRate)) {
|
}
|
||||||
// send heartbeat
|
|
||||||
CLock lock(&m_mutex);
|
|
||||||
CProtocolUtil::writef(getOutputStream(), kMsgCNoop);
|
|
||||||
heartbeat.reset();
|
|
||||||
if (n == (UInt32)-1) {
|
|
||||||
// no message to process
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// verify we got an entire code
|
else if (memcmp(code, kMsgDMouseDown, 4) == 0) {
|
||||||
if (n != 4) {
|
mouseDown();
|
||||||
// client sent an incomplete message
|
}
|
||||||
LOG((CLOG_ERR "incomplete message from server"));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse message
|
else if (memcmp(code, kMsgDMouseUp, 4) == 0) {
|
||||||
LOG((CLOG_DEBUG2 "msg from server: %c%c%c%c", code[0], code[1], code[2], code[3]));
|
mouseUp();
|
||||||
if (memcmp(code, kMsgDMouseMove, 4) == 0) {
|
}
|
||||||
mouseMove();
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (memcmp(code, kMsgDMouseWheel, 4) == 0) {
|
else if (memcmp(code, kMsgDKeyRepeat, 4) == 0) {
|
||||||
mouseWheel();
|
keyRepeat();
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (memcmp(code, kMsgDKeyDown, 4) == 0) {
|
else if (memcmp(code, kMsgCNoop, 4) == 0) {
|
||||||
keyDown();
|
// accept and discard no-op
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (memcmp(code, kMsgDKeyUp, 4) == 0) {
|
else if (memcmp(code, kMsgCEnter, 4) == 0) {
|
||||||
keyUp();
|
enter();
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (memcmp(code, kMsgDMouseDown, 4) == 0) {
|
else if (memcmp(code, kMsgCLeave, 4) == 0) {
|
||||||
mouseDown();
|
leave();
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (memcmp(code, kMsgDMouseUp, 4) == 0) {
|
else if (memcmp(code, kMsgCClipboard, 4) == 0) {
|
||||||
mouseUp();
|
grabClipboard();
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (memcmp(code, kMsgDKeyRepeat, 4) == 0) {
|
else if (memcmp(code, kMsgCScreenSaver, 4) == 0) {
|
||||||
keyRepeat();
|
screensaver();
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (memcmp(code, kMsgCNoop, 4) == 0) {
|
else if (memcmp(code, kMsgQInfo, 4) == 0) {
|
||||||
// accept and discard no-op
|
queryInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (memcmp(code, kMsgCEnter, 4) == 0) {
|
else if (memcmp(code, kMsgCInfoAck, 4) == 0) {
|
||||||
enter();
|
infoAcknowledgment();
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (memcmp(code, kMsgCLeave, 4) == 0) {
|
else if (memcmp(code, kMsgDClipboard, 4) == 0) {
|
||||||
leave();
|
setClipboard();
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (memcmp(code, kMsgCClipboard, 4) == 0) {
|
else if (memcmp(code, kMsgCResetOptions, 4) == 0) {
|
||||||
grabClipboard();
|
resetOptions();
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (memcmp(code, kMsgCScreenSaver, 4) == 0) {
|
else if (memcmp(code, kMsgDSetOptions, 4) == 0) {
|
||||||
screensaver();
|
setOptions();
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (memcmp(code, kMsgQInfo, 4) == 0) {
|
else if (memcmp(code, kMsgCClose, 4) == 0) {
|
||||||
queryInfo();
|
// server wants us to hangup
|
||||||
}
|
LOG((CLOG_DEBUG1 "recv close"));
|
||||||
|
m_client->disconnect(NULL);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
else if (memcmp(code, kMsgCInfoAck, 4) == 0) {
|
else if (memcmp(code, kMsgEIncompatible, 4) == 0) {
|
||||||
infoAcknowledgment();
|
SInt32 major, minor;
|
||||||
}
|
CProtocolUtil::readf(m_stream,
|
||||||
|
kMsgEIncompatible + 4, &major, &minor);
|
||||||
|
LOG((CLOG_ERR "server has incompatible version %d.%d", major, minor));
|
||||||
|
m_client->disconnect("server has incompatible version");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
else if (memcmp(code, kMsgDClipboard, 4) == 0) {
|
else if (memcmp(code, kMsgEBusy, 4) == 0) {
|
||||||
setClipboard();
|
LOG((CLOG_ERR "server already has a connected client with name \"%s\"", m_client->getName().c_str()));
|
||||||
}
|
m_client->disconnect("server already has a connected client with our name");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
else if (memcmp(code, kMsgCResetOptions, 4) == 0) {
|
else if (memcmp(code, kMsgEUnknown, 4) == 0) {
|
||||||
resetOptions();
|
LOG((CLOG_ERR "server refused client with name \"%s\"", m_client->getName().c_str()));
|
||||||
}
|
m_client->disconnect("server refused client with our name");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
else if (memcmp(code, kMsgDSetOptions, 4) == 0) {
|
else if (memcmp(code, kMsgEBad, 4) == 0) {
|
||||||
setOptions();
|
LOG((CLOG_ERR "server disconnected due to a protocol error"));
|
||||||
}
|
m_client->disconnect("server reported a protocol error");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
else if (memcmp(code, kMsgCClose, 4) == 0) {
|
else {
|
||||||
// server wants us to hangup
|
// unknown message
|
||||||
LOG((CLOG_DEBUG1 "recv close"));
|
LOG((CLOG_ERR "unknown message: %d %d %d %d [%c%c%c%c]", code[0], code[1], code[2], code[3], code[0], code[1], code[2], code[3]));
|
||||||
break;
|
m_client->disconnect("unknown message from server");
|
||||||
}
|
return;
|
||||||
|
|
||||||
else if (memcmp(code, kMsgEIncompatible, 4) == 0) {
|
|
||||||
SInt32 major, minor;
|
|
||||||
CProtocolUtil::readf(getInputStream(),
|
|
||||||
kMsgEIncompatible + 4, &major, &minor);
|
|
||||||
LOG((CLOG_ERR "server has incompatible version %d.%d", major, minor));
|
|
||||||
failedToConnect = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (memcmp(code, kMsgEBusy, 4) == 0) {
|
|
||||||
LOG((CLOG_ERR "server already has a connected client with name \"%s\"", getName().c_str()));
|
|
||||||
failedToConnect = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (memcmp(code, kMsgEUnknown, 4) == 0) {
|
|
||||||
LOG((CLOG_ERR "server refused client with name \"%s\"", getName().c_str()));
|
|
||||||
failedToConnect = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (memcmp(code, kMsgEBad, 4) == 0) {
|
|
||||||
LOG((CLOG_ERR "server disconnected due to a protocol error"));
|
|
||||||
failedToConnect = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
else {
|
|
||||||
// unknown message
|
|
||||||
LOG((CLOG_ERR "unknown message from server"));
|
|
||||||
LOG((CLOG_ERR "unknown message: %d %d %d %d [%c%c%c%c]", code[0], code[1], code[2], code[3], code[0], code[1], code[2], code[3]));
|
|
||||||
failedToConnect = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (XBase& e) {
|
flushCompressedMouse();
|
||||||
LOG((CLOG_ERR "error: %s", e.what()));
|
|
||||||
}
|
|
||||||
catch (...) {
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
|
|
||||||
return !failedToConnect;
|
|
||||||
}
|
|
||||||
|
|
||||||
IClient*
|
|
||||||
CServerProxy::getClient() const
|
|
||||||
{
|
|
||||||
return m_client;
|
|
||||||
}
|
|
||||||
|
|
||||||
CString
|
|
||||||
CServerProxy::getName() const
|
|
||||||
{
|
|
||||||
return m_client->getName();
|
|
||||||
}
|
|
||||||
|
|
||||||
IInputStream*
|
|
||||||
CServerProxy::getInputStream() const
|
|
||||||
{
|
|
||||||
return m_input;
|
|
||||||
}
|
|
||||||
|
|
||||||
IOutputStream*
|
|
||||||
CServerProxy::getOutputStream() const
|
|
||||||
{
|
|
||||||
return m_output;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CServerProxy::onError()
|
CServerProxy::handleHeartBeat(const CEvent&, void*)
|
||||||
{
|
{
|
||||||
// ignore
|
CProtocolUtil::writef(m_stream, kMsgCNoop);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CServerProxy::onInfoChanged(const CClientInfo& info)
|
CServerProxy::onInfoChanged()
|
||||||
{
|
{
|
||||||
// ignore mouse motion until we receive acknowledgment of our info
|
// ignore mouse motion until we receive acknowledgment of our info
|
||||||
// change message.
|
// change message.
|
||||||
CLock lock(&m_mutex);
|
|
||||||
m_ignoreMouse = true;
|
m_ignoreMouse = true;
|
||||||
|
|
||||||
// send info update
|
// send info update
|
||||||
sendInfo(info);
|
queryInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CServerProxy::onGrabClipboard(ClipboardID id)
|
CServerProxy::onGrabClipboard(ClipboardID id)
|
||||||
{
|
{
|
||||||
LOG((CLOG_DEBUG1 "sending clipboard %d changed", id));
|
LOG((CLOG_DEBUG1 "sending clipboard %d changed", id));
|
||||||
CLock lock(&m_mutex);
|
CProtocolUtil::writef(m_stream, kMsgCClipboard, id, m_seqNum);
|
||||||
CProtocolUtil::writef(getOutputStream(), kMsgCClipboard, id, m_seqNum);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CServerProxy::onClipboardChanged(ClipboardID id, const CString& data)
|
CServerProxy::onClipboardChanged(ClipboardID id, const IClipboard* clipboard)
|
||||||
{
|
{
|
||||||
CLock lock(&m_mutex);
|
CString data = IClipboard::marshall(clipboard);
|
||||||
LOG((CLOG_DEBUG1 "sending clipboard %d seqnum=%d, size=%d", id, m_seqNum, data.size()));
|
LOG((CLOG_DEBUG1 "sending clipboard %d seqnum=%d, size=%d", id, m_seqNum, data.size()));
|
||||||
CProtocolUtil::writef(getOutputStream(), kMsgDClipboard, id, m_seqNum, &data);
|
CProtocolUtil::writef(m_stream, kMsgDClipboard, id, m_seqNum, &data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CServerProxy::flushCompressedMouse()
|
CServerProxy::flushCompressedMouse()
|
||||||
{
|
{
|
||||||
bool send = false;
|
if (m_compressMouse) {
|
||||||
SInt32 x = 0, y = 0;
|
m_compressMouse = false;
|
||||||
{
|
m_client->mouseMove(m_xMouse, m_yMouse);
|
||||||
CLock lock(&m_mutex);
|
|
||||||
if (m_compressMouse) {
|
|
||||||
m_compressMouse = false;
|
|
||||||
x = m_xMouse;
|
|
||||||
y = m_yMouse;
|
|
||||||
send = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (send) {
|
|
||||||
getClient()->mouseMove(x, y);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CServerProxy::sendInfo(const CClientInfo& info)
|
CServerProxy::sendInfo(const CClientInfo& info)
|
||||||
{
|
{
|
||||||
// note -- m_mutex should be locked on entry
|
LOG((CLOG_DEBUG1 "sending info shape=%d,%d %dx%d", info.m_x, info.m_y, info.m_w, info.m_h));
|
||||||
LOG((CLOG_DEBUG1 "sending info shape=%d,%d %dx%d zone=%d pos=%d,%d", info.m_x, info.m_y, info.m_w, info.m_h, info.m_zoneSize, info.m_mx, info.m_my));
|
CProtocolUtil::writef(m_stream, kMsgDInfo,
|
||||||
CProtocolUtil::writef(getOutputStream(), kMsgDInfo,
|
|
||||||
info.m_x, info.m_y,
|
info.m_x, info.m_y,
|
||||||
info.m_w, info.m_h,
|
info.m_w, info.m_h, 0, 0, 0);
|
||||||
info.m_zoneSize,
|
|
||||||
info.m_mx, info.m_my);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
KeyID
|
KeyID
|
||||||
|
@ -434,19 +384,15 @@ CServerProxy::enter()
|
||||||
SInt16 x, y;
|
SInt16 x, y;
|
||||||
UInt16 mask;
|
UInt16 mask;
|
||||||
UInt32 seqNum;
|
UInt32 seqNum;
|
||||||
CProtocolUtil::readf(getInputStream(),
|
CProtocolUtil::readf(m_stream, kMsgCEnter + 4, &x, &y, &seqNum, &mask);
|
||||||
kMsgCEnter + 4, &x, &y, &seqNum, &mask);
|
|
||||||
LOG((CLOG_DEBUG1 "recv enter, %d,%d %d %04x", x, y, seqNum, mask));
|
LOG((CLOG_DEBUG1 "recv enter, %d,%d %d %04x", x, y, seqNum, mask));
|
||||||
|
|
||||||
// discard old compressed mouse motion, if any
|
// discard old compressed mouse motion, if any
|
||||||
{
|
m_compressMouse = false;
|
||||||
CLock lock(&m_mutex);
|
m_seqNum = seqNum;
|
||||||
m_compressMouse = false;
|
|
||||||
m_seqNum = seqNum;
|
|
||||||
}
|
|
||||||
|
|
||||||
// forward
|
// forward
|
||||||
getClient()->enter(x, y, seqNum, static_cast<KeyModifierMask>(mask), false);
|
m_client->enter(x, y, seqNum, static_cast<KeyModifierMask>(mask), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -459,7 +405,7 @@ CServerProxy::leave()
|
||||||
flushCompressedMouse();
|
flushCompressedMouse();
|
||||||
|
|
||||||
// forward
|
// forward
|
||||||
getClient()->leave();
|
m_client->leave();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -469,8 +415,7 @@ CServerProxy::setClipboard()
|
||||||
ClipboardID id;
|
ClipboardID id;
|
||||||
UInt32 seqNum;
|
UInt32 seqNum;
|
||||||
CString data;
|
CString data;
|
||||||
CProtocolUtil::readf(getInputStream(),
|
CProtocolUtil::readf(m_stream, kMsgDClipboard + 4, &id, &seqNum, &data);
|
||||||
kMsgDClipboard + 4, &id, &seqNum, &data);
|
|
||||||
LOG((CLOG_DEBUG "recv clipboard %d size=%d", id, data.size()));
|
LOG((CLOG_DEBUG "recv clipboard %d size=%d", id, data.size()));
|
||||||
|
|
||||||
// validate
|
// validate
|
||||||
|
@ -479,7 +424,9 @@ CServerProxy::setClipboard()
|
||||||
}
|
}
|
||||||
|
|
||||||
// forward
|
// forward
|
||||||
getClient()->setClipboard(id, data);
|
CClipboard clipboard;
|
||||||
|
clipboard.unmarshall(data, 0);
|
||||||
|
m_client->setClipboard(id, &clipboard);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -488,7 +435,7 @@ CServerProxy::grabClipboard()
|
||||||
// parse
|
// parse
|
||||||
ClipboardID id;
|
ClipboardID id;
|
||||||
UInt32 seqNum;
|
UInt32 seqNum;
|
||||||
CProtocolUtil::readf(getInputStream(), kMsgCClipboard + 4, &id, &seqNum);
|
CProtocolUtil::readf(m_stream, kMsgCClipboard + 4, &id, &seqNum);
|
||||||
LOG((CLOG_DEBUG "recv grab clipboard %d", id));
|
LOG((CLOG_DEBUG "recv grab clipboard %d", id));
|
||||||
|
|
||||||
// validate
|
// validate
|
||||||
|
@ -497,7 +444,7 @@ CServerProxy::grabClipboard()
|
||||||
}
|
}
|
||||||
|
|
||||||
// forward
|
// forward
|
||||||
getClient()->grabClipboard(id);
|
m_client->grabClipboard(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -508,8 +455,7 @@ CServerProxy::keyDown()
|
||||||
|
|
||||||
// parse
|
// parse
|
||||||
UInt16 id, mask, button;
|
UInt16 id, mask, button;
|
||||||
CProtocolUtil::readf(getInputStream(), kMsgDKeyDown + 4,
|
CProtocolUtil::readf(m_stream, kMsgDKeyDown + 4, &id, &mask, &button);
|
||||||
&id, &mask, &button);
|
|
||||||
LOG((CLOG_DEBUG1 "recv key down id=%d, mask=0x%04x, button=0x%04x", id, mask, button));
|
LOG((CLOG_DEBUG1 "recv key down id=%d, mask=0x%04x, button=0x%04x", id, mask, button));
|
||||||
|
|
||||||
// translate
|
// translate
|
||||||
|
@ -521,7 +467,7 @@ CServerProxy::keyDown()
|
||||||
LOG((CLOG_DEBUG1 "key down translated to id=%d, mask=0x%04x", id2, mask2));
|
LOG((CLOG_DEBUG1 "key down translated to id=%d, mask=0x%04x", id2, mask2));
|
||||||
|
|
||||||
// forward
|
// forward
|
||||||
getClient()->keyDown(id2, mask2, button);
|
m_client->keyDown(id2, mask2, button);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -532,7 +478,7 @@ CServerProxy::keyRepeat()
|
||||||
|
|
||||||
// parse
|
// parse
|
||||||
UInt16 id, mask, count, button;
|
UInt16 id, mask, count, button;
|
||||||
CProtocolUtil::readf(getInputStream(), kMsgDKeyRepeat + 4,
|
CProtocolUtil::readf(m_stream, kMsgDKeyRepeat + 4,
|
||||||
&id, &mask, &count, &button);
|
&id, &mask, &count, &button);
|
||||||
LOG((CLOG_DEBUG1 "recv key repeat id=%d, mask=0x%04x, count=%d, button=0x%04x", id, mask, count, button));
|
LOG((CLOG_DEBUG1 "recv key repeat id=%d, mask=0x%04x, count=%d, button=0x%04x", id, mask, count, button));
|
||||||
|
|
||||||
|
@ -545,7 +491,7 @@ CServerProxy::keyRepeat()
|
||||||
LOG((CLOG_DEBUG1 "key repeat translated to id=%d, mask=0x%04x", id2, mask2));
|
LOG((CLOG_DEBUG1 "key repeat translated to id=%d, mask=0x%04x", id2, mask2));
|
||||||
|
|
||||||
// forward
|
// forward
|
||||||
getClient()->keyRepeat(id2, mask2, count, button);
|
m_client->keyRepeat(id2, mask2, count, button);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -556,7 +502,7 @@ CServerProxy::keyUp()
|
||||||
|
|
||||||
// parse
|
// parse
|
||||||
UInt16 id, mask, button;
|
UInt16 id, mask, button;
|
||||||
CProtocolUtil::readf(getInputStream(), kMsgDKeyUp + 4, &id, &mask, &button);
|
CProtocolUtil::readf(m_stream, kMsgDKeyUp + 4, &id, &mask, &button);
|
||||||
LOG((CLOG_DEBUG1 "recv key up id=%d, mask=0x%04x, button=0x%04x", id, mask, button));
|
LOG((CLOG_DEBUG1 "recv key up id=%d, mask=0x%04x, button=0x%04x", id, mask, button));
|
||||||
|
|
||||||
// translate
|
// translate
|
||||||
|
@ -568,7 +514,7 @@ CServerProxy::keyUp()
|
||||||
LOG((CLOG_DEBUG1 "key up translated to id=%d, mask=0x%04x", id2, mask2));
|
LOG((CLOG_DEBUG1 "key up translated to id=%d, mask=0x%04x", id2, mask2));
|
||||||
|
|
||||||
// forward
|
// forward
|
||||||
getClient()->keyUp(id2, mask2, button);
|
m_client->keyUp(id2, mask2, button);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -579,11 +525,11 @@ CServerProxy::mouseDown()
|
||||||
|
|
||||||
// parse
|
// parse
|
||||||
SInt8 id;
|
SInt8 id;
|
||||||
CProtocolUtil::readf(getInputStream(), kMsgDMouseDown + 4, &id);
|
CProtocolUtil::readf(m_stream, kMsgDMouseDown + 4, &id);
|
||||||
LOG((CLOG_DEBUG1 "recv mouse down id=%d", id));
|
LOG((CLOG_DEBUG1 "recv mouse down id=%d", id));
|
||||||
|
|
||||||
// forward
|
// forward
|
||||||
getClient()->mouseDown(static_cast<ButtonID>(id));
|
m_client->mouseDown(static_cast<ButtonID>(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -594,11 +540,11 @@ CServerProxy::mouseUp()
|
||||||
|
|
||||||
// parse
|
// parse
|
||||||
SInt8 id;
|
SInt8 id;
|
||||||
CProtocolUtil::readf(getInputStream(), kMsgDMouseUp + 4, &id);
|
CProtocolUtil::readf(m_stream, kMsgDMouseUp + 4, &id);
|
||||||
LOG((CLOG_DEBUG1 "recv mouse up id=%d", id));
|
LOG((CLOG_DEBUG1 "recv mouse up id=%d", id));
|
||||||
|
|
||||||
// forward
|
// forward
|
||||||
getClient()->mouseUp(static_cast<ButtonID>(id));
|
m_client->mouseUp(static_cast<ButtonID>(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -607,30 +553,27 @@ CServerProxy::mouseMove()
|
||||||
// parse
|
// parse
|
||||||
bool ignore;
|
bool ignore;
|
||||||
SInt16 x, y;
|
SInt16 x, y;
|
||||||
CProtocolUtil::readf(getInputStream(), kMsgDMouseMove + 4, &x, &y);
|
CProtocolUtil::readf(m_stream, kMsgDMouseMove + 4, &x, &y);
|
||||||
|
|
||||||
{
|
// note if we should ignore the move
|
||||||
// note if we should ignore the move
|
ignore = m_ignoreMouse;
|
||||||
CLock lock(&m_mutex);
|
|
||||||
ignore = m_ignoreMouse;
|
|
||||||
|
|
||||||
// compress mouse motion events if more input follows
|
// compress mouse motion events if more input follows
|
||||||
if (!ignore && !m_compressMouse && getInputStream()->getSize() > 0) {
|
if (!ignore && !m_compressMouse && m_stream->isReady()) {
|
||||||
m_compressMouse = true;
|
m_compressMouse = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if compressing then ignore the motion but record it
|
// if compressing then ignore the motion but record it
|
||||||
if (m_compressMouse) {
|
if (m_compressMouse) {
|
||||||
ignore = true;
|
ignore = true;
|
||||||
m_xMouse = x;
|
m_xMouse = x;
|
||||||
m_yMouse = y;
|
m_yMouse = y;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
LOG((CLOG_DEBUG2 "recv mouse move %d,%d", x, y));
|
LOG((CLOG_DEBUG2 "recv mouse move %d,%d", x, y));
|
||||||
|
|
||||||
// forward
|
// forward
|
||||||
if (!ignore) {
|
if (!ignore) {
|
||||||
getClient()->mouseMove(x, y);
|
m_client->mouseMove(x, y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -642,11 +585,11 @@ CServerProxy::mouseWheel()
|
||||||
|
|
||||||
// parse
|
// parse
|
||||||
SInt16 delta;
|
SInt16 delta;
|
||||||
CProtocolUtil::readf(getInputStream(), kMsgDMouseWheel + 4, &delta);
|
CProtocolUtil::readf(m_stream, kMsgDMouseWheel + 4, &delta);
|
||||||
LOG((CLOG_DEBUG2 "recv mouse wheel %+d", delta));
|
LOG((CLOG_DEBUG2 "recv mouse wheel %+d", delta));
|
||||||
|
|
||||||
// forward
|
// forward
|
||||||
getClient()->mouseWheel(delta);
|
m_client->mouseWheel(delta);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -654,11 +597,11 @@ CServerProxy::screensaver()
|
||||||
{
|
{
|
||||||
// parse
|
// parse
|
||||||
SInt8 on;
|
SInt8 on;
|
||||||
CProtocolUtil::readf(getInputStream(), kMsgCScreenSaver + 4, &on);
|
CProtocolUtil::readf(m_stream, kMsgCScreenSaver + 4, &on);
|
||||||
LOG((CLOG_DEBUG1 "recv screen saver on=%d", on));
|
LOG((CLOG_DEBUG1 "recv screen saver on=%d", on));
|
||||||
|
|
||||||
// forward
|
// forward
|
||||||
getClient()->screensaver(on != 0);
|
m_client->screensaver(on != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -668,22 +611,18 @@ CServerProxy::resetOptions()
|
||||||
LOG((CLOG_DEBUG1 "recv reset options"));
|
LOG((CLOG_DEBUG1 "recv reset options"));
|
||||||
|
|
||||||
// forward
|
// forward
|
||||||
getClient()->resetOptions();
|
m_client->resetOptions();
|
||||||
|
|
||||||
CLock lock(&m_mutex);
|
// reset heart rate and send heartbeat if necessary
|
||||||
|
installHeartBeat(kHeartRate);
|
||||||
// reset heart rate
|
if (m_heartRate >= 0.0) {
|
||||||
m_heartRate = kHeartRate;
|
CProtocolUtil::writef(m_stream, kMsgCNoop);
|
||||||
|
}
|
||||||
|
|
||||||
// reset modifier translation table
|
// reset modifier translation table
|
||||||
for (KeyModifierID id = 0; id < kKeyModifierIDLast; ++id) {
|
for (KeyModifierID id = 0; id < kKeyModifierIDLast; ++id) {
|
||||||
m_modifierTranslationTable[id] = id;
|
m_modifierTranslationTable[id] = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
// send heartbeat if necessary
|
|
||||||
if (m_heartRate >= 0.0) {
|
|
||||||
CProtocolUtil::writef(getOutputStream(), kMsgCNoop);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -691,13 +630,11 @@ CServerProxy::setOptions()
|
||||||
{
|
{
|
||||||
// parse
|
// parse
|
||||||
COptionsList options;
|
COptionsList options;
|
||||||
CProtocolUtil::readf(getInputStream(), kMsgDSetOptions + 4, &options);
|
CProtocolUtil::readf(m_stream, kMsgDSetOptions + 4, &options);
|
||||||
LOG((CLOG_DEBUG1 "recv set options size=%d", options.size()));
|
LOG((CLOG_DEBUG1 "recv set options size=%d", options.size()));
|
||||||
|
|
||||||
// forward
|
// forward
|
||||||
getClient()->setOptions(options);
|
m_client->setOptions(options);
|
||||||
|
|
||||||
CLock lock(&m_mutex);
|
|
||||||
|
|
||||||
// update modifier table
|
// update modifier table
|
||||||
for (UInt32 i = 0, n = options.size(); i < n; i += 2) {
|
for (UInt32 i = 0, n = options.size(); i < n; i += 2) {
|
||||||
|
@ -718,12 +655,10 @@ CServerProxy::setOptions()
|
||||||
id = kKeyModifierIDSuper;
|
id = kKeyModifierIDSuper;
|
||||||
}
|
}
|
||||||
else if (options[i] == kOptionHeartbeat) {
|
else if (options[i] == kOptionHeartbeat) {
|
||||||
// update heart rate
|
// update heart rate and send heartbeat if necessary
|
||||||
m_heartRate = 1.0e-3 * static_cast<double>(options[i + 1]);
|
installHeartBeat(1.0e-3 * static_cast<double>(options[i + 1]));
|
||||||
|
|
||||||
// send heartbeat if necessary
|
|
||||||
if (m_heartRate >= 0.0) {
|
if (m_heartRate >= 0.0) {
|
||||||
CProtocolUtil::writef(getOutputStream(), kMsgCNoop);
|
CProtocolUtil::writef(m_stream, kMsgCNoop);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (id != kKeyModifierIDNull) {
|
if (id != kKeyModifierIDNull) {
|
||||||
|
@ -737,24 +672,14 @@ CServerProxy::setOptions()
|
||||||
void
|
void
|
||||||
CServerProxy::queryInfo()
|
CServerProxy::queryInfo()
|
||||||
{
|
{
|
||||||
// get current info
|
|
||||||
CClientInfo info;
|
CClientInfo info;
|
||||||
getClient()->getShape(info.m_x, info.m_y, info.m_w, info.m_h);
|
m_client->getShape(info.m_x, info.m_y, info.m_w, info.m_h);
|
||||||
getClient()->getCursorPos(info.m_mx, info.m_my);
|
|
||||||
info.m_zoneSize = getClient()->getJumpZoneSize();
|
|
||||||
|
|
||||||
// send it
|
|
||||||
CLock lock(&m_mutex);
|
|
||||||
sendInfo(info);
|
sendInfo(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CServerProxy::infoAcknowledgment()
|
CServerProxy::infoAcknowledgment()
|
||||||
{
|
{
|
||||||
// parse
|
|
||||||
LOG((CLOG_DEBUG1 "recv info acknowledgment"));
|
LOG((CLOG_DEBUG1 "recv info acknowledgment"));
|
||||||
|
|
||||||
// now allow mouse motion
|
|
||||||
CLock lock(&m_mutex);
|
|
||||||
m_ignoreMouse = false;
|
m_ignoreMouse = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,88 +15,66 @@
|
||||||
#ifndef CSERVERPROXY_H
|
#ifndef CSERVERPROXY_H
|
||||||
#define CSERVERPROXY_H
|
#define CSERVERPROXY_H
|
||||||
|
|
||||||
#include "IScreenReceiver.h"
|
#include "ClipboardTypes.h"
|
||||||
#include "KeyTypes.h"
|
#include "KeyTypes.h"
|
||||||
#include "CMutex.h"
|
#include "CEvent.h"
|
||||||
|
|
||||||
class IClient;
|
class CClient;
|
||||||
class IInputStream;
|
class CClientInfo;
|
||||||
class IOutputStream;
|
class CEventQueueTimer;
|
||||||
|
class IClipboard;
|
||||||
|
class IStream;
|
||||||
|
|
||||||
//! Proxy for server
|
//! Proxy for server
|
||||||
/*!
|
/*!
|
||||||
This class acts a proxy for the server, converting calls into messages
|
This class acts a proxy for the server, converting calls into messages
|
||||||
to the server and messages from the server to calls on the client.
|
to the server and messages from the server to calls on the client.
|
||||||
*/
|
*/
|
||||||
class CServerProxy : public IScreenReceiver {
|
class CServerProxy {
|
||||||
public:
|
public:
|
||||||
/*! \c adoptedInput is the stream from the server and
|
/*!
|
||||||
\c adoptedOutput is the stream to the server. This object
|
Process messages from the server on \p stream and forward to
|
||||||
takes ownership of both and destroys them in the d'tor.
|
\p client.
|
||||||
Messages from the server are converted to calls on \c client.
|
|
||||||
*/
|
*/
|
||||||
CServerProxy(IClient* client,
|
CServerProxy(CClient* client, IStream* stream);
|
||||||
IInputStream* adoptedInput,
|
|
||||||
IOutputStream* adoptedOutput);
|
|
||||||
~CServerProxy();
|
~CServerProxy();
|
||||||
|
|
||||||
//! @name manipulators
|
//! @name manipulators
|
||||||
//@{
|
//@{
|
||||||
|
|
||||||
//! Run event loop
|
virtual void onInfoChanged();
|
||||||
/*!
|
virtual bool onGrabClipboard(ClipboardID);
|
||||||
Run the event loop and return when the server disconnects or
|
virtual void onClipboardChanged(ClipboardID, const IClipboard*);
|
||||||
requests the client to disconnect. Return true iff the server
|
|
||||||
didn't reject our connection.
|
|
||||||
|
|
||||||
(cancellation point)
|
|
||||||
*/
|
|
||||||
bool mainLoop();
|
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
//! @name accessors
|
//! @name accessors
|
||||||
//@{
|
//@{
|
||||||
|
|
||||||
//! Get client
|
//! Get handshake complete event type
|
||||||
/*!
|
/*!
|
||||||
Returns the client passed to the c'tor.
|
Returns the handshake complete event type. This is sent when the
|
||||||
|
client has completed the handshake with the server.
|
||||||
*/
|
*/
|
||||||
IClient* getClient() const;
|
static CEvent::Type getHandshakeCompleteEvent();
|
||||||
|
|
||||||
//! Get input stream
|
|
||||||
/*!
|
|
||||||
Return the input stream passed to the c'tor.
|
|
||||||
*/
|
|
||||||
IInputStream* getInputStream() const;
|
|
||||||
|
|
||||||
//! Get output stream
|
|
||||||
/*!
|
|
||||||
Return the output stream passed to the c'tor.
|
|
||||||
*/
|
|
||||||
IOutputStream* getOutputStream() const;
|
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
// IScreenReceiver overrides
|
|
||||||
virtual void onError();
|
|
||||||
virtual void onInfoChanged(const CClientInfo&);
|
|
||||||
virtual bool onGrabClipboard(ClipboardID);
|
|
||||||
virtual void onClipboardChanged(ClipboardID, const CString& data);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
// get the client name (from the client)
|
|
||||||
CString getName() const;
|
|
||||||
|
|
||||||
// if compressing mouse motion then send the last motion now
|
// if compressing mouse motion then send the last motion now
|
||||||
void flushCompressedMouse();
|
void flushCompressedMouse();
|
||||||
|
|
||||||
void sendInfo(const CClientInfo&);
|
void sendInfo(const CClientInfo&);
|
||||||
|
|
||||||
|
void installHeartBeat(double);
|
||||||
|
|
||||||
// modifier key translation
|
// modifier key translation
|
||||||
KeyID translateKey(KeyID) const;
|
KeyID translateKey(KeyID) const;
|
||||||
KeyModifierMask translateModifierMask(KeyModifierMask) const;
|
KeyModifierMask translateModifierMask(KeyModifierMask) const;
|
||||||
|
|
||||||
|
// event handlers
|
||||||
|
void handleMessage(const CEvent&, void*);
|
||||||
|
void handleHeartBeat(const CEvent&, void*);
|
||||||
|
|
||||||
// message handlers
|
// message handlers
|
||||||
void enter();
|
void enter();
|
||||||
void leave();
|
void leave();
|
||||||
|
@ -116,11 +94,9 @@ private:
|
||||||
void infoAcknowledgment();
|
void infoAcknowledgment();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CMutex m_mutex;
|
CClient* m_client;
|
||||||
|
IStream* m_stream;
|
||||||
IClient* m_client;
|
CEventQueueTimer* m_timer;
|
||||||
IInputStream* m_input;
|
|
||||||
IOutputStream* m_output;
|
|
||||||
|
|
||||||
UInt32 m_seqNum;
|
UInt32 m_seqNum;
|
||||||
|
|
||||||
|
@ -131,6 +107,8 @@ private:
|
||||||
|
|
||||||
KeyModifierID m_modifierTranslationTable[kKeyModifierIDLast];
|
KeyModifierID m_modifierTranslationTable[kKeyModifierIDLast];
|
||||||
double m_heartRate;
|
double m_heartRate;
|
||||||
|
|
||||||
|
static CEvent::Type s_handshakeCompleteEvent;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -77,7 +77,7 @@ CStreamFilter::setEventFilter(IEventJob* filter)
|
||||||
void*
|
void*
|
||||||
CStreamFilter::getEventTarget() const
|
CStreamFilter::getEventTarget() const
|
||||||
{
|
{
|
||||||
return const_cast<void*>(reinterpret_cast<const void*>(this));
|
return getStream()->getEventTarget();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
|
@ -113,6 +113,9 @@ CNetworkAddress::CNetworkAddress(const CString& hostname_, int port) :
|
||||||
catch (XArchNetworkNameNoAddress&) {
|
catch (XArchNetworkNameNoAddress&) {
|
||||||
throw XSocketAddress(XSocketAddress::kNoAddress, hostname, port);
|
throw XSocketAddress(XSocketAddress::kNoAddress, hostname, port);
|
||||||
}
|
}
|
||||||
|
catch (XArchNetworkNameUnsupported&) {
|
||||||
|
throw XSocketAddress(XSocketAddress::kUnsupported, hostname, port);
|
||||||
|
}
|
||||||
catch (XArchNetworkName&) {
|
catch (XArchNetworkName&) {
|
||||||
throw XSocketAddress(XSocketAddress::kUnknown, hostname, port);
|
throw XSocketAddress(XSocketAddress::kUnknown, hostname, port);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,10 +19,9 @@
|
||||||
#include "TSocketMultiplexerMethodJob.h"
|
#include "TSocketMultiplexerMethodJob.h"
|
||||||
#include "XSocket.h"
|
#include "XSocket.h"
|
||||||
#include "XIO.h"
|
#include "XIO.h"
|
||||||
#include "CEvent.h"
|
|
||||||
#include "CEventQueue.h"
|
|
||||||
#include "CLock.h"
|
#include "CLock.h"
|
||||||
#include "CMutex.h"
|
#include "CMutex.h"
|
||||||
|
#include "IEventQueue.h"
|
||||||
#include "CArch.h"
|
#include "CArch.h"
|
||||||
#include "XArch.h"
|
#include "XArch.h"
|
||||||
|
|
||||||
|
@ -125,8 +124,7 @@ CTCPListenSocket::serviceListening(ISocketMultiplexerJob* job,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (read) {
|
if (read) {
|
||||||
CEventQueue::getInstance()->addEvent(
|
EVENTQUEUE->addEvent(CEvent(getConnectingEvent(), this, NULL));
|
||||||
CEvent(getConnectingEvent(), this, NULL));
|
|
||||||
// stop polling on this socket until the client accepts
|
// stop polling on this socket until the client accepts
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,11 +18,12 @@
|
||||||
#include "TSocketMultiplexerMethodJob.h"
|
#include "TSocketMultiplexerMethodJob.h"
|
||||||
#include "XSocket.h"
|
#include "XSocket.h"
|
||||||
#include "CLock.h"
|
#include "CLock.h"
|
||||||
#include "CEventQueue.h"
|
|
||||||
#include "CLog.h"
|
#include "CLog.h"
|
||||||
|
#include "IEventQueue.h"
|
||||||
#include "IEventJob.h"
|
#include "IEventJob.h"
|
||||||
#include "CArch.h"
|
#include "CArch.h"
|
||||||
#include "XArch.h"
|
#include "XArch.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
//
|
//
|
||||||
// CTCPSocket
|
// CTCPSocket
|
||||||
|
@ -84,6 +85,9 @@ CTCPSocket::bind(const CNetworkAddress& addr)
|
||||||
void
|
void
|
||||||
CTCPSocket::close()
|
CTCPSocket::close()
|
||||||
{
|
{
|
||||||
|
// remove ourself from the multiplexer
|
||||||
|
setJob(NULL);
|
||||||
|
|
||||||
CLock lock(&m_mutex);
|
CLock lock(&m_mutex);
|
||||||
|
|
||||||
// clear buffers and enter disconnected state
|
// clear buffers and enter disconnected state
|
||||||
|
@ -92,9 +96,6 @@ CTCPSocket::close()
|
||||||
}
|
}
|
||||||
onDisconnected();
|
onDisconnected();
|
||||||
|
|
||||||
// remove ourself from the multiplexer
|
|
||||||
setJob(NULL);
|
|
||||||
|
|
||||||
// close the socket
|
// close the socket
|
||||||
if (m_socket != NULL) {
|
if (m_socket != NULL) {
|
||||||
CArchSocket socket = m_socket;
|
CArchSocket socket = m_socket;
|
||||||
|
@ -141,26 +142,29 @@ CTCPSocket::read(void* buffer, UInt32 n)
|
||||||
void
|
void
|
||||||
CTCPSocket::write(const void* buffer, UInt32 n)
|
CTCPSocket::write(const void* buffer, UInt32 n)
|
||||||
{
|
{
|
||||||
CLock lock(&m_mutex);
|
bool wasEmpty;
|
||||||
|
{
|
||||||
|
CLock lock(&m_mutex);
|
||||||
|
|
||||||
// must not have shutdown output
|
// must not have shutdown output
|
||||||
if (!m_writable) {
|
if (!m_writable) {
|
||||||
sendStreamEvent(getOutputErrorEvent());
|
sendStreamEvent(getOutputErrorEvent());
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ignore empty writes
|
||||||
|
if (n == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy data to the output buffer
|
||||||
|
wasEmpty = (m_outputBuffer.getSize() == 0);
|
||||||
|
m_outputBuffer.write(buffer, n);
|
||||||
|
|
||||||
|
// there's data to write
|
||||||
|
m_flushed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ignore empty writes
|
|
||||||
if (n == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// copy data to the output buffer
|
|
||||||
bool wasEmpty = (m_outputBuffer.getSize() == 0);
|
|
||||||
m_outputBuffer.write(buffer, n);
|
|
||||||
|
|
||||||
// there's data to write
|
|
||||||
m_flushed = false;
|
|
||||||
|
|
||||||
// make sure we're waiting to write
|
// make sure we're waiting to write
|
||||||
if (wasEmpty) {
|
if (wasEmpty) {
|
||||||
setJob(newJob());
|
setJob(newJob());
|
||||||
|
@ -179,20 +183,26 @@ CTCPSocket::flush()
|
||||||
void
|
void
|
||||||
CTCPSocket::shutdownInput()
|
CTCPSocket::shutdownInput()
|
||||||
{
|
{
|
||||||
CLock lock(&m_mutex);
|
bool useNewJob = false;
|
||||||
|
{
|
||||||
|
CLock lock(&m_mutex);
|
||||||
|
|
||||||
// shutdown socket for reading
|
// shutdown socket for reading
|
||||||
try {
|
try {
|
||||||
ARCH->closeSocketForRead(m_socket);
|
ARCH->closeSocketForRead(m_socket);
|
||||||
}
|
}
|
||||||
catch (XArchNetwork&) {
|
catch (XArchNetwork&) {
|
||||||
// ignore
|
// ignore
|
||||||
}
|
}
|
||||||
|
|
||||||
// shutdown buffer for reading
|
// shutdown buffer for reading
|
||||||
if (m_readable) {
|
if (m_readable) {
|
||||||
sendStreamEvent(getInputShutdownEvent());
|
sendStreamEvent(getInputShutdownEvent());
|
||||||
onInputShutdown();
|
onInputShutdown();
|
||||||
|
useNewJob = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (useNewJob) {
|
||||||
setJob(newJob());
|
setJob(newJob());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -200,20 +210,26 @@ CTCPSocket::shutdownInput()
|
||||||
void
|
void
|
||||||
CTCPSocket::shutdownOutput()
|
CTCPSocket::shutdownOutput()
|
||||||
{
|
{
|
||||||
CLock lock(&m_mutex);
|
bool useNewJob = false;
|
||||||
|
{
|
||||||
|
CLock lock(&m_mutex);
|
||||||
|
|
||||||
// shutdown socket for writing
|
// shutdown socket for writing
|
||||||
try {
|
try {
|
||||||
ARCH->closeSocketForWrite(m_socket);
|
ARCH->closeSocketForWrite(m_socket);
|
||||||
}
|
}
|
||||||
catch (XArchNetwork&) {
|
catch (XArchNetwork&) {
|
||||||
// ignore
|
// ignore
|
||||||
}
|
}
|
||||||
|
|
||||||
// shutdown buffer for writing
|
// shutdown buffer for writing
|
||||||
if (m_writable) {
|
if (m_writable) {
|
||||||
sendStreamEvent(getOutputShutdownEvent());
|
sendStreamEvent(getOutputShutdownEvent());
|
||||||
onOutputShutdown();
|
onOutputShutdown();
|
||||||
|
useNewJob = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (useNewJob) {
|
||||||
setJob(newJob());
|
setJob(newJob());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -249,28 +265,29 @@ CTCPSocket::getEventFilter() const
|
||||||
void
|
void
|
||||||
CTCPSocket::connect(const CNetworkAddress& addr)
|
CTCPSocket::connect(const CNetworkAddress& addr)
|
||||||
{
|
{
|
||||||
CLock lock(&m_mutex);
|
{
|
||||||
|
CLock lock(&m_mutex);
|
||||||
|
|
||||||
// fail on attempts to reconnect
|
// fail on attempts to reconnect
|
||||||
if (m_socket == NULL || m_connected) {
|
if (m_socket == NULL || m_connected) {
|
||||||
sendSocketEvent(getConnectionFailedEvent());
|
sendConnectionFailedEvent("busy");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ARCH->connectSocket(m_socket, addr.getAddress());
|
ARCH->connectSocket(m_socket, addr.getAddress());
|
||||||
sendSocketEvent(getConnectedEvent());
|
sendSocketEvent(getConnectedEvent());
|
||||||
onConnected();
|
onConnected();
|
||||||
setJob(newJob());
|
}
|
||||||
}
|
catch (XArchNetworkConnecting&) {
|
||||||
catch (XArchNetworkConnecting&) {
|
// connection is in progress
|
||||||
// connection is in progress
|
m_writable = true;
|
||||||
m_writable = true;
|
}
|
||||||
setJob(newJob());
|
catch (XArchNetwork& e) {
|
||||||
}
|
throw XSocketConnect(e.what());
|
||||||
catch (XArchNetwork& e) {
|
}
|
||||||
throw XSocketConnect(e.what());
|
|
||||||
}
|
}
|
||||||
|
setJob(newJob());
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -339,17 +356,27 @@ CTCPSocket::newJob()
|
||||||
void
|
void
|
||||||
CTCPSocket::sendSocketEvent(CEvent::Type type)
|
CTCPSocket::sendSocketEvent(CEvent::Type type)
|
||||||
{
|
{
|
||||||
EVENTQUEUE->addEvent(CEvent(type, this, NULL));
|
EVENTQUEUE->addEvent(CEvent(type, getEventTarget(), NULL));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CTCPSocket::sendConnectionFailedEvent(const char* msg)
|
||||||
|
{
|
||||||
|
CConnectionFailedInfo* info = (CConnectionFailedInfo*)malloc(
|
||||||
|
sizeof(CConnectionFailedInfo) + strlen(msg));
|
||||||
|
strcpy(info->m_what, msg);
|
||||||
|
EVENTQUEUE->addEvent(CEvent(getConnectionFailedEvent(),
|
||||||
|
getEventTarget(), info));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CTCPSocket::sendStreamEvent(CEvent::Type type)
|
CTCPSocket::sendStreamEvent(CEvent::Type type)
|
||||||
{
|
{
|
||||||
if (m_eventFilter != NULL) {
|
if (m_eventFilter != NULL) {
|
||||||
m_eventFilter->run(CEvent(type, this, NULL));
|
m_eventFilter->run(CEvent(type, getEventTarget(), NULL));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
EVENTQUEUE->addEvent(CEvent(type, this, NULL));
|
EVENTQUEUE->addEvent(CEvent(type, getEventTarget(), NULL));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -394,22 +421,18 @@ CTCPSocket::serviceConnecting(ISocketMultiplexerJob* job,
|
||||||
{
|
{
|
||||||
CLock lock(&m_mutex);
|
CLock lock(&m_mutex);
|
||||||
|
|
||||||
if (write && !error) {
|
if (error) {
|
||||||
try {
|
try {
|
||||||
// connection may have failed or succeeded
|
// connection may have failed or succeeded
|
||||||
ARCH->throwErrorOnSocket(m_socket);
|
ARCH->throwErrorOnSocket(m_socket);
|
||||||
}
|
}
|
||||||
catch (XArchNetwork&) {
|
catch (XArchNetwork& e) {
|
||||||
error = true;
|
sendConnectionFailedEvent(e.what().c_str());
|
||||||
|
onDisconnected();
|
||||||
|
return newJob();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error) {
|
|
||||||
sendSocketEvent(getConnectionFailedEvent());
|
|
||||||
onDisconnected();
|
|
||||||
return newJob();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (write) {
|
if (write) {
|
||||||
sendSocketEvent(getConnectedEvent());
|
sendSocketEvent(getConnectedEvent());
|
||||||
onConnected();
|
onConnected();
|
||||||
|
|
|
@ -60,6 +60,7 @@ private:
|
||||||
void setJob(ISocketMultiplexerJob*);
|
void setJob(ISocketMultiplexerJob*);
|
||||||
ISocketMultiplexerJob* newJob();
|
ISocketMultiplexerJob* newJob();
|
||||||
void sendSocketEvent(CEvent::Type);
|
void sendSocketEvent(CEvent::Type);
|
||||||
|
void sendConnectionFailedEvent(const char*);
|
||||||
void sendStreamEvent(CEvent::Type);
|
void sendStreamEvent(CEvent::Type);
|
||||||
|
|
||||||
void onConnected();
|
void onConnected();
|
||||||
|
|
|
@ -25,6 +25,12 @@ represent a full-duplex data stream.
|
||||||
*/
|
*/
|
||||||
class IDataSocket : public ISocket, public IStream {
|
class IDataSocket : public ISocket, public IStream {
|
||||||
public:
|
public:
|
||||||
|
class CConnectionFailedInfo {
|
||||||
|
public:
|
||||||
|
// pointer to a string describing the failure
|
||||||
|
char m_what[1];
|
||||||
|
};
|
||||||
|
|
||||||
//! @name manipulators
|
//! @name manipulators
|
||||||
//@{
|
//@{
|
||||||
|
|
||||||
|
@ -52,6 +58,7 @@ public:
|
||||||
/*!
|
/*!
|
||||||
Returns the socket connection failed event type. A socket sends
|
Returns the socket connection failed event type. A socket sends
|
||||||
this event when an attempt to connect to a remote port has failed.
|
this event when an attempt to connect to a remote port has failed.
|
||||||
|
The data is a pointer to a CConnectionFailedInfo.
|
||||||
*/
|
*/
|
||||||
static CEvent::Type getConnectionFailedEvent();
|
static CEvent::Type getConnectionFailedEvent();
|
||||||
|
|
||||||
|
|
|
@ -53,12 +53,14 @@ XSocketAddress::getWhat() const throw()
|
||||||
"XSocketAddressUnknown",
|
"XSocketAddressUnknown",
|
||||||
"XSocketAddressNotFound",
|
"XSocketAddressNotFound",
|
||||||
"XSocketAddressNoAddress",
|
"XSocketAddressNoAddress",
|
||||||
|
"XSocketAddressUnsupported",
|
||||||
"XSocketAddressBadPort"
|
"XSocketAddressBadPort"
|
||||||
};
|
};
|
||||||
static const char* s_errorMsg[] = {
|
static const char* s_errorMsg[] = {
|
||||||
"unknown error for: %{1}:%{2}",
|
"unknown error for: %{1}:%{2}",
|
||||||
"address not found for: %{1}",
|
"address not found for: %{1}",
|
||||||
"no address for: %{1}",
|
"no address for: %{1}",
|
||||||
|
"unsupported address for: %{1}",
|
||||||
"invalid port" // m_port may not be set to the bad port
|
"invalid port" // m_port may not be set to the bad port
|
||||||
};
|
};
|
||||||
return format(s_errorID[m_error], s_errorMsg[m_error],
|
return format(s_errorID[m_error], s_errorMsg[m_error],
|
||||||
|
|
|
@ -34,6 +34,7 @@ public:
|
||||||
kUnknown, //!< Unknown error
|
kUnknown, //!< Unknown error
|
||||||
kNotFound, //!< The hostname is unknown
|
kNotFound, //!< The hostname is unknown
|
||||||
kNoAddress, //!< The hostname is valid but has no IP address
|
kNoAddress, //!< The hostname is valid but has no IP address
|
||||||
|
kUnsupported, //!< The hostname is valid but has no supported address
|
||||||
kBadPort //!< The port is invalid
|
kBadPort //!< The port is invalid
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -835,7 +835,7 @@ CXWindowsScreen::sendEvent(CEvent::Type type, void* data)
|
||||||
void
|
void
|
||||||
CXWindowsScreen::sendClipboardEvent(CEvent::Type type, ClipboardID id)
|
CXWindowsScreen::sendClipboardEvent(CEvent::Type type, ClipboardID id)
|
||||||
{
|
{
|
||||||
CClipboardInfo* info = new CClipboardInfo;
|
CClipboardInfo* info = (CClipboardInfo*)malloc(sizeof(CClipboardInfo));
|
||||||
info->m_id = id;
|
info->m_id = id;
|
||||||
info->m_sequenceNumber = m_sequenceNumber;
|
info->m_sequenceNumber = m_sequenceNumber;
|
||||||
sendEvent(type, info);
|
sendEvent(type, info);
|
||||||
|
@ -1028,11 +1028,11 @@ CXWindowsScreen::onKeyPress(XKeyEvent& xkey)
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle key
|
// handle key
|
||||||
sendEvent(getKeyDownEvent(), new CKeyInfo(key, mask, keycode, 1));
|
sendEvent(getKeyDownEvent(), CKeyInfo::alloc(key, mask, keycode, 1));
|
||||||
KeyModifierMask keyMask = m_keyState->getMaskForKey(keycode);
|
KeyModifierMask keyMask = m_keyState->getMaskForKey(keycode);
|
||||||
if (m_keyState->isHalfDuplex(keyMask)) {
|
if (m_keyState->isHalfDuplex(keyMask)) {
|
||||||
sendEvent(getKeyUpEvent(),
|
sendEvent(getKeyUpEvent(),
|
||||||
new CKeyInfo(key, mask | keyMask, keycode, 1));
|
CKeyInfo::alloc(key, mask | keyMask, keycode, 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1040,7 +1040,7 @@ CXWindowsScreen::onKeyPress(XKeyEvent& xkey)
|
||||||
Bool
|
Bool
|
||||||
CXWindowsScreen::findKeyEvent(Display*, XEvent* xevent, XPointer arg)
|
CXWindowsScreen::findKeyEvent(Display*, XEvent* xevent, XPointer arg)
|
||||||
{
|
{
|
||||||
CKeyEventInfo* filter = reinterpret_cast<CKeyEventInfo*>(arg);
|
CKeyEventFilter* filter = reinterpret_cast<CKeyEventFilter*>(arg);
|
||||||
return (xevent->type == filter->m_event &&
|
return (xevent->type == filter->m_event &&
|
||||||
xevent->xkey.window == filter->m_window &&
|
xevent->xkey.window == filter->m_window &&
|
||||||
xevent->xkey.time == filter->m_time &&
|
xevent->xkey.time == filter->m_time &&
|
||||||
|
@ -1057,7 +1057,7 @@ CXWindowsScreen::onKeyRelease(XKeyEvent& xkey)
|
||||||
// KeyPress event that has the same key and time as
|
// KeyPress event that has the same key and time as
|
||||||
// this release event, if any. first prepare the
|
// this release event, if any. first prepare the
|
||||||
// filter info.
|
// filter info.
|
||||||
CKeyEventInfo filter;
|
CKeyEventFilter filter;
|
||||||
filter.m_event = KeyPress;
|
filter.m_event = KeyPress;
|
||||||
filter.m_window = xkey.window;
|
filter.m_window = xkey.window;
|
||||||
filter.m_time = xkey.time;
|
filter.m_time = xkey.time;
|
||||||
|
@ -1089,9 +1089,9 @@ CXWindowsScreen::onKeyRelease(XKeyEvent& xkey)
|
||||||
KeyModifierMask keyMask = m_keyState->getMaskForKey(keycode);
|
KeyModifierMask keyMask = m_keyState->getMaskForKey(keycode);
|
||||||
if (m_keyState->isHalfDuplex(keyMask)) {
|
if (m_keyState->isHalfDuplex(keyMask)) {
|
||||||
sendEvent(getKeyDownEvent(),
|
sendEvent(getKeyDownEvent(),
|
||||||
new CKeyInfo(key, mask, keycode, 1));
|
CKeyInfo::alloc(key, mask, keycode, 1));
|
||||||
}
|
}
|
||||||
sendEvent(getKeyUpEvent(), new CKeyInfo(key, mask, keycode, 1));
|
sendEvent(getKeyUpEvent(), CKeyInfo::alloc(key, mask, keycode, 1));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// found a press event following so it's a repeat.
|
// found a press event following so it's a repeat.
|
||||||
|
@ -1099,7 +1099,8 @@ CXWindowsScreen::onKeyRelease(XKeyEvent& xkey)
|
||||||
// repeats but we'll just send a repeat of 1.
|
// repeats but we'll just send a repeat of 1.
|
||||||
// note that we discard the press event.
|
// note that we discard the press event.
|
||||||
LOG((CLOG_DEBUG1 "event: repeat code=%d, state=0x%04x", keycode, xkey.state));
|
LOG((CLOG_DEBUG1 "event: repeat code=%d, state=0x%04x", keycode, xkey.state));
|
||||||
sendEvent(getKeyRepeatEvent(), new CKeyInfo(key, mask, keycode, 1));
|
sendEvent(getKeyRepeatEvent(),
|
||||||
|
CKeyInfo::alloc(key, mask, keycode, 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1110,7 +1111,7 @@ CXWindowsScreen::onMousePress(const XButtonEvent& xbutton)
|
||||||
LOG((CLOG_DEBUG1 "event: ButtonPress button=%d", xbutton.button));
|
LOG((CLOG_DEBUG1 "event: ButtonPress button=%d", xbutton.button));
|
||||||
const ButtonID button = mapButtonFromX(&xbutton);
|
const ButtonID button = mapButtonFromX(&xbutton);
|
||||||
if (button != kButtonNone) {
|
if (button != kButtonNone) {
|
||||||
sendEvent(getButtonDownEvent(), new CButtonInfo(button));
|
sendEvent(getButtonDownEvent(), CButtonInfo::alloc(button));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1120,15 +1121,15 @@ CXWindowsScreen::onMouseRelease(const XButtonEvent& xbutton)
|
||||||
LOG((CLOG_DEBUG1 "event: ButtonRelease button=%d", xbutton.button));
|
LOG((CLOG_DEBUG1 "event: ButtonRelease button=%d", xbutton.button));
|
||||||
const ButtonID button = mapButtonFromX(&xbutton);
|
const ButtonID button = mapButtonFromX(&xbutton);
|
||||||
if (button != kButtonNone) {
|
if (button != kButtonNone) {
|
||||||
sendEvent(getButtonUpEvent(), new CButtonInfo(button));
|
sendEvent(getButtonUpEvent(), CButtonInfo::alloc(button));
|
||||||
}
|
}
|
||||||
else if (xbutton.button == 4) {
|
else if (xbutton.button == 4) {
|
||||||
// wheel forward (away from user)
|
// wheel forward (away from user)
|
||||||
sendEvent(getWheelEvent(), new CWheelInfo(120));
|
sendEvent(getWheelEvent(), CWheelInfo::alloc(120));
|
||||||
}
|
}
|
||||||
else if (xbutton.button == 5) {
|
else if (xbutton.button == 5) {
|
||||||
// wheel backward (toward user)
|
// wheel backward (toward user)
|
||||||
sendEvent(getWheelEvent(), new CWheelInfo(-120));
|
sendEvent(getWheelEvent(), CWheelInfo::alloc(-120));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1160,7 +1161,7 @@ CXWindowsScreen::onMouseMove(const XMotionEvent& xmotion)
|
||||||
else if (m_isOnScreen) {
|
else if (m_isOnScreen) {
|
||||||
// motion on primary screen
|
// motion on primary screen
|
||||||
sendEvent(getMotionOnPrimaryEvent(),
|
sendEvent(getMotionOnPrimaryEvent(),
|
||||||
new CMotionInfo(m_xCursor, m_yCursor));
|
CMotionInfo::alloc(m_xCursor, m_yCursor));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// motion on secondary screen. warp mouse back to
|
// motion on secondary screen. warp mouse back to
|
||||||
|
@ -1190,7 +1191,7 @@ CXWindowsScreen::onMouseMove(const XMotionEvent& xmotion)
|
||||||
// warping to the primary screen's enter position,
|
// warping to the primary screen's enter position,
|
||||||
// effectively overriding it.
|
// effectively overriding it.
|
||||||
if (x != 0 || y != 0) {
|
if (x != 0 || y != 0) {
|
||||||
sendEvent(getMotionOnSecondaryEvent(), new CMotionInfo(x, y));
|
sendEvent(getMotionOnSecondaryEvent(), CMotionInfo::alloc(x, y));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,7 +108,7 @@ private:
|
||||||
static int ioErrorHandler(Display*);
|
static int ioErrorHandler(Display*);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class CKeyEventInfo {
|
class CKeyEventFilter {
|
||||||
public:
|
public:
|
||||||
int m_event;
|
int m_event;
|
||||||
Window m_window;
|
Window m_window;
|
||||||
|
|
|
@ -78,7 +78,7 @@ public:
|
||||||
UInt32 seqNum, KeyModifierMask mask,
|
UInt32 seqNum, KeyModifierMask mask,
|
||||||
bool forScreensaver) = 0;
|
bool forScreensaver) = 0;
|
||||||
virtual bool leave() = 0;
|
virtual bool leave() = 0;
|
||||||
virtual void setClipboard(ClipboardID, const CString&) = 0;
|
virtual void setClipboard(ClipboardID, const IClipboard*) = 0;
|
||||||
virtual void grabClipboard(ClipboardID) = 0;
|
virtual void grabClipboard(ClipboardID) = 0;
|
||||||
virtual void setClipboardDirty(ClipboardID, bool) = 0;
|
virtual void setClipboardDirty(ClipboardID, bool) = 0;
|
||||||
virtual void keyDown(KeyID, KeyModifierMask, KeyButton) = 0;
|
virtual void keyDown(KeyID, KeyModifierMask, KeyButton) = 0;
|
||||||
|
|
|
@ -218,11 +218,9 @@ CClientProxy1_0::getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) const
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CClientProxy1_0::getCursorPos(SInt32& x, SInt32& y) const
|
CClientProxy1_0::getCursorPos(SInt32&, SInt32&) const
|
||||||
{
|
{
|
||||||
assert(0 && "shouldn't be called");
|
assert(0 && "shouldn't be called");
|
||||||
x = m_info.m_mx;
|
|
||||||
y = m_info.m_my;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -245,13 +243,15 @@ CClientProxy1_0::leave()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CClientProxy1_0::setClipboard(ClipboardID id, const CString& data)
|
CClientProxy1_0::setClipboard(ClipboardID id, const IClipboard* clipboard)
|
||||||
{
|
{
|
||||||
// ignore if this clipboard is already clean
|
// ignore if this clipboard is already clean
|
||||||
if (m_clipboard[id].m_dirty) {
|
if (m_clipboard[id].m_dirty) {
|
||||||
// this clipboard is now clean
|
// this clipboard is now clean
|
||||||
m_clipboard[id].m_dirty = false;
|
m_clipboard[id].m_dirty = false;
|
||||||
|
CClipboard::copy(&m_clipboard[id].m_clipboard, clipboard);
|
||||||
|
|
||||||
|
CString data = m_clipboard[id].m_clipboard.marshall();
|
||||||
LOG((CLOG_DEBUG "send clipboard %d to \"%s\" size=%d", id, getName().c_str(), data.size()));
|
LOG((CLOG_DEBUG "send clipboard %d to \"%s\" size=%d", id, getName().c_str(), data.size()));
|
||||||
CProtocolUtil::writef(getStream(), kMsgDClipboard, id, 0, &data);
|
CProtocolUtil::writef(getStream(), kMsgDClipboard, id, 0, &data);
|
||||||
}
|
}
|
||||||
|
@ -366,29 +366,23 @@ bool
|
||||||
CClientProxy1_0::recvInfo()
|
CClientProxy1_0::recvInfo()
|
||||||
{
|
{
|
||||||
// parse the message
|
// parse the message
|
||||||
SInt16 x, y, w, h, zoneSize, mx, my;
|
SInt16 x, y, w, h, dummy1, dummy2, dummy3;
|
||||||
if (!CProtocolUtil::readf(getStream(), kMsgDInfo + 4,
|
if (!CProtocolUtil::readf(getStream(), kMsgDInfo + 4,
|
||||||
&x, &y, &w, &h, &zoneSize, &mx, &my)) {
|
&x, &y, &w, &h, &dummy1, &dummy2, &dummy3)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
LOG((CLOG_DEBUG "received client \"%s\" info shape=%d,%d %dx%d, zone=%d, pos=%d,%d", getName().c_str(), x, y, w, h, zoneSize, mx, my));
|
LOG((CLOG_DEBUG "received client \"%s\" info shape=%d,%d %dx%d", getName().c_str(), x, y, w, h));
|
||||||
|
|
||||||
// validate
|
// validate
|
||||||
if (w <= 0 || h <= 0 || zoneSize < 0) {
|
if (w <= 0 || h <= 0) {
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (mx < x || my < y || mx >= x + w || my >= y + h) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// save
|
// save
|
||||||
m_info.m_x = x;
|
m_info.m_x = x;
|
||||||
m_info.m_y = y;
|
m_info.m_y = y;
|
||||||
m_info.m_w = w;
|
m_info.m_w = w;
|
||||||
m_info.m_h = h;
|
m_info.m_h = h;
|
||||||
m_info.m_zoneSize = zoneSize;
|
|
||||||
m_info.m_mx = mx;
|
|
||||||
m_info.m_my = my;
|
|
||||||
|
|
||||||
// acknowledge receipt
|
// acknowledge receipt
|
||||||
LOG((CLOG_DEBUG1 "send info ack to \"%s\"", getName().c_str()));
|
LOG((CLOG_DEBUG1 "send info ack to \"%s\"", getName().c_str()));
|
||||||
|
|
|
@ -39,7 +39,7 @@ public:
|
||||||
UInt32 seqNum, KeyModifierMask mask,
|
UInt32 seqNum, KeyModifierMask mask,
|
||||||
bool forScreensaver);
|
bool forScreensaver);
|
||||||
virtual bool leave();
|
virtual bool leave();
|
||||||
virtual void setClipboard(ClipboardID, const CString&);
|
virtual void setClipboard(ClipboardID, const IClipboard*);
|
||||||
virtual void grabClipboard(ClipboardID);
|
virtual void grabClipboard(ClipboardID);
|
||||||
virtual void setClipboardDirty(ClipboardID, bool);
|
virtual void setClipboardDirty(ClipboardID, bool);
|
||||||
virtual void keyDown(KeyID, KeyModifierMask, KeyButton);
|
virtual void keyDown(KeyID, KeyModifierMask, KeyButton);
|
||||||
|
|
|
@ -761,8 +761,9 @@ CConfig::readSectionOptions(std::istream& s)
|
||||||
try {
|
try {
|
||||||
m_synergyAddress = CNetworkAddress(value, kDefaultPort);
|
m_synergyAddress = CNetworkAddress(value, kDefaultPort);
|
||||||
}
|
}
|
||||||
catch (XSocketAddress&) {
|
catch (XSocketAddress& e) {
|
||||||
throw XConfigRead("invalid address argument");
|
throw XConfigRead(CString("invalid address argument: ") +
|
||||||
|
e.what());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (name == "heartbeat") {
|
else if (name == "heartbeat") {
|
||||||
|
|
|
@ -42,6 +42,12 @@ CPrimaryClient::reconfigure(UInt32 activeSides)
|
||||||
m_screen->reconfigure(activeSides);
|
m_screen->reconfigure(activeSides);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SInt32
|
||||||
|
CPrimaryClient::getJumpZoneSize() const
|
||||||
|
{
|
||||||
|
return m_screen->getJumpZoneSize();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CPrimaryClient::getCursorCenter(SInt32& x, SInt32& y) const
|
CPrimaryClient::getCursorCenter(SInt32& x, SInt32& y) const
|
||||||
{
|
{
|
||||||
|
@ -72,12 +78,6 @@ CPrimaryClient::getClipboard(ClipboardID id, IClipboard* clipboard) const
|
||||||
return m_screen->getClipboard(id, clipboard);
|
return m_screen->getClipboard(id, clipboard);
|
||||||
}
|
}
|
||||||
|
|
||||||
SInt32
|
|
||||||
CPrimaryClient::getJumpZoneSize() const
|
|
||||||
{
|
|
||||||
return m_screen->getJumpZoneSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
CPrimaryClient::getShape(SInt32& x, SInt32& y,
|
CPrimaryClient::getShape(SInt32& x, SInt32& y,
|
||||||
SInt32& width, SInt32& height) const
|
SInt32& width, SInt32& height) const
|
||||||
|
@ -121,19 +121,15 @@ CPrimaryClient::leave()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CPrimaryClient::setClipboard(ClipboardID id, const CString& data)
|
CPrimaryClient::setClipboard(ClipboardID id, const IClipboard* clipboard)
|
||||||
{
|
{
|
||||||
// ignore if this clipboard is already clean
|
// ignore if this clipboard is already clean
|
||||||
if (m_clipboardDirty[id]) {
|
if (m_clipboardDirty[id]) {
|
||||||
// this clipboard is now clean
|
// this clipboard is now clean
|
||||||
m_clipboardDirty[id] = false;
|
m_clipboardDirty[id] = false;
|
||||||
|
|
||||||
// unmarshall data
|
|
||||||
CClipboard clipboard;
|
|
||||||
clipboard.unmarshall(data, 0);
|
|
||||||
|
|
||||||
// set clipboard
|
// set clipboard
|
||||||
m_screen->setClipboard(id, &clipboard);
|
m_screen->setClipboard(id, clipboard);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,13 @@ public:
|
||||||
//! @name accessors
|
//! @name accessors
|
||||||
//@{
|
//@{
|
||||||
|
|
||||||
|
//! Get jump zone size
|
||||||
|
/*!
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
SInt32 getJumpZoneSize() const;
|
||||||
|
|
||||||
//! Get cursor center position
|
//! Get cursor center position
|
||||||
/*!
|
/*!
|
||||||
Return the cursor center position which is where we park the
|
Return the cursor center position which is where we park the
|
||||||
|
@ -76,7 +83,6 @@ public:
|
||||||
// IScreen overrides
|
// IScreen overrides
|
||||||
virtual void* getEventTarget() const;
|
virtual void* getEventTarget() const;
|
||||||
virtual bool getClipboard(ClipboardID id, IClipboard*) const;
|
virtual bool getClipboard(ClipboardID id, IClipboard*) const;
|
||||||
virtual SInt32 getJumpZoneSize() const;
|
|
||||||
virtual void getShape(SInt32& x, SInt32& y,
|
virtual void getShape(SInt32& x, SInt32& y,
|
||||||
SInt32& width, SInt32& height) const;
|
SInt32& width, SInt32& height) const;
|
||||||
virtual void getCursorPos(SInt32& x, SInt32& y) const;
|
virtual void getCursorPos(SInt32& x, SInt32& y) const;
|
||||||
|
@ -86,7 +92,7 @@ public:
|
||||||
UInt32 seqNum, KeyModifierMask mask,
|
UInt32 seqNum, KeyModifierMask mask,
|
||||||
bool forScreensaver);
|
bool forScreensaver);
|
||||||
virtual bool leave();
|
virtual bool leave();
|
||||||
virtual void setClipboard(ClipboardID, const CString&);
|
virtual void setClipboard(ClipboardID, const IClipboard*);
|
||||||
virtual void grabClipboard(ClipboardID);
|
virtual void grabClipboard(ClipboardID);
|
||||||
virtual void setClipboardDirty(ClipboardID, bool);
|
virtual void setClipboardDirty(ClipboardID, bool);
|
||||||
virtual void keyDown(KeyID, KeyModifierMask, KeyButton);
|
virtual void keyDown(KeyID, KeyModifierMask, KeyButton);
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
#include "CClientProxy.h"
|
#include "CClientProxy.h"
|
||||||
#include "CClientProxyUnknown.h"
|
#include "CClientProxyUnknown.h"
|
||||||
#include "CPrimaryClient.h"
|
#include "CPrimaryClient.h"
|
||||||
#include "CPacketStreamFilter.h"
|
|
||||||
#include "IPlatformScreen.h"
|
#include "IPlatformScreen.h"
|
||||||
#include "OptionTypes.h"
|
#include "OptionTypes.h"
|
||||||
#include "ProtocolTypes.h"
|
#include "ProtocolTypes.h"
|
||||||
|
@ -205,6 +204,11 @@ CServer::adoptClient(IClient* client)
|
||||||
{
|
{
|
||||||
assert(client != NULL);
|
assert(client != NULL);
|
||||||
|
|
||||||
|
// watch for client disconnection
|
||||||
|
EVENTQUEUE->adoptHandler(CClientProxy::getDisconnectedEvent(), client,
|
||||||
|
new TMethodEventJob<CServer>(this,
|
||||||
|
&CServer::handleClientDisconnected, client));
|
||||||
|
|
||||||
// name must be in our configuration
|
// name must be in our configuration
|
||||||
if (!m_config.isScreen(client->getName())) {
|
if (!m_config.isScreen(client->getName())) {
|
||||||
LOG((CLOG_WARN "a client with name \"%s\" is not in the map", client->getName().c_str()));
|
LOG((CLOG_WARN "a client with name \"%s\" is not in the map", client->getName().c_str()));
|
||||||
|
@ -221,11 +225,6 @@ CServer::adoptClient(IClient* client)
|
||||||
}
|
}
|
||||||
LOG((CLOG_NOTE "client \"%s\" has connected", getName(client).c_str()));
|
LOG((CLOG_NOTE "client \"%s\" has connected", getName(client).c_str()));
|
||||||
|
|
||||||
// watch for client disconnection
|
|
||||||
EVENTQUEUE->adoptHandler(CClientProxy::getDisconnectedEvent(), client,
|
|
||||||
new TMethodEventJob<CServer>(this,
|
|
||||||
&CServer::handleClientDisconnected, client));
|
|
||||||
|
|
||||||
// send configuration options to client
|
// send configuration options to client
|
||||||
sendOptions(client);
|
sendOptions(client);
|
||||||
|
|
||||||
|
@ -287,7 +286,11 @@ CServer::onCommandKey(KeyID /*id*/, KeyModifierMask /*mask*/, bool /*down*/)
|
||||||
CString
|
CString
|
||||||
CServer::getName(const IClient* client) const
|
CServer::getName(const IClient* client) const
|
||||||
{
|
{
|
||||||
return m_config.getCanonicalName(client->getName());
|
CString name = m_config.getCanonicalName(client->getName());
|
||||||
|
if (name.empty()) {
|
||||||
|
name = client->getName();
|
||||||
|
}
|
||||||
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
UInt32
|
UInt32
|
||||||
|
@ -397,7 +400,7 @@ CServer::switchScreen(IClient* dst, SInt32 x, SInt32 y, bool forScreensaver)
|
||||||
|
|
||||||
// send the clipboard data to new active screen
|
// send the clipboard data to new active screen
|
||||||
for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
|
for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
|
||||||
m_active->setClipboard(id, m_clipboards[id].m_clipboardData);
|
m_active->setClipboard(id, &m_clipboards[id].m_clipboard);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -1078,7 +1081,7 @@ CServer::onClipboardChanged(IClient* sender, ClipboardID id, UInt32 seqNum)
|
||||||
}
|
}
|
||||||
|
|
||||||
// send the new clipboard to the active screen
|
// send the new clipboard to the active screen
|
||||||
m_active->setClipboard(id, clipboard.m_clipboardData);
|
m_active->setClipboard(id, &clipboard.m_clipboard);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -101,126 +101,14 @@ CClipboard::get(EFormat format) const
|
||||||
return m_data[format];
|
return m_data[format];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
CClipboard::copy(IClipboard* dst, const IClipboard* src)
|
|
||||||
{
|
|
||||||
assert(dst != NULL);
|
|
||||||
assert(src != NULL);
|
|
||||||
|
|
||||||
return copy(dst, src, src->getTime());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
CClipboard::copy(IClipboard* dst, const IClipboard* src, Time time)
|
|
||||||
{
|
|
||||||
assert(dst != NULL);
|
|
||||||
assert(src != NULL);
|
|
||||||
|
|
||||||
bool success = false;
|
|
||||||
if (src->open(time)) {
|
|
||||||
if (dst->open(time)) {
|
|
||||||
if (dst->empty()) {
|
|
||||||
for (SInt32 format = 0;
|
|
||||||
format != IClipboard::kNumFormats; ++format) {
|
|
||||||
IClipboard::EFormat eFormat = (IClipboard::EFormat)format;
|
|
||||||
if (src->has(eFormat)) {
|
|
||||||
dst->add(eFormat, src->get(eFormat));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
success = true;
|
|
||||||
}
|
|
||||||
dst->close();
|
|
||||||
}
|
|
||||||
src->close();
|
|
||||||
}
|
|
||||||
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
CClipboard::unmarshall(const CString& data, Time time)
|
CClipboard::unmarshall(const CString& data, Time time)
|
||||||
{
|
{
|
||||||
const char* index = data.data();
|
IClipboard::unmarshall(this, data, time);
|
||||||
|
|
||||||
// clear existing data
|
|
||||||
open(time);
|
|
||||||
empty();
|
|
||||||
|
|
||||||
// read the number of formats
|
|
||||||
const UInt32 numFormats = readUInt32(index);
|
|
||||||
index += 4;
|
|
||||||
|
|
||||||
// read each format
|
|
||||||
for (UInt32 i = 0; i < numFormats; ++i) {
|
|
||||||
// get the format id
|
|
||||||
UInt32 format = readUInt32(index);
|
|
||||||
index += 4;
|
|
||||||
|
|
||||||
// get the size of the format data
|
|
||||||
UInt32 size = readUInt32(index);
|
|
||||||
index += 4;
|
|
||||||
|
|
||||||
// save the data if it's a known format. if either the client
|
|
||||||
// or server supports more clipboard formats than the other
|
|
||||||
// then one of them will get a format >= kNumFormats here.
|
|
||||||
if (format < static_cast<UInt32>(IClipboard::kNumFormats)) {
|
|
||||||
m_added[format] = true;
|
|
||||||
m_data[format] = CString(index, size);
|
|
||||||
}
|
|
||||||
index += size;
|
|
||||||
}
|
|
||||||
|
|
||||||
// done
|
|
||||||
close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CString
|
CString
|
||||||
CClipboard::marshall() const
|
CClipboard::marshall() const
|
||||||
{
|
{
|
||||||
CString data;
|
return IClipboard::marshall(this);
|
||||||
|
|
||||||
// compute size of marshalled data
|
|
||||||
UInt32 size = 4;
|
|
||||||
UInt32 numFormats = 0;
|
|
||||||
UInt32 format;
|
|
||||||
for (format = 0; format != IClipboard::kNumFormats; ++format) {
|
|
||||||
if (m_added[format]) {
|
|
||||||
++numFormats;
|
|
||||||
size += 4 + 4 + m_data[format].size();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// allocate space
|
|
||||||
data.reserve(size);
|
|
||||||
|
|
||||||
// marshall the data
|
|
||||||
writeUInt32(&data, numFormats);
|
|
||||||
for (format = 0; format != IClipboard::kNumFormats; ++format) {
|
|
||||||
if (m_added[format]) {
|
|
||||||
writeUInt32(&data, format);
|
|
||||||
writeUInt32(&data, m_data[format].size());
|
|
||||||
data += m_data[format];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
UInt32
|
|
||||||
CClipboard::readUInt32(const char* buf) const
|
|
||||||
{
|
|
||||||
const unsigned char* ubuf = reinterpret_cast<const unsigned char*>(buf);
|
|
||||||
return (static_cast<UInt32>(ubuf[0]) << 24) |
|
|
||||||
(static_cast<UInt32>(ubuf[1]) << 16) |
|
|
||||||
(static_cast<UInt32>(ubuf[2]) << 8) |
|
|
||||||
static_cast<UInt32>(ubuf[3]);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CClipboard::writeUInt32(CString* buf, UInt32 v) const
|
|
||||||
{
|
|
||||||
*buf += static_cast<UInt8>((v >> 24) & 0xff);
|
|
||||||
*buf += static_cast<UInt8>((v >> 16) & 0xff);
|
|
||||||
*buf += static_cast<UInt8>((v >> 8) & 0xff);
|
|
||||||
*buf += static_cast<UInt8>( v & 0xff);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,25 +47,6 @@ public:
|
||||||
*/
|
*/
|
||||||
CString marshall() const;
|
CString marshall() const;
|
||||||
|
|
||||||
//! Copy clipboard
|
|
||||||
/*!
|
|
||||||
Transfers all the data in one clipboard to another. The
|
|
||||||
clipboards can be of any concrete clipboard type (and
|
|
||||||
they don't have to be the same type). This also sets
|
|
||||||
the destination clipboard's timestamp to source clipboard's
|
|
||||||
timestamp. Returns true iff the copy succeeded.
|
|
||||||
*/
|
|
||||||
static bool copy(IClipboard* dst, const IClipboard* src);
|
|
||||||
|
|
||||||
//! Copy clipboard
|
|
||||||
/*!
|
|
||||||
Transfers all the data in one clipboard to another. The
|
|
||||||
clipboards can be of any concrete clipboard type (and they
|
|
||||||
don't have to be the same type). This also sets the
|
|
||||||
timestamp to \c time. Returns true iff the copy succeeded.
|
|
||||||
*/
|
|
||||||
static bool copy(IClipboard* dst, const IClipboard* src, Time);
|
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
// IClipboard overrides
|
// IClipboard overrides
|
||||||
|
@ -77,10 +58,6 @@ public:
|
||||||
virtual bool has(EFormat) const;
|
virtual bool has(EFormat) const;
|
||||||
virtual CString get(EFormat) const;
|
virtual CString get(EFormat) const;
|
||||||
|
|
||||||
private:
|
|
||||||
UInt32 readUInt32(const char*) const;
|
|
||||||
void writeUInt32(CString*, UInt32) const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
mutable bool m_open;
|
mutable bool m_open;
|
||||||
mutable Time m_time;
|
mutable Time m_time;
|
||||||
|
|
|
@ -34,7 +34,9 @@ CPacketStreamFilter::CPacketStreamFilter(IStream* stream, bool adoptStream) :
|
||||||
|
|
||||||
CPacketStreamFilter::~CPacketStreamFilter()
|
CPacketStreamFilter::~CPacketStreamFilter()
|
||||||
{
|
{
|
||||||
delete getStream()->getEventFilter();
|
IEventJob* job = getStream()->getEventFilter();
|
||||||
|
getStream()->setEventFilter(NULL);
|
||||||
|
delete job;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -58,7 +58,7 @@ public:
|
||||||
already known to be up to date then this may do nothing. \c data
|
already known to be up to date then this may do nothing. \c data
|
||||||
has marshalled clipboard data.
|
has marshalled clipboard data.
|
||||||
*/
|
*/
|
||||||
virtual void setClipboard(ClipboardID, const CString& data) = 0;
|
virtual void setClipboard(ClipboardID, const IClipboard*) = 0;
|
||||||
|
|
||||||
//! Grab clipboard
|
//! Grab clipboard
|
||||||
/*!
|
/*!
|
||||||
|
|
|
@ -0,0 +1,155 @@
|
||||||
|
/*
|
||||||
|
* 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 "IClipboard.h"
|
||||||
|
#include "stdvector.h"
|
||||||
|
|
||||||
|
//
|
||||||
|
// IClipboard
|
||||||
|
//
|
||||||
|
|
||||||
|
void
|
||||||
|
IClipboard::unmarshall(IClipboard* clipboard, const CString& data, Time time)
|
||||||
|
{
|
||||||
|
assert(clipboard != NULL);
|
||||||
|
|
||||||
|
const char* index = data.data();
|
||||||
|
|
||||||
|
// clear existing data
|
||||||
|
clipboard->open(time);
|
||||||
|
clipboard->empty();
|
||||||
|
|
||||||
|
// read the number of formats
|
||||||
|
const UInt32 numFormats = readUInt32(index);
|
||||||
|
index += 4;
|
||||||
|
|
||||||
|
// read each format
|
||||||
|
for (UInt32 i = 0; i < numFormats; ++i) {
|
||||||
|
// get the format id
|
||||||
|
IClipboard::EFormat format =
|
||||||
|
static_cast<IClipboard::EFormat>(readUInt32(index));
|
||||||
|
index += 4;
|
||||||
|
|
||||||
|
// get the size of the format data
|
||||||
|
UInt32 size = readUInt32(index);
|
||||||
|
index += 4;
|
||||||
|
|
||||||
|
// save the data if it's a known format. if either the client
|
||||||
|
// or server supports more clipboard formats than the other
|
||||||
|
// then one of them will get a format >= kNumFormats here.
|
||||||
|
if (format <IClipboard::kNumFormats) {
|
||||||
|
clipboard->add(format, CString(index, size));
|
||||||
|
}
|
||||||
|
index += size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// done
|
||||||
|
clipboard->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
CString
|
||||||
|
IClipboard::marshall(const IClipboard* clipboard)
|
||||||
|
{
|
||||||
|
assert(clipboard != NULL);
|
||||||
|
|
||||||
|
CString data;
|
||||||
|
|
||||||
|
std::vector<CString> formatData;
|
||||||
|
formatData.resize(IClipboard::kNumFormats);
|
||||||
|
// FIXME -- use current time
|
||||||
|
clipboard->open(0);
|
||||||
|
|
||||||
|
// compute size of marshalled data
|
||||||
|
UInt32 size = 4;
|
||||||
|
UInt32 numFormats = 0;
|
||||||
|
for (UInt32 format = 0; format != IClipboard::kNumFormats; ++format) {
|
||||||
|
if (clipboard->has(static_cast<IClipboard::EFormat>(format))) {
|
||||||
|
++numFormats;
|
||||||
|
formatData[format] =
|
||||||
|
clipboard->get(static_cast<IClipboard::EFormat>(format));
|
||||||
|
size += 4 + 4 + formatData[format].size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// allocate space
|
||||||
|
data.reserve(size);
|
||||||
|
|
||||||
|
// marshall the data
|
||||||
|
writeUInt32(&data, numFormats);
|
||||||
|
for (UInt32 format = 0; format != IClipboard::kNumFormats; ++format) {
|
||||||
|
if (clipboard->has(static_cast<IClipboard::EFormat>(format))) {
|
||||||
|
writeUInt32(&data, format);
|
||||||
|
writeUInt32(&data, formatData[format].size());
|
||||||
|
data += formatData[format];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
clipboard->close();
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
IClipboard::copy(IClipboard* dst, const IClipboard* src)
|
||||||
|
{
|
||||||
|
assert(dst != NULL);
|
||||||
|
assert(src != NULL);
|
||||||
|
|
||||||
|
return copy(dst, src, src->getTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
IClipboard::copy(IClipboard* dst, const IClipboard* src, Time time)
|
||||||
|
{
|
||||||
|
assert(dst != NULL);
|
||||||
|
assert(src != NULL);
|
||||||
|
|
||||||
|
bool success = false;
|
||||||
|
if (src->open(time)) {
|
||||||
|
if (dst->open(time)) {
|
||||||
|
if (dst->empty()) {
|
||||||
|
for (SInt32 format = 0;
|
||||||
|
format != IClipboard::kNumFormats; ++format) {
|
||||||
|
IClipboard::EFormat eFormat = (IClipboard::EFormat)format;
|
||||||
|
if (src->has(eFormat)) {
|
||||||
|
dst->add(eFormat, src->get(eFormat));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
success = true;
|
||||||
|
}
|
||||||
|
dst->close();
|
||||||
|
}
|
||||||
|
src->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
UInt32
|
||||||
|
IClipboard::readUInt32(const char* buf)
|
||||||
|
{
|
||||||
|
const unsigned char* ubuf = reinterpret_cast<const unsigned char*>(buf);
|
||||||
|
return (static_cast<UInt32>(ubuf[0]) << 24) |
|
||||||
|
(static_cast<UInt32>(ubuf[1]) << 16) |
|
||||||
|
(static_cast<UInt32>(ubuf[2]) << 8) |
|
||||||
|
static_cast<UInt32>(ubuf[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
IClipboard::writeUInt32(CString* buf, UInt32 v)
|
||||||
|
{
|
||||||
|
*buf += static_cast<UInt8>((v >> 24) & 0xff);
|
||||||
|
*buf += static_cast<UInt8>((v >> 16) & 0xff);
|
||||||
|
*buf += static_cast<UInt8>((v >> 8) & 0xff);
|
||||||
|
*buf += static_cast<UInt8>( v & 0xff);
|
||||||
|
}
|
|
@ -111,7 +111,45 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual CString get(EFormat) const = 0;
|
virtual CString get(EFormat) const = 0;
|
||||||
|
|
||||||
|
//! Marshall clipboard data
|
||||||
|
/*!
|
||||||
|
Merge \p clipboard's data into a single buffer that can be later
|
||||||
|
unmarshalled to restore the clipboard and return the buffer.
|
||||||
|
*/
|
||||||
|
static CString marshall(const IClipboard* clipboard);
|
||||||
|
|
||||||
|
//! Unmarshall clipboard data
|
||||||
|
/*!
|
||||||
|
Extract marshalled clipboard data and store it in \p clipboard.
|
||||||
|
Sets the clipboard time to \c time.
|
||||||
|
*/
|
||||||
|
static void unmarshall(IClipboard* clipboard,
|
||||||
|
const CString& data, Time time);
|
||||||
|
|
||||||
|
//! Copy clipboard
|
||||||
|
/*!
|
||||||
|
Transfers all the data in one clipboard to another. The
|
||||||
|
clipboards can be of any concrete clipboard type (and
|
||||||
|
they don't have to be the same type). This also sets
|
||||||
|
the destination clipboard's timestamp to source clipboard's
|
||||||
|
timestamp. Returns true iff the copy succeeded.
|
||||||
|
*/
|
||||||
|
static bool copy(IClipboard* dst, const IClipboard* src);
|
||||||
|
|
||||||
|
//! Copy clipboard
|
||||||
|
/*!
|
||||||
|
Transfers all the data in one clipboard to another. The
|
||||||
|
clipboards can be of any concrete clipboard type (and they
|
||||||
|
don't have to be the same type). This also sets the
|
||||||
|
timestamp to \c time. Returns true iff the copy succeeded.
|
||||||
|
*/
|
||||||
|
static bool copy(IClipboard* dst, const IClipboard* src, Time);
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static UInt32 readUInt32(const char*);
|
||||||
|
static void writeUInt32(CString*, UInt32);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -104,14 +104,16 @@ IPlatformScreen::getScreensaverDeactivatedEvent()
|
||||||
// IPlatformScreen::CKeyInfo
|
// IPlatformScreen::CKeyInfo
|
||||||
//
|
//
|
||||||
|
|
||||||
IPlatformScreen::CKeyInfo::CKeyInfo(KeyID id,
|
IPlatformScreen::CKeyInfo*
|
||||||
KeyModifierMask mask, KeyButton button, SInt32 count) :
|
IPlatformScreen::CKeyInfo::alloc(KeyID id,
|
||||||
m_key(id),
|
KeyModifierMask mask, KeyButton button, SInt32 count)
|
||||||
m_mask(mask),
|
|
||||||
m_button(button),
|
|
||||||
m_count(count)
|
|
||||||
{
|
{
|
||||||
// do nothing
|
CKeyInfo* info = (CKeyInfo*)malloc(sizeof(CKeyInfo));
|
||||||
|
info->m_key = id;
|
||||||
|
info->m_mask = mask;
|
||||||
|
info->m_button = button;
|
||||||
|
info->m_count = count;
|
||||||
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -119,10 +121,12 @@ IPlatformScreen::CKeyInfo::CKeyInfo(KeyID id,
|
||||||
// IPlatformScreen::CButtonInfo
|
// IPlatformScreen::CButtonInfo
|
||||||
//
|
//
|
||||||
|
|
||||||
IPlatformScreen::CButtonInfo::CButtonInfo(ButtonID id) :
|
IPlatformScreen::CButtonInfo*
|
||||||
m_button(id)
|
IPlatformScreen::CButtonInfo::alloc(ButtonID id)
|
||||||
{
|
{
|
||||||
// do nothing
|
CButtonInfo* info = (CButtonInfo*)malloc(sizeof(CButtonInfo));
|
||||||
|
info->m_button = id;
|
||||||
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -130,11 +134,13 @@ IPlatformScreen::CButtonInfo::CButtonInfo(ButtonID id) :
|
||||||
// IPlatformScreen::CMotionInfo
|
// IPlatformScreen::CMotionInfo
|
||||||
//
|
//
|
||||||
|
|
||||||
IPlatformScreen::CMotionInfo::CMotionInfo(SInt32 x, SInt32 y) :
|
IPlatformScreen::CMotionInfo*
|
||||||
m_x(x),
|
IPlatformScreen::CMotionInfo::alloc(SInt32 x, SInt32 y)
|
||||||
m_y(y)
|
|
||||||
{
|
{
|
||||||
// do nothing
|
CMotionInfo* info = (CMotionInfo*)malloc(sizeof(CMotionInfo));
|
||||||
|
info->m_x = x;
|
||||||
|
info->m_y = y;
|
||||||
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -142,8 +148,10 @@ IPlatformScreen::CMotionInfo::CMotionInfo(SInt32 x, SInt32 y) :
|
||||||
// IPlatformScreen::CWheelInfo
|
// IPlatformScreen::CWheelInfo
|
||||||
//
|
//
|
||||||
|
|
||||||
IPlatformScreen::CWheelInfo::CWheelInfo(SInt32 wheel) :
|
IPlatformScreen::CWheelInfo*
|
||||||
m_wheel(wheel)
|
IPlatformScreen::CWheelInfo::alloc(SInt32 wheel)
|
||||||
{
|
{
|
||||||
// do nothing
|
CWheelInfo* info = (CWheelInfo*)malloc(sizeof(CWheelInfo));
|
||||||
|
info->m_wheel = wheel;
|
||||||
|
return info;
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ public:
|
||||||
//! Key event data
|
//! Key event data
|
||||||
class CKeyInfo {
|
class CKeyInfo {
|
||||||
public:
|
public:
|
||||||
CKeyInfo(KeyID, KeyModifierMask, KeyButton, SInt32 count);
|
static CKeyInfo* alloc(KeyID, KeyModifierMask, KeyButton, SInt32 count);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
KeyID m_key;
|
KeyID m_key;
|
||||||
|
@ -51,7 +51,7 @@ public:
|
||||||
//! Button event data
|
//! Button event data
|
||||||
class CButtonInfo {
|
class CButtonInfo {
|
||||||
public:
|
public:
|
||||||
CButtonInfo(ButtonID);
|
static CButtonInfo* alloc(ButtonID);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ButtonID m_button;
|
ButtonID m_button;
|
||||||
|
@ -59,7 +59,7 @@ public:
|
||||||
//! Motion event data
|
//! Motion event data
|
||||||
class CMotionInfo {
|
class CMotionInfo {
|
||||||
public:
|
public:
|
||||||
CMotionInfo(SInt32 x, SInt32 y);
|
static CMotionInfo* alloc(SInt32 x, SInt32 y);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SInt32 m_x;
|
SInt32 m_x;
|
||||||
|
@ -68,7 +68,7 @@ public:
|
||||||
//! Wheel motion event data
|
//! Wheel motion event data
|
||||||
class CWheelInfo {
|
class CWheelInfo {
|
||||||
public:
|
public:
|
||||||
CWheelInfo(SInt32);
|
static CWheelInfo* alloc(SInt32);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SInt32 m_wheel;
|
SInt32 m_wheel;
|
||||||
|
|
|
@ -29,6 +29,7 @@ libsynergy_a_SOURCES = \
|
||||||
CPacketStreamFilter.cpp \
|
CPacketStreamFilter.cpp \
|
||||||
CProtocolUtil.cpp \
|
CProtocolUtil.cpp \
|
||||||
CScreen.cpp \
|
CScreen.cpp \
|
||||||
|
IClipboard.cpp \
|
||||||
IPlatformScreen.cpp \
|
IPlatformScreen.cpp \
|
||||||
IScreen.cpp \
|
IScreen.cpp \
|
||||||
XScreen.cpp \
|
XScreen.cpp \
|
||||||
|
|
|
@ -267,19 +267,11 @@ public:
|
||||||
*/
|
*/
|
||||||
SInt32 m_w, m_h;
|
SInt32 m_w, m_h;
|
||||||
|
|
||||||
//! Jump zone size
|
//! Obsolete (jump zone size)
|
||||||
/*!
|
SInt32 obsolete1;
|
||||||
This is the size of the jump zone. The cursor jumps to the adjacent
|
|
||||||
screen when it comes within this many pixels of the edge of the screen.
|
|
||||||
*/
|
|
||||||
SInt32 m_zoneSize;
|
|
||||||
|
|
||||||
//! Mouse position
|
//! Obsolete (mouse position)
|
||||||
/*!
|
SInt32 obsolete2, obsolete3;
|
||||||
The position of the cursor. This is not kept up-to-date so it's
|
|
||||||
only meaningful when receiving an update.
|
|
||||||
*/
|
|
||||||
SInt32 m_mx, m_my;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue