Checkpoint. synergys now works. Still need to do lib/client and
synergyc.
This commit is contained in:
parent
c44c18bfdc
commit
1861f21fb5
|
@ -14,8 +14,8 @@
|
||||||
|
|
||||||
#include "CServerTaskBarReceiver.h"
|
#include "CServerTaskBarReceiver.h"
|
||||||
#include "CServer.h"
|
#include "CServer.h"
|
||||||
|
#include "CEventQueue.h"
|
||||||
#include "CLock.h"
|
#include "CLock.h"
|
||||||
#include "TMethodJob.h"
|
|
||||||
#include "CArch.h"
|
#include "CArch.h"
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -23,71 +23,80 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
CServerTaskBarReceiver::CServerTaskBarReceiver() :
|
CServerTaskBarReceiver::CServerTaskBarReceiver() :
|
||||||
m_quit(NULL),
|
m_state(kNotRunning)
|
||||||
m_state(kNotRunning),
|
|
||||||
m_server(NULL)
|
|
||||||
{
|
{
|
||||||
// create a job for getting notification when the server's
|
// do nothing
|
||||||
// status changes.
|
|
||||||
m_job = new TMethodJob<CServerTaskBarReceiver>(this,
|
|
||||||
&CServerTaskBarReceiver::statusChanged, NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CServerTaskBarReceiver::~CServerTaskBarReceiver()
|
CServerTaskBarReceiver::~CServerTaskBarReceiver()
|
||||||
{
|
{
|
||||||
if (m_server != NULL) {
|
// do nothing
|
||||||
m_server->removeStatusJob(m_job);
|
|
||||||
}
|
|
||||||
delete m_job;
|
|
||||||
delete m_quit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include "CLog.h"
|
||||||
void
|
void
|
||||||
CServerTaskBarReceiver::setServer(CServer* server)
|
CServerTaskBarReceiver::updateStatus(CServer* server, const CString& errorMsg)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
|
// update our status
|
||||||
CLock lock(&m_mutex);
|
CLock lock(&m_mutex);
|
||||||
if (m_server != server) {
|
m_errorMessage = errorMsg;
|
||||||
if (m_server != NULL) {
|
if (server == NULL) {
|
||||||
m_server->removeStatusJob(m_job);
|
if (m_errorMessage.empty()) {
|
||||||
|
m_state = kNotRunning;
|
||||||
}
|
}
|
||||||
m_server = server;
|
else {
|
||||||
if (m_server != NULL) {
|
m_state = kNotWorking;
|
||||||
m_server->addStatusJob(m_job);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
m_clients.clear();
|
||||||
|
server->getClients(m_clients);
|
||||||
|
if (m_clients.size() <= 1) {
|
||||||
|
m_state = kNotConnected;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
m_state = kConnected;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// let subclasses have a go
|
||||||
|
onStatusChanged(server);
|
||||||
|
LOG((CLOG_INFO "### status: %s", getToolTip().c_str()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// tell task bar
|
||||||
ARCH->updateReceiver(this);
|
ARCH->updateReceiver(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
CServerTaskBarReceiver::setState(EState state)
|
|
||||||
{
|
|
||||||
{
|
|
||||||
CLock lock(&m_mutex);
|
|
||||||
m_state = state;
|
|
||||||
}
|
|
||||||
ARCH->updateReceiver(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CServerTaskBarReceiver::setQuitJob(IJob* job)
|
|
||||||
{
|
|
||||||
CLock lock(&m_mutex);
|
|
||||||
delete m_quit;
|
|
||||||
m_quit = job;
|
|
||||||
}
|
|
||||||
|
|
||||||
CServerTaskBarReceiver::EState
|
CServerTaskBarReceiver::EState
|
||||||
CServerTaskBarReceiver::getState() const
|
CServerTaskBarReceiver::getStatus() const
|
||||||
{
|
{
|
||||||
return m_state;
|
return m_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
CServer*
|
const CString&
|
||||||
CServerTaskBarReceiver::getServer() const
|
CServerTaskBarReceiver::getErrorMessage() const
|
||||||
{
|
{
|
||||||
return m_server;
|
return m_errorMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CServerTaskBarReceiver::CClients&
|
||||||
|
CServerTaskBarReceiver::getClients() const
|
||||||
|
{
|
||||||
|
return m_clients;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CServerTaskBarReceiver::quit()
|
||||||
|
{
|
||||||
|
EVENTQUEUE->addEvent(CEvent(CEvent::kQuit));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CServerTaskBarReceiver::onStatusChanged(CServer*)
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -110,7 +119,7 @@ CServerTaskBarReceiver::getToolTip() const
|
||||||
return "Synergy: Not running";
|
return "Synergy: Not running";
|
||||||
|
|
||||||
case kNotWorking:
|
case kNotWorking:
|
||||||
return CString("Synergy: ") + m_errorMessage;
|
return std::string("Synergy: ") + m_errorMessage;
|
||||||
|
|
||||||
case kNotConnected:
|
case kNotConnected:
|
||||||
return "Synergy: Waiting for clients";
|
return "Synergy: Waiting for clients";
|
||||||
|
@ -122,50 +131,3 @@ CServerTaskBarReceiver::getToolTip() const
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
CServerTaskBarReceiver::quit()
|
|
||||||
{
|
|
||||||
if (m_quit != NULL) {
|
|
||||||
m_quit->run();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CServerTaskBarReceiver::onStatusChanged()
|
|
||||||
{
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CServerTaskBarReceiver::statusChanged(void*)
|
|
||||||
{
|
|
||||||
// update our status
|
|
||||||
switch (m_server->getStatus(&m_errorMessage)) {
|
|
||||||
case CServer::kNotRunning:
|
|
||||||
setState(kNotRunning);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CServer::kRunning:
|
|
||||||
if (m_server->getNumClients() > 1)
|
|
||||||
setState(kConnected);
|
|
||||||
else
|
|
||||||
setState(kNotConnected);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CServer::kServerNameUnknown:
|
|
||||||
m_errorMessage = "Server name is not in configuration";
|
|
||||||
setState(kNotWorking);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CServer::kError:
|
|
||||||
setState(kNotWorking);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// let subclasses have a go
|
|
||||||
onStatusChanged();
|
|
||||||
}
|
|
||||||
|
|
|
@ -18,61 +18,24 @@
|
||||||
#include "CMutex.h"
|
#include "CMutex.h"
|
||||||
#include "CString.h"
|
#include "CString.h"
|
||||||
#include "IArchTaskBarReceiver.h"
|
#include "IArchTaskBarReceiver.h"
|
||||||
|
#include "stdvector.h"
|
||||||
|
|
||||||
class CServer;
|
class CServer;
|
||||||
class IJob;
|
|
||||||
|
|
||||||
//! Implementation of IArchTaskBarReceiver for the synergy server
|
//! Implementation of IArchTaskBarReceiver for the synergy server
|
||||||
class CServerTaskBarReceiver : public IArchTaskBarReceiver {
|
class CServerTaskBarReceiver : public IArchTaskBarReceiver {
|
||||||
public:
|
public:
|
||||||
enum EState {
|
|
||||||
kNotRunning,
|
|
||||||
kNotWorking,
|
|
||||||
kNotConnected,
|
|
||||||
kConnected,
|
|
||||||
kMaxState
|
|
||||||
};
|
|
||||||
|
|
||||||
CServerTaskBarReceiver();
|
CServerTaskBarReceiver();
|
||||||
virtual ~CServerTaskBarReceiver();
|
virtual ~CServerTaskBarReceiver();
|
||||||
|
|
||||||
//! @name manipulators
|
//! @name manipulators
|
||||||
//@{
|
//@{
|
||||||
|
|
||||||
//! Set server
|
//! Update status
|
||||||
/*!
|
/*!
|
||||||
Sets the server. The receiver will query state from this server.
|
Determine the status and query required information from the server.
|
||||||
*/
|
*/
|
||||||
void setServer(CServer*);
|
void updateStatus(CServer*, const CString& errorMsg);
|
||||||
|
|
||||||
//! Set state
|
|
||||||
/*!
|
|
||||||
Sets the current server state.
|
|
||||||
*/
|
|
||||||
void setState(EState);
|
|
||||||
|
|
||||||
//! Set the quit job that causes the server to quit
|
|
||||||
/*!
|
|
||||||
Set the job that causes the server to quit.
|
|
||||||
*/
|
|
||||||
void setQuitJob(IJob* adopted);
|
|
||||||
|
|
||||||
//@}
|
|
||||||
//! @name accessors
|
|
||||||
//@{
|
|
||||||
|
|
||||||
//! Get state
|
|
||||||
/*!
|
|
||||||
Returns the current server state. The receiver is not locked
|
|
||||||
by this call; the caller must do the locking.
|
|
||||||
*/
|
|
||||||
EState getState() const;
|
|
||||||
|
|
||||||
//! Get server
|
|
||||||
/*!
|
|
||||||
Returns the server set by \c setServer().
|
|
||||||
*/
|
|
||||||
CServer* getServer() const;
|
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
|
@ -86,6 +49,28 @@ public:
|
||||||
virtual std::string getToolTip() const;
|
virtual std::string getToolTip() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
typedef std::vector<CString> CClients;
|
||||||
|
enum EState {
|
||||||
|
kNotRunning,
|
||||||
|
kNotWorking,
|
||||||
|
kNotConnected,
|
||||||
|
kConnected,
|
||||||
|
kMaxState
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Get status
|
||||||
|
EState getStatus() const;
|
||||||
|
|
||||||
|
//! Get error message
|
||||||
|
const CString& getErrorMessage() const;
|
||||||
|
|
||||||
|
//! Get connected clients
|
||||||
|
const CClients& getClients() const;
|
||||||
|
|
||||||
|
//! Quit app
|
||||||
|
/*!
|
||||||
|
Causes the application to quit gracefully
|
||||||
|
*/
|
||||||
void quit();
|
void quit();
|
||||||
|
|
||||||
//! Status change notification
|
//! Status change notification
|
||||||
|
@ -93,18 +78,13 @@ protected:
|
||||||
Called when status changes. The default implementation does
|
Called when status changes. The default implementation does
|
||||||
nothing.
|
nothing.
|
||||||
*/
|
*/
|
||||||
virtual void onStatusChanged();
|
virtual void onStatusChanged(CServer* server);
|
||||||
|
|
||||||
private:
|
|
||||||
void statusChanged(void*);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CMutex m_mutex;
|
CMutex m_mutex;
|
||||||
IJob* m_quit;
|
|
||||||
EState m_state;
|
EState m_state;
|
||||||
CServer* m_server;
|
|
||||||
IJob* m_job;
|
|
||||||
CString m_errorMessage;
|
CString m_errorMessage;
|
||||||
|
CClients m_clients;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -53,9 +53,3 @@ CXWindowsServerTaskBarReceiver::getIcon() const
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
CXWindowsServerTaskBarReceiver::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:
|
|
||||||
// CServerTaskBarReceiver overrides
|
|
||||||
virtual void onStatusChanged();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -12,22 +12,25 @@
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "CServer.h"
|
#include "CClientListener.h"
|
||||||
|
#include "CClientProxy.h"
|
||||||
#include "CConfig.h"
|
#include "CConfig.h"
|
||||||
#include "IScreenFactory.h"
|
#include "CPrimaryClient.h"
|
||||||
|
#include "CServer.h"
|
||||||
|
#include "CScreen.h"
|
||||||
#include "ProtocolTypes.h"
|
#include "ProtocolTypes.h"
|
||||||
#include "Version.h"
|
#include "Version.h"
|
||||||
#include "XScreen.h"
|
#include "XScreen.h"
|
||||||
|
#include "CSocketMultiplexer.h"
|
||||||
#include "CTCPSocketFactory.h"
|
#include "CTCPSocketFactory.h"
|
||||||
#include "XSocket.h"
|
#include "XSocket.h"
|
||||||
#include "CLock.h"
|
|
||||||
#include "CMutex.h"
|
|
||||||
#include "CThread.h"
|
#include "CThread.h"
|
||||||
#include "XThread.h"
|
#include "CEventQueue.h"
|
||||||
#include "CFunctionJob.h"
|
#include "CFunctionEventJob.h"
|
||||||
#include "CLog.h"
|
#include "CLog.h"
|
||||||
#include "LogOutputters.h"
|
#include "LogOutputters.h"
|
||||||
#include "CArch.h"
|
#include "CArch.h"
|
||||||
|
#include "XArch.h"
|
||||||
#include "stdfstream.h"
|
#include "stdfstream.h"
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
|
@ -98,82 +101,243 @@ CArgs* CArgs::s_instance = NULL;
|
||||||
// platform dependent factories
|
// platform dependent factories
|
||||||
//
|
//
|
||||||
|
|
||||||
//! Factory for creating screens
|
static
|
||||||
/*!
|
CScreen*
|
||||||
Objects of this type create screens appropriate for the platform.
|
createScreen()
|
||||||
*/
|
|
||||||
class CScreenFactory : public IScreenFactory {
|
|
||||||
public:
|
|
||||||
CScreenFactory() { }
|
|
||||||
virtual ~CScreenFactory() { }
|
|
||||||
|
|
||||||
// IScreenFactory overrides
|
|
||||||
virtual IPlatformScreen*
|
|
||||||
create(IScreenReceiver*, IPrimaryScreenReceiver*);
|
|
||||||
};
|
|
||||||
|
|
||||||
IPlatformScreen*
|
|
||||||
CScreenFactory::create(IScreenReceiver* receiver,
|
|
||||||
IPrimaryScreenReceiver* primaryReceiver)
|
|
||||||
{
|
{
|
||||||
#if WINDOWS_LIKE
|
#if WINDOWS_LIKE
|
||||||
return new CMSWindowsScreen(receiver, primaryReceiver);
|
return new CScreen(new CMSWindowsScreen(true));
|
||||||
#elif UNIX_LIKE
|
#elif UNIX_LIKE
|
||||||
return new CXWindowsScreen(receiver, primaryReceiver);
|
return new CScreen(new CXWindowsScreen(true));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//! CQuitJob
|
|
||||||
/*!
|
|
||||||
A job that cancels a given thread.
|
|
||||||
*/
|
|
||||||
class CQuitJob : public IJob {
|
|
||||||
public:
|
|
||||||
CQuitJob(const CThread& thread);
|
|
||||||
~CQuitJob();
|
|
||||||
|
|
||||||
// IJob overrides
|
|
||||||
virtual void run();
|
|
||||||
|
|
||||||
private:
|
|
||||||
CThread m_thread;
|
|
||||||
};
|
|
||||||
|
|
||||||
CQuitJob::CQuitJob(const CThread& thread) :
|
|
||||||
m_thread(thread)
|
|
||||||
{
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
CQuitJob::~CQuitJob()
|
|
||||||
{
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CQuitJob::run()
|
|
||||||
{
|
|
||||||
m_thread.cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// platform independent main
|
// platform independent main
|
||||||
//
|
//
|
||||||
|
|
||||||
static CServer* s_server = NULL;
|
static CServer* s_server = NULL;
|
||||||
|
static CPrimaryClient* s_primaryClient = NULL;
|
||||||
|
static CClientListener* s_listener = NULL;
|
||||||
static CServerTaskBarReceiver* s_taskBarReceiver = NULL;
|
static CServerTaskBarReceiver* s_taskBarReceiver = NULL;
|
||||||
|
|
||||||
static
|
static
|
||||||
int
|
void
|
||||||
realMain(void)
|
updateStatus()
|
||||||
{
|
{
|
||||||
int result = kExitSuccess;
|
s_taskBarReceiver->updateStatus(s_server, "");
|
||||||
do {
|
}
|
||||||
bool opened = false;
|
|
||||||
bool locked = true;
|
static
|
||||||
|
void
|
||||||
|
updateStatus(const CString& msg)
|
||||||
|
{
|
||||||
|
s_taskBarReceiver->updateStatus(s_server, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
handleClientConnected(const CEvent&, void* vlistener)
|
||||||
|
{
|
||||||
|
CClientListener* listener = reinterpret_cast<CClientListener*>(vlistener);
|
||||||
|
CClientProxy* client = listener->getNextClient();
|
||||||
|
if (client != NULL) {
|
||||||
|
s_server->adoptClient(client);
|
||||||
|
updateStatus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
CClientListener*
|
||||||
|
openClientListener(const CNetworkAddress& address)
|
||||||
|
{
|
||||||
|
CClientListener* listen =
|
||||||
|
new CClientListener(address, new CTCPSocketFactory, NULL);
|
||||||
|
EVENTQUEUE->adoptHandler(CClientListener::getConnectedEvent(), listen,
|
||||||
|
new CFunctionEventJob(
|
||||||
|
&handleClientConnected, listen));
|
||||||
|
return listen;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
closeClientListener(CClientListener* listen)
|
||||||
|
{
|
||||||
|
if (listen != NULL) {
|
||||||
|
EVENTQUEUE->removeHandler(CClientListener::getConnectedEvent(), listen);
|
||||||
|
delete listen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
handleScreenError(const CEvent&, void*)
|
||||||
|
{
|
||||||
|
EVENTQUEUE->addEvent(CEvent(CEvent::kQuit));
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
CPrimaryClient*
|
||||||
|
openPrimaryClient(const CString& name)
|
||||||
|
{
|
||||||
|
LOG((CLOG_DEBUG1 "creating primary screen"));
|
||||||
|
CScreen* screen = createScreen();
|
||||||
|
CPrimaryClient* primaryClient = new CPrimaryClient(name, screen);
|
||||||
|
EVENTQUEUE->adoptHandler(IScreen::getErrorEvent(),
|
||||||
|
primaryClient->getEventTarget(),
|
||||||
|
new CFunctionEventJob(
|
||||||
|
&handleScreenError));
|
||||||
|
return primaryClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
closePrimaryClient(CPrimaryClient* primaryClient)
|
||||||
|
{
|
||||||
|
if (primaryClient != NULL) {
|
||||||
|
EVENTQUEUE->removeHandler(IScreen::getErrorEvent(),
|
||||||
|
primaryClient->getEventTarget());
|
||||||
|
delete primaryClient;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
handleNoClients(const CEvent&, void*)
|
||||||
|
{
|
||||||
|
updateStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
handleClientsDisconnected(const CEvent&, void*)
|
||||||
|
{
|
||||||
|
EVENTQUEUE->addEvent(CEvent(CEvent::kQuit));
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
CServer*
|
||||||
|
openServer(const CConfig& config, CPrimaryClient* primaryClient)
|
||||||
|
{
|
||||||
|
CServer* server = new CServer(config, primaryClient);
|
||||||
|
EVENTQUEUE->adoptHandler(CServer::getDisconnectedEvent(), server,
|
||||||
|
new CFunctionEventJob(handleNoClients));
|
||||||
|
return server;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
closeServer(CServer* server)
|
||||||
|
{
|
||||||
|
if (server == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// tell all clients to disconnect
|
||||||
|
server->disconnect();
|
||||||
|
|
||||||
|
// wait for clients to disconnect for up to timeout seconds
|
||||||
|
double timeout = 3.0;
|
||||||
|
CEventQueueTimer* timer = EVENTQUEUE->newOneShotTimer(timeout, NULL);
|
||||||
|
EVENTQUEUE->adoptHandler(CEvent::kTimer, timer,
|
||||||
|
new CFunctionEventJob(handleClientsDisconnected));
|
||||||
|
EVENTQUEUE->adoptHandler(CServer::getDisconnectedEvent(), server,
|
||||||
|
new CFunctionEventJob(handleClientsDisconnected));
|
||||||
|
CEvent event;
|
||||||
|
EVENTQUEUE->getEvent(event);
|
||||||
|
while (event.getType() != CEvent::kQuit) {
|
||||||
|
EVENTQUEUE->dispatchEvent(event);
|
||||||
|
CEvent::deleteData(event);
|
||||||
|
EVENTQUEUE->getEvent(event);
|
||||||
|
}
|
||||||
|
EVENTQUEUE->removeHandler(CEvent::kTimer, timer);
|
||||||
|
EVENTQUEUE->deleteTimer(timer);
|
||||||
|
EVENTQUEUE->removeHandler(CServer::getDisconnectedEvent(), server);
|
||||||
|
|
||||||
|
// done with server
|
||||||
|
delete server;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool startServer();
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
retryStartHandler(const CEvent&, void* vtimer)
|
||||||
|
{
|
||||||
|
// discard old timer
|
||||||
|
CEventQueueTimer* timer = reinterpret_cast<CEventQueueTimer*>(vtimer);
|
||||||
|
EVENTQUEUE->deleteTimer(timer);
|
||||||
|
EVENTQUEUE->removeHandler(CEvent::kTimer, NULL);
|
||||||
|
|
||||||
|
// try starting the server again
|
||||||
|
LOG((CLOG_DEBUG1 "retry starting server"));
|
||||||
|
startServer();
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
bool
|
||||||
|
startServer()
|
||||||
|
{
|
||||||
|
double retryTime;
|
||||||
|
CPrimaryClient* primaryClient = NULL;
|
||||||
|
CClientListener* listener = NULL;
|
||||||
try {
|
try {
|
||||||
|
CString name = ARG->m_config.getCanonicalName(ARG->m_name);
|
||||||
|
primaryClient = openPrimaryClient(name);
|
||||||
|
listener = openClientListener(ARG->m_config.getSynergyAddress());
|
||||||
|
s_server = openServer(ARG->m_config, primaryClient);
|
||||||
|
s_primaryClient = primaryClient;
|
||||||
|
s_listener = listener;
|
||||||
|
updateStatus();
|
||||||
|
LOG((CLOG_NOTE "started server"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (XScreenUnavailable& e) {
|
||||||
|
LOG((CLOG_WARN "cannot open primary screen: %s", e.what()));
|
||||||
|
closeClientListener(listener);
|
||||||
|
closePrimaryClient(primaryClient);
|
||||||
|
updateStatus(CString("cannot open primary screen: ") + e.what());
|
||||||
|
retryTime = e.getRetryTime();
|
||||||
|
}
|
||||||
|
catch (XSocketAddressInUse& e) {
|
||||||
|
LOG((CLOG_WARN "cannot listen for clients: %s", e.what()));
|
||||||
|
closeClientListener(listener);
|
||||||
|
closePrimaryClient(primaryClient);
|
||||||
|
updateStatus(CString("cannot listen for clients: ") + e.what());
|
||||||
|
retryTime = 10.0;
|
||||||
|
}
|
||||||
|
catch (XScreenOpenFailure& e) {
|
||||||
|
LOG((CLOG_CRIT "cannot open primary screen: %s", e.what()));
|
||||||
|
closeClientListener(listener);
|
||||||
|
closePrimaryClient(primaryClient);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
catch (XBase& e) {
|
||||||
|
LOG((CLOG_CRIT "failed to start server: %s", e.what()));
|
||||||
|
closeClientListener(listener);
|
||||||
|
closePrimaryClient(primaryClient);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ARG->m_restartable) {
|
||||||
|
// install a timer and handler to retry later
|
||||||
|
LOG((CLOG_DEBUG "retry in %.0f seconds", retryTime));
|
||||||
|
CEventQueueTimer* timer = EVENTQUEUE->newOneShotTimer(retryTime, NULL);
|
||||||
|
EVENTQUEUE->adoptHandler(CEvent::kTimer, timer,
|
||||||
|
new CFunctionEventJob(&retryStartHandler, timer));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// don't try again
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int
|
||||||
|
realMain()
|
||||||
|
{
|
||||||
// if configuration has no screens then add this system
|
// if configuration has no screens then add this system
|
||||||
// as the default
|
// as the default
|
||||||
if (ARG->m_config.begin() == ARG->m_config.end()) {
|
if (ARG->m_config.begin() == ARG->m_config.end()) {
|
||||||
|
@ -190,74 +354,48 @@ realMain(void)
|
||||||
ARG->m_config.setSynergyAddress(CNetworkAddress(kDefaultPort));
|
ARG->m_config.setSynergyAddress(CNetworkAddress(kDefaultPort));
|
||||||
}
|
}
|
||||||
|
|
||||||
// create server
|
// canonicalize the primary screen name
|
||||||
s_server = new CServer(ARG->m_name);
|
CString primaryName = ARG->m_config.getCanonicalName(ARG->m_name);
|
||||||
s_server->setConfig(ARG->m_config);
|
if (primaryName.empty()) {
|
||||||
s_server->setScreenFactory(new CScreenFactory);
|
LOG((CLOG_CRIT "unknown screen name `%s'", ARG->m_name.c_str()));
|
||||||
s_server->setSocketFactory(new CTCPSocketFactory);
|
return kExitFailed;
|
||||||
s_server->setStreamFilterFactory(NULL);
|
}
|
||||||
|
|
||||||
// open server
|
// start the server. if this return false then we've failed and
|
||||||
try {
|
// we shouldn't retry.
|
||||||
s_taskBarReceiver->setServer(s_server);
|
LOG((CLOG_DEBUG1 "starting server"));
|
||||||
s_server->open();
|
if (!startServer()) {
|
||||||
opened = true;
|
return kExitFailed;
|
||||||
|
}
|
||||||
|
|
||||||
// run server
|
// run event loop. if startServer() failed we're supposed to retry
|
||||||
|
// later. the timer installed by startServer() will take care of
|
||||||
|
// that.
|
||||||
DAEMON_RUNNING(true);
|
DAEMON_RUNNING(true);
|
||||||
locked = false;
|
CEvent event;
|
||||||
s_server->mainLoop();
|
EVENTQUEUE->getEvent(event);
|
||||||
|
while (event.getType() != CEvent::kQuit) {
|
||||||
|
EVENTQUEUE->dispatchEvent(event);
|
||||||
|
CEvent::deleteData(event);
|
||||||
|
EVENTQUEUE->getEvent(event);
|
||||||
|
}
|
||||||
|
DAEMON_RUNNING(false);
|
||||||
|
|
||||||
// clean up
|
// close down
|
||||||
#define FINALLY do { \
|
LOG((CLOG_DEBUG1 "stopping server"));
|
||||||
if (!locked) { \
|
closeClientListener(s_listener);
|
||||||
DAEMON_RUNNING(false); \
|
closeServer(s_server);
|
||||||
locked = true; \
|
closePrimaryClient(s_primaryClient);
|
||||||
} \
|
s_server = NULL;
|
||||||
if (opened) { \
|
s_listener = NULL;
|
||||||
s_server->close(); \
|
s_primaryClient = NULL;
|
||||||
} \
|
updateStatus();
|
||||||
s_taskBarReceiver->setServer(NULL); \
|
LOG((CLOG_NOTE "stopped server"));
|
||||||
delete s_server; \
|
|
||||||
s_server = NULL; \
|
|
||||||
} while (false)
|
|
||||||
FINALLY;
|
|
||||||
}
|
|
||||||
catch (XScreenUnavailable& e) {
|
|
||||||
// wait before retrying if we're going to retry
|
|
||||||
if (ARG->m_restartable) {
|
|
||||||
ARCH->sleep(e.getRetryTime());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
result = kExitFailed;
|
|
||||||
}
|
|
||||||
FINALLY;
|
|
||||||
}
|
|
||||||
catch (XThread&) {
|
|
||||||
FINALLY;
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
catch (...) {
|
|
||||||
// don't try to restart and fail
|
|
||||||
ARG->m_restartable = false;
|
|
||||||
result = kExitFailed;
|
|
||||||
FINALLY;
|
|
||||||
}
|
|
||||||
#undef FINALLY
|
|
||||||
}
|
|
||||||
catch (XBase& e) {
|
|
||||||
LOG((CLOG_CRIT "failed: %s", e.what()));
|
|
||||||
}
|
|
||||||
catch (XThread&) {
|
|
||||||
// terminated
|
|
||||||
ARG->m_restartable = false;
|
|
||||||
result = kExitTerminated;
|
|
||||||
}
|
|
||||||
} while (ARG->m_restartable);
|
|
||||||
|
|
||||||
return result;
|
return kExitSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* XXX
|
||||||
static
|
static
|
||||||
void
|
void
|
||||||
realMainEntry(void* vresult)
|
realMainEntry(void* vresult)
|
||||||
|
@ -293,7 +431,7 @@ runMainInThread(void)
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
//
|
//
|
||||||
// command line parsing
|
// command line parsing
|
||||||
|
@ -666,9 +804,6 @@ daemonStartup(int argc, const char** argv)
|
||||||
{
|
{
|
||||||
CSystemLogger sysLogger(DAEMON_NAME);
|
CSystemLogger sysLogger(DAEMON_NAME);
|
||||||
|
|
||||||
// have to cancel this thread to quit
|
|
||||||
s_taskBarReceiver->setQuitJob(new CQuitJob(CThread::getCurrentThread()));
|
|
||||||
|
|
||||||
// catch errors that would normally exit
|
// catch errors that would normally exit
|
||||||
bye = &byeThrow;
|
bye = &byeThrow;
|
||||||
|
|
||||||
|
@ -768,7 +903,6 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
|
||||||
// through the task bar.
|
// through the task bar.
|
||||||
s_taskBarReceiver = new CMSWindowsServerTaskBarReceiver(instance,
|
s_taskBarReceiver = new CMSWindowsServerTaskBarReceiver(instance,
|
||||||
&logBuffer);
|
&logBuffer);
|
||||||
s_taskBarReceiver->setQuitJob(new CQuitJob(CThread::getCurrentThread()));
|
|
||||||
|
|
||||||
int result;
|
int result;
|
||||||
try {
|
try {
|
||||||
|
@ -817,15 +951,20 @@ main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
CArch arch;
|
CArch arch;
|
||||||
CLOG;
|
CLOG;
|
||||||
CArgs args;
|
|
||||||
|
// go really fast
|
||||||
|
CThread::getCurrentThread().setPriority(-14);
|
||||||
|
|
||||||
|
CSocketMultiplexer multiplexer;
|
||||||
|
CEventQueue eventQueue;
|
||||||
|
|
||||||
// get program name
|
// get program name
|
||||||
|
CArgs args;
|
||||||
ARG->m_pname = ARCH->getBasename(argv[0]);
|
ARG->m_pname = ARCH->getBasename(argv[0]);
|
||||||
|
|
||||||
// make the task bar receiver. the user can control this app
|
// make the task bar receiver. the user can control this app
|
||||||
// through the task bar.
|
// through the task bar.
|
||||||
s_taskBarReceiver = new CXWindowsServerTaskBarReceiver;
|
s_taskBarReceiver = new CXWindowsServerTaskBarReceiver;
|
||||||
s_taskBarReceiver->setQuitJob(new CQuitJob(CThread::getCurrentThread()));
|
|
||||||
|
|
||||||
// parse command line
|
// parse command line
|
||||||
parse(argc, argv);
|
parse(argc, argv);
|
||||||
|
|
|
@ -555,6 +555,12 @@ CArch::isAnyAddr(CArchNetAddress addr)
|
||||||
return m_net->isAnyAddr(addr);
|
return m_net->isAnyAddr(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CArch::isEqualAddr(CArchNetAddress a, CArchNetAddress b)
|
||||||
|
{
|
||||||
|
return m_net->isEqualAddr(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CArch::sleep(double timeout)
|
CArch::sleep(double timeout)
|
||||||
{
|
{
|
||||||
|
|
|
@ -153,6 +153,7 @@ public:
|
||||||
virtual void setAddrPort(CArchNetAddress, int port);
|
virtual void setAddrPort(CArchNetAddress, int port);
|
||||||
virtual int getAddrPort(CArchNetAddress);
|
virtual int getAddrPort(CArchNetAddress);
|
||||||
virtual bool isAnyAddr(CArchNetAddress);
|
virtual bool isAnyAddr(CArchNetAddress);
|
||||||
|
virtual bool isEqualAddr(CArchNetAddress, CArchNetAddress);
|
||||||
|
|
||||||
// IArchSleep overrides
|
// IArchSleep overrides
|
||||||
virtual void sleep(double timeout);
|
virtual void sleep(double timeout);
|
||||||
|
|
|
@ -575,6 +575,7 @@ CArchMultithreadPosix::interrupt()
|
||||||
lockMutex(m_threadMutex);
|
lockMutex(m_threadMutex);
|
||||||
if (m_signalFunc != NULL) {
|
if (m_signalFunc != NULL) {
|
||||||
m_signalFunc(m_signalUserData);
|
m_signalFunc(m_signalUserData);
|
||||||
|
pthread_kill(m_mainThread->m_thread, SIGWAKEUP);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ARCH->cancelThread(m_mainThread);
|
ARCH->cancelThread(m_mainThread);
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#if HAVE_POLL
|
#if HAVE_POLL
|
||||||
# include <sys/poll.h>
|
# include <sys/poll.h>
|
||||||
|
@ -750,6 +751,13 @@ CArchNetworkBSD::isAnyAddr(CArchNetAddress addr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CArchNetworkBSD::isEqualAddr(CArchNetAddress a, CArchNetAddress b)
|
||||||
|
{
|
||||||
|
return (a->m_len == b->m_len &&
|
||||||
|
memcmp(&a->m_addr, &b->m_addr, a->m_len) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CArchNetworkBSD::throwError(int err)
|
CArchNetworkBSD::throwError(int err)
|
||||||
{
|
{
|
||||||
|
|
|
@ -77,6 +77,7 @@ public:
|
||||||
virtual void setAddrPort(CArchNetAddress, int port);
|
virtual void setAddrPort(CArchNetAddress, int port);
|
||||||
virtual int getAddrPort(CArchNetAddress);
|
virtual int getAddrPort(CArchNetAddress);
|
||||||
virtual bool isAnyAddr(CArchNetAddress);
|
virtual bool isAnyAddr(CArchNetAddress);
|
||||||
|
virtual bool isEqualAddr(CArchNetAddress, CArchNetAddress);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void throwError(int);
|
void throwError(int);
|
||||||
|
|
|
@ -265,6 +265,9 @@ public:
|
||||||
//! Get the port of an address
|
//! Get the port of an address
|
||||||
virtual int getAddrPort(CArchNetAddress) = 0;
|
virtual int getAddrPort(CArchNetAddress) = 0;
|
||||||
|
|
||||||
|
//! Test addresses for equality
|
||||||
|
virtual bool isEqualAddr(CArchNetAddress, CArchNetAddress) = 0;
|
||||||
|
|
||||||
//! Test for the "any" address
|
//! Test for the "any" address
|
||||||
/*!
|
/*!
|
||||||
Returns true if \c addr is the "any" address. \c newAnyAddr()
|
Returns true if \c addr is the "any" address. \c newAnyAddr()
|
||||||
|
|
|
@ -56,7 +56,6 @@ ARCH_STRING::vsnprintf(char* str, int size, const char* fmt, va_list ap)
|
||||||
|
|
||||||
#else // !HAVE_VSNPRINTF && !UNIX_LIKE
|
#else // !HAVE_VSNPRINTF && !UNIX_LIKE
|
||||||
|
|
||||||
// FIXME
|
|
||||||
#error vsnprintf not implemented
|
#error vsnprintf not implemented
|
||||||
|
|
||||||
#endif // !HAVE_VSNPRINTF
|
#endif // !HAVE_VSNPRINTF
|
||||||
|
|
|
@ -13,13 +13,12 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "CEvent.h"
|
#include "CEvent.h"
|
||||||
|
#include "CEventQueue.h"
|
||||||
|
|
||||||
//
|
//
|
||||||
// CEvent
|
// CEvent
|
||||||
//
|
//
|
||||||
|
|
||||||
CEvent::Type CEvent::s_nextType = kLast;
|
|
||||||
|
|
||||||
CEvent::CEvent() :
|
CEvent::CEvent() :
|
||||||
m_type(kUnknown),
|
m_type(kUnknown),
|
||||||
m_target(NULL),
|
m_target(NULL),
|
||||||
|
@ -55,20 +54,21 @@ CEvent::getData() const
|
||||||
}
|
}
|
||||||
|
|
||||||
CEvent::Type
|
CEvent::Type
|
||||||
CEvent::registerType()
|
CEvent::registerType(const char* name)
|
||||||
{
|
{
|
||||||
// FIXME -- lock mutex (need a mutex)
|
return EVENTQUEUE->registerType(name);
|
||||||
return s_nextType++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CEvent::Type
|
CEvent::Type
|
||||||
CEvent::registerTypeOnce(Type& type)
|
CEvent::registerTypeOnce(Type& type, const char* name)
|
||||||
{
|
{
|
||||||
// FIXME -- lock mutex (need a mutex)
|
return EVENTQUEUE->registerTypeOnce(type, name);
|
||||||
if (type == CEvent::kUnknown) {
|
|
||||||
type = s_nextType++;
|
|
||||||
}
|
}
|
||||||
return type;
|
|
||||||
|
const char*
|
||||||
|
CEvent::getTypeName(Type type)
|
||||||
|
{
|
||||||
|
return EVENTQUEUE->getTypeName(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#define CEVENT_H
|
#define CEVENT_H
|
||||||
|
|
||||||
#include "BasicTypes.h"
|
#include "BasicTypes.h"
|
||||||
|
#include "stdmap.h"
|
||||||
|
|
||||||
//! Event
|
//! Event
|
||||||
/*!
|
/*!
|
||||||
|
@ -46,6 +47,33 @@ public:
|
||||||
//! @name manipulators
|
//! @name manipulators
|
||||||
//@{
|
//@{
|
||||||
|
|
||||||
|
//! Creates a new event type
|
||||||
|
/*!
|
||||||
|
Returns a unique event type id.
|
||||||
|
*/
|
||||||
|
static Type registerType(const char* name);
|
||||||
|
|
||||||
|
//! Creates a new event type
|
||||||
|
/*!
|
||||||
|
If \p type contains \c kUnknown then it is set to a unique event
|
||||||
|
type id otherwise it is left alone. The final value of \p type
|
||||||
|
is returned.
|
||||||
|
*/
|
||||||
|
static Type registerTypeOnce(Type& type, const char* name);
|
||||||
|
|
||||||
|
//! Get name for event
|
||||||
|
/*!
|
||||||
|
Returns the name for the event \p type. This is primarily for
|
||||||
|
debugging.
|
||||||
|
*/
|
||||||
|
static const char* getTypeName(Type type);
|
||||||
|
|
||||||
|
//! Release event data
|
||||||
|
/*!
|
||||||
|
Deletes event data for the given event.
|
||||||
|
*/
|
||||||
|
static void deleteData(const CEvent&);
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
//! @name accessors
|
//! @name accessors
|
||||||
//@{
|
//@{
|
||||||
|
@ -68,33 +96,12 @@ public:
|
||||||
*/
|
*/
|
||||||
void* getData() const;
|
void* getData() const;
|
||||||
|
|
||||||
//! Creates a new event type
|
|
||||||
/*!
|
|
||||||
Returns a unique event type id.
|
|
||||||
*/
|
|
||||||
static Type registerType();
|
|
||||||
|
|
||||||
//! Creates a new event type
|
|
||||||
/*!
|
|
||||||
If \p type contains \c kUnknown then it is set to a unique event
|
|
||||||
type id otherwise it is left alone. The final value of \p type
|
|
||||||
is returned.
|
|
||||||
*/
|
|
||||||
static Type registerTypeOnce(Type& type);
|
|
||||||
|
|
||||||
//! Release event data
|
|
||||||
/*!
|
|
||||||
Deletes event data for the given event.
|
|
||||||
*/
|
|
||||||
static void deleteData(const CEvent&);
|
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Type m_type;
|
Type m_type;
|
||||||
void* m_target;
|
void* m_target;
|
||||||
void* m_data;
|
void* m_data;
|
||||||
static Type s_nextType;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -13,7 +13,9 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "CEventQueue.h"
|
#include "CEventQueue.h"
|
||||||
|
#include "CLog.h"
|
||||||
#include "CSimpleEventQueueBuffer.h"
|
#include "CSimpleEventQueueBuffer.h"
|
||||||
|
#include "CStopwatch.h"
|
||||||
#include "IEventJob.h"
|
#include "IEventJob.h"
|
||||||
#include "CArch.h"
|
#include "CArch.h"
|
||||||
|
|
||||||
|
@ -30,7 +32,8 @@ interrupt(void*)
|
||||||
// CEventQueue
|
// CEventQueue
|
||||||
//
|
//
|
||||||
|
|
||||||
CEventQueue::CEventQueue()
|
CEventQueue::CEventQueue() :
|
||||||
|
m_nextType(CEvent::kLast)
|
||||||
{
|
{
|
||||||
setInstance(this);
|
setInstance(this);
|
||||||
m_mutex = ARCH->newMutex();
|
m_mutex = ARCH->newMutex();
|
||||||
|
@ -46,6 +49,54 @@ CEventQueue::~CEventQueue()
|
||||||
setInstance(NULL);
|
setInstance(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CEvent::Type
|
||||||
|
CEventQueue::registerType(const char* name)
|
||||||
|
{
|
||||||
|
CArchMutexLock lock(m_mutex);
|
||||||
|
m_typeMap.insert(std::make_pair(m_nextType, name));
|
||||||
|
LOG((CLOG_DEBUG1 "registered event type %s as %d", name, m_nextType));
|
||||||
|
return m_nextType++;
|
||||||
|
}
|
||||||
|
|
||||||
|
CEvent::Type
|
||||||
|
CEventQueue::registerTypeOnce(CEvent::Type& type, const char* name)
|
||||||
|
{
|
||||||
|
CArchMutexLock lock(m_mutex);
|
||||||
|
if (type == CEvent::kUnknown) {
|
||||||
|
m_typeMap.insert(std::make_pair(m_nextType, name));
|
||||||
|
LOG((CLOG_DEBUG1 "registered event type %s as %d", name, m_nextType));
|
||||||
|
type = m_nextType++;
|
||||||
|
}
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char*
|
||||||
|
CEventQueue::getTypeName(CEvent::Type type)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case CEvent::kUnknown:
|
||||||
|
return "nil";
|
||||||
|
|
||||||
|
case CEvent::kQuit:
|
||||||
|
return "quit";
|
||||||
|
|
||||||
|
case CEvent::kSystem:
|
||||||
|
return "system";
|
||||||
|
|
||||||
|
case CEvent::kTimer:
|
||||||
|
return "timer";
|
||||||
|
|
||||||
|
default:
|
||||||
|
CTypeMap::const_iterator i = m_typeMap.find(type);
|
||||||
|
if (i == m_typeMap.end()) {
|
||||||
|
return "<unknown>";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return i->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CEventQueue::adoptBuffer(IEventQueueBuffer* buffer)
|
CEventQueue::adoptBuffer(IEventQueueBuffer* buffer)
|
||||||
{
|
{
|
||||||
|
@ -69,34 +120,44 @@ CEventQueue::adoptBuffer(IEventQueueBuffer* buffer)
|
||||||
bool
|
bool
|
||||||
CEventQueue::getEvent(CEvent& event, double timeout)
|
CEventQueue::getEvent(CEvent& event, double timeout)
|
||||||
{
|
{
|
||||||
|
CStopwatch timer(true);
|
||||||
|
retry:
|
||||||
// if no events are waiting then handle timers and then wait
|
// if no events are waiting then handle timers and then wait
|
||||||
if (m_buffer->isEmpty()) {
|
while (m_buffer->isEmpty()) {
|
||||||
// handle timers first
|
// handle timers first
|
||||||
if (hasTimerExpired(event)) {
|
if (hasTimerExpired(event)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get time remaining in timeout
|
||||||
|
double timeLeft = timeout - timer.getTime();
|
||||||
|
if (timeout >= 0.0 && timeLeft <= 0.0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// get time until next timer expires. if there is a timer
|
// get time until next timer expires. if there is a timer
|
||||||
// and it'll expire before the client's timeout then use
|
// and it'll expire before the client's timeout then use
|
||||||
// that duration for our timeout instead.
|
// that duration for our timeout instead.
|
||||||
double timerTimeout = getNextTimerTimeout();
|
double timerTimeout = getNextTimerTimeout();
|
||||||
if (timerTimeout >= 0.0 && timerTimeout < timeout) {
|
if (timeout < 0.0 || (timerTimeout >= 0.0 && timerTimeout < timeLeft)) {
|
||||||
timeout = timerTimeout;
|
timeLeft = timerTimeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
// wait for an event
|
// wait for an event
|
||||||
m_buffer->waitForEvent(timeout);
|
m_buffer->waitForEvent(timeLeft);
|
||||||
}
|
|
||||||
|
|
||||||
// if no events are pending then do the timers
|
|
||||||
if (m_buffer->isEmpty()) {
|
|
||||||
return hasTimerExpired(event);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get the event
|
||||||
UInt32 dataID;
|
UInt32 dataID;
|
||||||
IEventQueueBuffer::Type type = m_buffer->getEvent(event, dataID);
|
IEventQueueBuffer::Type type = m_buffer->getEvent(event, dataID);
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case IEventQueueBuffer::kNone:
|
case IEventQueueBuffer::kNone:
|
||||||
|
if (timeout < 0.0 || timeout <= timer.getTime()) {
|
||||||
|
// don't want to fail if client isn't expecting that
|
||||||
|
// so if getEvent() fails with an infinite timeout
|
||||||
|
// then just try getting another event.
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
case IEventQueueBuffer::kSystem:
|
case IEventQueueBuffer::kSystem:
|
||||||
|
@ -156,9 +217,16 @@ CEventQueue::newTimer(double duration, void* target)
|
||||||
assert(duration > 0.0);
|
assert(duration > 0.0);
|
||||||
|
|
||||||
CEventQueueTimer* timer = m_buffer->newTimer(duration, false);
|
CEventQueueTimer* timer = m_buffer->newTimer(duration, false);
|
||||||
|
if (target == NULL) {
|
||||||
|
target = timer;
|
||||||
|
}
|
||||||
CArchMutexLock lock(m_mutex);
|
CArchMutexLock lock(m_mutex);
|
||||||
m_timers.insert(timer);
|
m_timers.insert(timer);
|
||||||
m_timerQueue.push(CTimer(timer, duration, target, false));
|
// initial duration is requested duration plus whatever's on
|
||||||
|
// the clock currently because the latter will be subtracted
|
||||||
|
// the next time we check for timers.
|
||||||
|
m_timerQueue.push(CTimer(timer, duration,
|
||||||
|
duration + m_time.getTime(), target, false));
|
||||||
return timer;
|
return timer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,9 +236,16 @@ CEventQueue::newOneShotTimer(double duration, void* target)
|
||||||
assert(duration > 0.0);
|
assert(duration > 0.0);
|
||||||
|
|
||||||
CEventQueueTimer* timer = m_buffer->newTimer(duration, true);
|
CEventQueueTimer* timer = m_buffer->newTimer(duration, true);
|
||||||
|
if (target == NULL) {
|
||||||
|
target = timer;
|
||||||
|
}
|
||||||
CArchMutexLock lock(m_mutex);
|
CArchMutexLock lock(m_mutex);
|
||||||
m_timers.insert(timer);
|
m_timers.insert(timer);
|
||||||
m_timerQueue.push(CTimer(timer, duration, target, true));
|
// initial duration is requested duration plus whatever's on
|
||||||
|
// the clock currently because the latter will be subtracted
|
||||||
|
// the next time we check for timers.
|
||||||
|
m_timerQueue.push(CTimer(timer, duration,
|
||||||
|
duration + m_time.getTime(), target, true));
|
||||||
return timer;
|
return timer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -401,13 +476,13 @@ CEventQueue::CTypeTarget::operator<(const CTypeTarget& tt) const
|
||||||
// CEventQueue::CTimer
|
// CEventQueue::CTimer
|
||||||
//
|
//
|
||||||
|
|
||||||
CEventQueue::CTimer::CTimer(CEventQueueTimer* timer,
|
CEventQueue::CTimer::CTimer(CEventQueueTimer* timer, double timeout,
|
||||||
double timeout, void* target, bool oneShot) :
|
double initialTime, void* target, bool oneShot) :
|
||||||
m_timer(timer),
|
m_timer(timer),
|
||||||
m_timeout(timeout),
|
m_timeout(timeout),
|
||||||
m_target(target),
|
m_target(target),
|
||||||
m_oneShot(oneShot),
|
m_oneShot(oneShot),
|
||||||
m_time(timeout)
|
m_time(initialTime)
|
||||||
{
|
{
|
||||||
assert(m_timeout > 0.0);
|
assert(m_timeout > 0.0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,9 +39,9 @@ public:
|
||||||
virtual bool dispatchEvent(const CEvent& event);
|
virtual bool dispatchEvent(const CEvent& event);
|
||||||
virtual void addEvent(const CEvent& event);
|
virtual void addEvent(const CEvent& event);
|
||||||
virtual CEventQueueTimer*
|
virtual CEventQueueTimer*
|
||||||
newTimer(double duration, void* target = NULL);
|
newTimer(double duration, void* target);
|
||||||
virtual CEventQueueTimer*
|
virtual CEventQueueTimer*
|
||||||
newOneShotTimer(double duration, void* target = NULL);
|
newOneShotTimer(double duration, void* target);
|
||||||
virtual void deleteTimer(CEventQueueTimer*);
|
virtual void deleteTimer(CEventQueueTimer*);
|
||||||
virtual void adoptHandler(void* target, IEventJob* dispatcher);
|
virtual void adoptHandler(void* target, IEventJob* dispatcher);
|
||||||
virtual void adoptHandler(CEvent::Type type,
|
virtual void adoptHandler(CEvent::Type type,
|
||||||
|
@ -50,8 +50,13 @@ public:
|
||||||
virtual IEventJob* orphanHandler(CEvent::Type type, void* target);
|
virtual IEventJob* orphanHandler(CEvent::Type type, void* target);
|
||||||
virtual void removeHandler(void* target);
|
virtual void removeHandler(void* target);
|
||||||
virtual void removeHandler(CEvent::Type type, void* target);
|
virtual void removeHandler(CEvent::Type type, void* target);
|
||||||
|
virtual CEvent::Type
|
||||||
|
registerType(const char* name);
|
||||||
|
virtual CEvent::Type
|
||||||
|
registerTypeOnce(CEvent::Type& type, const char* name);
|
||||||
virtual bool isEmpty() const;
|
virtual bool isEmpty() const;
|
||||||
virtual IEventJob* getHandler(CEvent::Type type, void* target) const;
|
virtual IEventJob* getHandler(CEvent::Type type, void* target) const;
|
||||||
|
virtual const char* getTypeName(CEvent::Type type);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void doAdoptHandler(CEvent::Type type,
|
void doAdoptHandler(CEvent::Type type,
|
||||||
|
@ -77,7 +82,8 @@ private:
|
||||||
};
|
};
|
||||||
class CTimer {
|
class CTimer {
|
||||||
public:
|
public:
|
||||||
CTimer(CEventQueueTimer*, double timeout, void* target, bool oneShot);
|
CTimer(CEventQueueTimer*, double timeout, double initialTime,
|
||||||
|
void* target, bool oneShot);
|
||||||
~CTimer();
|
~CTimer();
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
|
@ -106,19 +112,28 @@ private:
|
||||||
typedef std::map<UInt32, CEvent> CEventTable;
|
typedef std::map<UInt32, CEvent> CEventTable;
|
||||||
typedef std::vector<UInt32> CEventIDList;
|
typedef std::vector<UInt32> CEventIDList;
|
||||||
typedef std::map<CTypeTarget, IEventJob*> CHandlerTable;
|
typedef std::map<CTypeTarget, IEventJob*> CHandlerTable;
|
||||||
|
typedef std::map<CEvent::Type, const char*> CTypeMap;
|
||||||
|
|
||||||
CArchMutex m_mutex;
|
CArchMutex m_mutex;
|
||||||
|
|
||||||
|
// registered events
|
||||||
|
CEvent::Type m_nextType;
|
||||||
|
CTypeMap m_typeMap;
|
||||||
|
|
||||||
|
// buffer of events
|
||||||
IEventQueueBuffer* m_buffer;
|
IEventQueueBuffer* m_buffer;
|
||||||
|
|
||||||
|
// saved events
|
||||||
CEventTable m_events;
|
CEventTable m_events;
|
||||||
CEventIDList m_oldEventIDs;
|
CEventIDList m_oldEventIDs;
|
||||||
|
|
||||||
|
// timers
|
||||||
CStopwatch m_time;
|
CStopwatch m_time;
|
||||||
CTimers m_timers;
|
CTimers m_timers;
|
||||||
CTimerQueue m_timerQueue;
|
CTimerQueue m_timerQueue;
|
||||||
CTimerEvent m_timerEvent;
|
CTimerEvent m_timerEvent;
|
||||||
|
|
||||||
|
// event handlers
|
||||||
CHandlerTable m_handlers;
|
CHandlerTable m_handlers;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,97 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2004 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* This package is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* found in the file COPYING that should have accompanied this file.
|
||||||
|
*
|
||||||
|
* This package is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "CSimpleEventQueueBuffer.h"
|
||||||
|
#include "CStopwatch.h"
|
||||||
|
#include "CArch.h"
|
||||||
|
|
||||||
|
class CEventQueueTimer { };
|
||||||
|
|
||||||
|
//
|
||||||
|
// CSimpleEventQueueBuffer
|
||||||
|
//
|
||||||
|
|
||||||
|
CSimpleEventQueueBuffer::CSimpleEventQueueBuffer()
|
||||||
|
{
|
||||||
|
m_queueMutex = ARCH->newMutex();
|
||||||
|
m_queueReadyCond = ARCH->newCondVar();
|
||||||
|
m_queueReady = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
CSimpleEventQueueBuffer::~CSimpleEventQueueBuffer()
|
||||||
|
{
|
||||||
|
ARCH->closeCondVar(m_queueReadyCond);
|
||||||
|
ARCH->closeMutex(m_queueMutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CSimpleEventQueueBuffer::waitForEvent(double timeout)
|
||||||
|
{
|
||||||
|
CArchMutexLock lock(m_queueMutex);
|
||||||
|
CStopwatch timer(true);
|
||||||
|
while (!m_queueReady) {
|
||||||
|
double timeLeft = timeout;
|
||||||
|
if (timeLeft >= 0.0) {
|
||||||
|
timeLeft -= timer.getTime();
|
||||||
|
if (timeLeft < 0.0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ARCH->waitCondVar(m_queueReadyCond, m_queueMutex, timeLeft);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IEventQueueBuffer::Type
|
||||||
|
CSimpleEventQueueBuffer::getEvent(CEvent& event, UInt32& dataID)
|
||||||
|
{
|
||||||
|
CArchMutexLock lock(m_queueMutex);
|
||||||
|
if (!m_queueReady) {
|
||||||
|
return kNone;
|
||||||
|
}
|
||||||
|
dataID = m_queue.back();
|
||||||
|
m_queue.pop_back();
|
||||||
|
m_queueReady = !m_queue.empty();
|
||||||
|
return kUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CSimpleEventQueueBuffer::addEvent(UInt32 dataID)
|
||||||
|
{
|
||||||
|
CArchMutexLock lock(m_queueMutex);
|
||||||
|
m_queue.push_front(dataID);
|
||||||
|
if (!m_queueReady) {
|
||||||
|
m_queueReady = true;
|
||||||
|
ARCH->broadcastCondVar(m_queueReadyCond);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CSimpleEventQueueBuffer::isEmpty() const
|
||||||
|
{
|
||||||
|
CArchMutexLock lock(m_queueMutex);
|
||||||
|
return !m_queueReady;
|
||||||
|
}
|
||||||
|
|
||||||
|
CEventQueueTimer*
|
||||||
|
CSimpleEventQueueBuffer::newTimer(double, bool) const
|
||||||
|
{
|
||||||
|
return new CEventQueueTimer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CSimpleEventQueueBuffer::deleteTimer(CEventQueueTimer* timer) const
|
||||||
|
{
|
||||||
|
delete timer;
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2004 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* This package is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* found in the file COPYING that should have accompanied this file.
|
||||||
|
*
|
||||||
|
* This package is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CSIMPLEEVENTQUEUEBUFFER_H
|
||||||
|
#define CSIMPLEEVENTQUEUEBUFFER_H
|
||||||
|
|
||||||
|
#include "IEventQueueBuffer.h"
|
||||||
|
#include "IArchMultithread.h"
|
||||||
|
#include "stddeque.h"
|
||||||
|
|
||||||
|
//! In-memory event queue buffer
|
||||||
|
/*!
|
||||||
|
An event queue buffer provides a queue of events for an IEventQueue.
|
||||||
|
*/
|
||||||
|
class CSimpleEventQueueBuffer : public IEventQueueBuffer {
|
||||||
|
public:
|
||||||
|
CSimpleEventQueueBuffer();
|
||||||
|
~CSimpleEventQueueBuffer();
|
||||||
|
|
||||||
|
// IEventQueueBuffer overrides
|
||||||
|
virtual void waitForEvent(double timeout);
|
||||||
|
virtual Type getEvent(CEvent& event, UInt32& dataID);
|
||||||
|
virtual bool addEvent(UInt32 dataID);
|
||||||
|
virtual bool isEmpty() const;
|
||||||
|
virtual CEventQueueTimer*
|
||||||
|
newTimer(double duration, bool oneShot) const;
|
||||||
|
virtual void deleteTimer(CEventQueueTimer*) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef std::deque<UInt32> CEventDeque;
|
||||||
|
|
||||||
|
CArchMutex m_queueMutex;
|
||||||
|
CArchCond m_queueReadyCond;
|
||||||
|
bool m_queueReady;
|
||||||
|
CEventDeque m_queue;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -176,7 +176,7 @@ CStringUtil::CaselessCmp::cmpEqual(
|
||||||
const CString::value_type& a,
|
const CString::value_type& a,
|
||||||
const CString::value_type& b)
|
const CString::value_type& b)
|
||||||
{
|
{
|
||||||
// FIXME -- use std::tolower but not in all versions of libstdc++ have it
|
// should use std::tolower but not in all versions of libstdc++ have it
|
||||||
return tolower(a) == tolower(b);
|
return tolower(a) == tolower(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,7 +185,7 @@ CStringUtil::CaselessCmp::cmpLess(
|
||||||
const CString::value_type& a,
|
const CString::value_type& a,
|
||||||
const CString::value_type& b)
|
const CString::value_type& b)
|
||||||
{
|
{
|
||||||
// FIXME -- use std::tolower but not in all versions of libstdc++ have it
|
// should use std::tolower but not in all versions of libstdc++ have it
|
||||||
return tolower(a) < tolower(b);
|
return tolower(a) < tolower(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -80,7 +80,8 @@ public:
|
||||||
is returned the data points to a \c CTimerEvent. The client must pass
|
is returned the data points to a \c CTimerEvent. The client must pass
|
||||||
the returned timer to \c deleteTimer() (whether or not the timer has
|
the returned timer to \c deleteTimer() (whether or not the timer has
|
||||||
expired) to release the timer. The returned timer event uses the
|
expired) to release the timer. The returned timer event uses the
|
||||||
given \p target.
|
given \p target. If \p target is NULL it uses the returned timer as
|
||||||
|
the target.
|
||||||
|
|
||||||
Events for a single timer don't accumulate in the queue, even if the
|
Events for a single timer don't accumulate in the queue, even if the
|
||||||
client reading events can't keep up. Instead, the \c m_count member
|
client reading events can't keep up. Instead, the \c m_count member
|
||||||
|
@ -89,7 +90,7 @@ public:
|
||||||
removed (or since the timer was added).
|
removed (or since the timer was added).
|
||||||
*/
|
*/
|
||||||
virtual CEventQueueTimer*
|
virtual CEventQueueTimer*
|
||||||
newTimer(double duration, void* target = NULL) = 0;
|
newTimer(double duration, void* target) = 0;
|
||||||
|
|
||||||
//! Create a one-shot timer
|
//! Create a one-shot timer
|
||||||
/*!
|
/*!
|
||||||
|
@ -99,11 +100,12 @@ public:
|
||||||
The \m c_count member of the \c CTimerEvent is always 1. The client
|
The \m c_count member of the \c CTimerEvent is always 1. The client
|
||||||
must pass the returned timer to \c deleteTimer() (whether or not the
|
must pass the returned timer to \c deleteTimer() (whether or not the
|
||||||
timer has expired) to release the timer. The returned timer event
|
timer has expired) to release the timer. The returned timer event
|
||||||
uses the given \p target.
|
uses the given \p target. If \p target is NULL it uses the returned
|
||||||
|
timer as the target.
|
||||||
*/
|
*/
|
||||||
virtual CEventQueueTimer*
|
virtual CEventQueueTimer*
|
||||||
newOneShotTimer(double duration,
|
newOneShotTimer(double duration,
|
||||||
void* target = NULL) = 0;
|
void* target) = 0;
|
||||||
|
|
||||||
//! Destroy a timer
|
//! Destroy a timer
|
||||||
/*!
|
/*!
|
||||||
|
@ -160,6 +162,23 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual void removeHandler(CEvent::Type type, void* target) = 0;
|
virtual void removeHandler(CEvent::Type type, void* target) = 0;
|
||||||
|
|
||||||
|
//! Creates a new event type
|
||||||
|
/*!
|
||||||
|
Returns a unique event type id.
|
||||||
|
*/
|
||||||
|
virtual CEvent::Type
|
||||||
|
registerType(const char* name) = 0;
|
||||||
|
|
||||||
|
//! Creates a new event type
|
||||||
|
/*!
|
||||||
|
If \p type contains \c kUnknown then it is set to a unique event
|
||||||
|
type id otherwise it is left alone. The final value of \p type
|
||||||
|
is returned.
|
||||||
|
*/
|
||||||
|
virtual CEvent::Type
|
||||||
|
registerTypeOnce(CEvent::Type& type,
|
||||||
|
const char* name) = 0;
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
//! @name accessors
|
//! @name accessors
|
||||||
//@{
|
//@{
|
||||||
|
@ -179,6 +198,13 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual IEventJob* getHandler(CEvent::Type type, void* target) const = 0;
|
virtual IEventJob* getHandler(CEvent::Type type, void* target) const = 0;
|
||||||
|
|
||||||
|
//! Get name for event
|
||||||
|
/*!
|
||||||
|
Returns the name for the event \p type. This is primarily for
|
||||||
|
debugging.
|
||||||
|
*/
|
||||||
|
virtual const char* getTypeName(CEvent::Type type) = 0;
|
||||||
|
|
||||||
//! Get the system event type target
|
//! Get the system event type target
|
||||||
/*!
|
/*!
|
||||||
Returns the target to use for dispatching \c CEvent::kSystem events.
|
Returns the target to use for dispatching \c CEvent::kSystem events.
|
||||||
|
|
|
@ -0,0 +1,94 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2004 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* This package is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* found in the file COPYING that should have accompanied this file.
|
||||||
|
*
|
||||||
|
* This package is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef IEVENTQUEUEBUFFER_H
|
||||||
|
#define IEVENTQUEUEBUFFER_H
|
||||||
|
|
||||||
|
#include "IInterface.h"
|
||||||
|
#include "BasicTypes.h"
|
||||||
|
|
||||||
|
class CEvent;
|
||||||
|
class CEventQueueTimer;
|
||||||
|
|
||||||
|
//! Event queue buffer interface
|
||||||
|
/*!
|
||||||
|
An event queue buffer provides a queue of events for an IEventQueue.
|
||||||
|
*/
|
||||||
|
class IEventQueueBuffer : public IInterface {
|
||||||
|
public:
|
||||||
|
enum Type {
|
||||||
|
kNone, //!< No event is available
|
||||||
|
kSystem, //!< Event is a system event
|
||||||
|
kUser //!< Event is a user event
|
||||||
|
};
|
||||||
|
|
||||||
|
//! @name manipulators
|
||||||
|
//@{
|
||||||
|
|
||||||
|
//! Block waiting for an event
|
||||||
|
/*!
|
||||||
|
Wait for an event in the event queue buffer for up to \p timeout
|
||||||
|
seconds.
|
||||||
|
*/
|
||||||
|
virtual void waitForEvent(double timeout) = 0;
|
||||||
|
|
||||||
|
//! Get the next event
|
||||||
|
/*!
|
||||||
|
Get the next event from the buffer. Return kNone if no event is
|
||||||
|
available. If a system event is next, return kSystem and fill in
|
||||||
|
event. The event data in a system event can point to a static
|
||||||
|
buffer (because CEvent::deleteData() will not attempt to delete
|
||||||
|
data in a kSystem event). Otherwise, return kUser and fill in
|
||||||
|
\p dataID with the value passed to \c addEvent().
|
||||||
|
*/
|
||||||
|
virtual Type getEvent(CEvent& event, UInt32& dataID) = 0;
|
||||||
|
|
||||||
|
//! Post an event
|
||||||
|
/*!
|
||||||
|
Add the given event to the end of the queue buffer. This is a user
|
||||||
|
event and \c getEvent() must be able to identify it as such and
|
||||||
|
return \p dataID. This method must cause \c waitForEvent() to
|
||||||
|
return at some future time if it's blocked waiting on an event.
|
||||||
|
*/
|
||||||
|
virtual bool addEvent(UInt32 dataID) = 0;
|
||||||
|
|
||||||
|
//@}
|
||||||
|
//! @name accessors
|
||||||
|
//@{
|
||||||
|
|
||||||
|
//! Check if event queue buffer is empty
|
||||||
|
/*!
|
||||||
|
Return true iff the event queue buffer is empty.
|
||||||
|
*/
|
||||||
|
virtual bool isEmpty() const = 0;
|
||||||
|
|
||||||
|
//! Create a timer object
|
||||||
|
/*!
|
||||||
|
Create and return a timer object. The object is opaque and is
|
||||||
|
used only by the buffer but it must be a valid object (i.e.
|
||||||
|
not NULL).
|
||||||
|
*/
|
||||||
|
virtual CEventQueueTimer*
|
||||||
|
newTimer(double duration, bool oneShot) const = 0;
|
||||||
|
|
||||||
|
//! Destroy a timer object
|
||||||
|
/*!
|
||||||
|
Destroy a timer object previously returned by \c newTimer().
|
||||||
|
*/
|
||||||
|
virtual void deleteTimer(CEventQueueTimer*) const = 0;
|
||||||
|
|
||||||
|
//@}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -27,29 +27,34 @@ CEvent::Type IStream::s_outputShutdownEvent = CEvent::kUnknown;
|
||||||
CEvent::Type
|
CEvent::Type
|
||||||
IStream::getInputReadyEvent()
|
IStream::getInputReadyEvent()
|
||||||
{
|
{
|
||||||
return CEvent::registerTypeOnce(s_inputReadyEvent);
|
return CEvent::registerTypeOnce(s_inputReadyEvent,
|
||||||
|
"IStream::inputReady");
|
||||||
}
|
}
|
||||||
|
|
||||||
CEvent::Type
|
CEvent::Type
|
||||||
IStream::getOutputFlushedEvent()
|
IStream::getOutputFlushedEvent()
|
||||||
{
|
{
|
||||||
return CEvent::registerTypeOnce(s_outputFlushedEvent);
|
return CEvent::registerTypeOnce(s_outputFlushedEvent,
|
||||||
|
"IStream::outputFlushed");
|
||||||
}
|
}
|
||||||
|
|
||||||
CEvent::Type
|
CEvent::Type
|
||||||
IStream::getOutputErrorEvent()
|
IStream::getOutputErrorEvent()
|
||||||
{
|
{
|
||||||
return CEvent::registerTypeOnce(s_outputErrorEvent);
|
return CEvent::registerTypeOnce(s_outputErrorEvent,
|
||||||
|
"IStream::outputError");
|
||||||
}
|
}
|
||||||
|
|
||||||
CEvent::Type
|
CEvent::Type
|
||||||
IStream::getInputShutdownEvent()
|
IStream::getInputShutdownEvent()
|
||||||
{
|
{
|
||||||
return CEvent::registerTypeOnce(s_inputShutdownEvent);
|
return CEvent::registerTypeOnce(s_inputShutdownEvent,
|
||||||
|
"IStream::inputShutdown");
|
||||||
}
|
}
|
||||||
|
|
||||||
CEvent::Type
|
CEvent::Type
|
||||||
IStream::getOutputShutdownEvent()
|
IStream::getOutputShutdownEvent()
|
||||||
{
|
{
|
||||||
return CEvent::registerTypeOnce(s_outputShutdownEvent);
|
return CEvent::registerTypeOnce(s_outputShutdownEvent,
|
||||||
|
"IStream::outputShutdown");
|
||||||
}
|
}
|
||||||
|
|
|
@ -141,6 +141,18 @@ CNetworkAddress::operator=(const CNetworkAddress& addr)
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CNetworkAddress::operator==(const CNetworkAddress& addr) const
|
||||||
|
{
|
||||||
|
return ARCH->isEqualAddr(m_address, addr.m_address);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CNetworkAddress::operator!=(const CNetworkAddress& addr) const
|
||||||
|
{
|
||||||
|
return !operator==(addr);
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CNetworkAddress::isValid() const
|
CNetworkAddress::isValid() const
|
||||||
{
|
{
|
||||||
|
|
|
@ -55,6 +55,18 @@ public:
|
||||||
//! @name accessors
|
//! @name accessors
|
||||||
//@{
|
//@{
|
||||||
|
|
||||||
|
//! Check address equality
|
||||||
|
/*!
|
||||||
|
Returns true if this address is equal to \p address.
|
||||||
|
*/
|
||||||
|
bool operator==(const CNetworkAddress&) const;
|
||||||
|
|
||||||
|
//! Check address inequality
|
||||||
|
/*!
|
||||||
|
Returns true if this address is not equal to \p address.
|
||||||
|
*/
|
||||||
|
bool operator!=(const CNetworkAddress&) const;
|
||||||
|
|
||||||
//! Check address validity
|
//! Check address validity
|
||||||
/*!
|
/*!
|
||||||
Returns true if this is not the invalid address.
|
Returns true if this is not the invalid address.
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "CLock.h"
|
#include "CLock.h"
|
||||||
#include "CMutex.h"
|
#include "CMutex.h"
|
||||||
#include "CThread.h"
|
#include "CThread.h"
|
||||||
|
#include "CLog.h"
|
||||||
#include "TMethodJob.h"
|
#include "TMethodJob.h"
|
||||||
#include "CArch.h"
|
#include "CArch.h"
|
||||||
#include "XArch.h"
|
#include "XArch.h"
|
||||||
|
@ -207,8 +208,8 @@ CSocketMultiplexer::serviceThread(void*)
|
||||||
// check for status
|
// check for status
|
||||||
status = ARCH->pollSocket(&pfds[0], pfds.size(), -1);
|
status = ARCH->pollSocket(&pfds[0], pfds.size(), -1);
|
||||||
}
|
}
|
||||||
catch (XArchNetwork&) {
|
catch (XArchNetwork& e) {
|
||||||
// FIXME -- uh oh
|
LOG((CLOG_WARN "error in socket multiplexer: %s", e.what().c_str()));
|
||||||
status = 0;
|
status = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -62,6 +62,7 @@ CTCPListenSocket::bind(const CNetworkAddress& addr)
|
||||||
CLock lock(m_mutex);
|
CLock lock(m_mutex);
|
||||||
ARCH->bindSocket(m_socket, addr.getAddress());
|
ARCH->bindSocket(m_socket, addr.getAddress());
|
||||||
ARCH->listenOnSocket(m_socket);
|
ARCH->listenOnSocket(m_socket);
|
||||||
|
ARCH->setBlockingOnSocket(m_socket, false);
|
||||||
CSocketMultiplexer::getInstance()->addSocket(this,
|
CSocketMultiplexer::getInstance()->addSocket(this,
|
||||||
new TSocketMultiplexerMethodJob<CTCPListenSocket>(
|
new TSocketMultiplexerMethodJob<CTCPListenSocket>(
|
||||||
this, &CTCPListenSocket::serviceListening,
|
this, &CTCPListenSocket::serviceListening,
|
||||||
|
@ -102,11 +103,13 @@ IDataSocket*
|
||||||
CTCPListenSocket::accept()
|
CTCPListenSocket::accept()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
IDataSocket* socket =
|
||||||
|
new CTCPSocket(ARCH->acceptSocket(m_socket, NULL));
|
||||||
CSocketMultiplexer::getInstance()->addSocket(this,
|
CSocketMultiplexer::getInstance()->addSocket(this,
|
||||||
new TSocketMultiplexerMethodJob<CTCPListenSocket>(
|
new TSocketMultiplexerMethodJob<CTCPListenSocket>(
|
||||||
this, &CTCPListenSocket::serviceListening,
|
this, &CTCPListenSocket::serviceListening,
|
||||||
m_socket, true, false));
|
m_socket, true, false));
|
||||||
return new CTCPSocket(ARCH->acceptSocket(m_socket, NULL));
|
return socket;
|
||||||
}
|
}
|
||||||
catch (XArchNetwork&) {
|
catch (XArchNetwork&) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "XSocket.h"
|
#include "XSocket.h"
|
||||||
#include "CLock.h"
|
#include "CLock.h"
|
||||||
#include "CEventQueue.h"
|
#include "CEventQueue.h"
|
||||||
|
#include "CLog.h"
|
||||||
#include "IEventJob.h"
|
#include "IEventJob.h"
|
||||||
#include "CArch.h"
|
#include "CArch.h"
|
||||||
#include "XArch.h"
|
#include "XArch.h"
|
||||||
|
@ -102,8 +103,8 @@ CTCPSocket::close()
|
||||||
ARCH->closeSocket(socket);
|
ARCH->closeSocket(socket);
|
||||||
}
|
}
|
||||||
catch (XArchNetwork& e) {
|
catch (XArchNetwork& e) {
|
||||||
// FIXME -- just discard this for now
|
// ignore, there's not much we can do
|
||||||
//throw XSocketIOClose(e.what());
|
LOG((CLOG_WARN "error closing socket: %s", e.what().c_str()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -257,7 +258,6 @@ CTCPSocket::connect(const CNetworkAddress& addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// FIXME -- don't throw if in progress, just return that info
|
|
||||||
ARCH->connectSocket(m_socket, addr.getAddress());
|
ARCH->connectSocket(m_socket, addr.getAddress());
|
||||||
sendSocketEvent(getConnectedEvent());
|
sendSocketEvent(getConnectedEvent());
|
||||||
onConnected();
|
onConnected();
|
||||||
|
@ -281,15 +281,13 @@ CTCPSocket::init()
|
||||||
m_readable = false;
|
m_readable = false;
|
||||||
m_writable = false;
|
m_writable = false;
|
||||||
|
|
||||||
|
try {
|
||||||
// make socket non-blocking
|
// make socket non-blocking
|
||||||
// FIXME -- check for error
|
|
||||||
ARCH->setBlockingOnSocket(m_socket, false);
|
ARCH->setBlockingOnSocket(m_socket, false);
|
||||||
|
|
||||||
// turn off Nagle algorithm. we send lots of very short messages
|
// turn off Nagle algorithm. we send lots of very short messages
|
||||||
// that should be sent without (much) delay. for example, the
|
// that should be sent without (much) delay. for example, the
|
||||||
// mouse motion messages are much less useful if they're delayed.
|
// mouse motion messages are much less useful if they're delayed.
|
||||||
// FIXME -- the client should do this
|
|
||||||
try {
|
|
||||||
ARCH->setNoDelayOnSocket(m_socket, true);
|
ARCH->setNoDelayOnSocket(m_socket, true);
|
||||||
}
|
}
|
||||||
catch (XArchNetwork& e) {
|
catch (XArchNetwork& e) {
|
||||||
|
|
|
@ -24,11 +24,13 @@ CEvent::Type IDataSocket::s_failedEvent = CEvent::kUnknown;
|
||||||
CEvent::Type
|
CEvent::Type
|
||||||
IDataSocket::getConnectedEvent()
|
IDataSocket::getConnectedEvent()
|
||||||
{
|
{
|
||||||
return CEvent::registerTypeOnce(s_connectedEvent);
|
return CEvent::registerTypeOnce(s_connectedEvent,
|
||||||
|
"IDataSocket::connected");
|
||||||
}
|
}
|
||||||
|
|
||||||
CEvent::Type
|
CEvent::Type
|
||||||
IDataSocket::getConnectionFailedEvent()
|
IDataSocket::getConnectionFailedEvent()
|
||||||
{
|
{
|
||||||
return CEvent::registerTypeOnce(s_failedEvent);
|
return CEvent::registerTypeOnce(s_failedEvent,
|
||||||
|
"IDataSocket::failed");
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,5 +23,6 @@ CEvent::Type IListenSocket::s_connectingEvent = CEvent::kUnknown;
|
||||||
CEvent::Type
|
CEvent::Type
|
||||||
IListenSocket::getConnectingEvent()
|
IListenSocket::getConnectingEvent()
|
||||||
{
|
{
|
||||||
return CEvent::registerTypeOnce(s_connectingEvent);
|
return CEvent::registerTypeOnce(s_connectingEvent,
|
||||||
|
"IListenSocket::connecting");
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,5 +23,6 @@ CEvent::Type ISocket::s_disconnectedEvent = CEvent::kUnknown;
|
||||||
CEvent::Type
|
CEvent::Type
|
||||||
ISocket::getDisconnectedEvent()
|
ISocket::getDisconnectedEvent()
|
||||||
{
|
{
|
||||||
return CEvent::registerTypeOnce(s_disconnectedEvent);
|
return CEvent::registerTypeOnce(s_disconnectedEvent,
|
||||||
|
"ISocket::disconnected");
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,9 +12,10 @@
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "CXWindowsEventQueue.h"
|
#include "CXWindowsEventQueueBuffer.h"
|
||||||
#include "CEvent.h"
|
|
||||||
#include "CThread.h"
|
#include "CThread.h"
|
||||||
|
#include "CEvent.h"
|
||||||
|
#include "IEventQueue.h"
|
||||||
#if UNIX_LIKE
|
#if UNIX_LIKE
|
||||||
# if HAVE_POLL
|
# if HAVE_POLL
|
||||||
# include <sys/poll.h>
|
# include <sys/poll.h>
|
||||||
|
@ -42,52 +43,27 @@ class CEventQueueTimer { };
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// CXWindowsEventQueue
|
// CXWindowsEventQueueBuffer
|
||||||
//
|
//
|
||||||
|
|
||||||
CXWindowsEventQueue::CXWindowsEventQueue(Display* display) :
|
CXWindowsEventQueueBuffer::CXWindowsEventQueueBuffer(
|
||||||
m_display(display)
|
Display* display, Window window) :
|
||||||
|
m_display(display),
|
||||||
|
m_window(window)
|
||||||
{
|
{
|
||||||
|
assert(m_display != NULL);
|
||||||
|
assert(m_window != None);
|
||||||
|
|
||||||
m_userEvent = XInternAtom(m_display, "SYNERGY_USER_EVENT", False);
|
m_userEvent = XInternAtom(m_display, "SYNERGY_USER_EVENT", False);
|
||||||
|
|
||||||
XSetWindowAttributes attr;
|
|
||||||
m_window = XCreateWindow(m_display, DefaultRootWindow(m_display),
|
|
||||||
0, 0, 1, 1, 0, 0, InputOnly, CopyFromParent,
|
|
||||||
0, &attr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CXWindowsEventQueue::~CXWindowsEventQueue()
|
CXWindowsEventQueueBuffer::~CXWindowsEventQueueBuffer()
|
||||||
{
|
{
|
||||||
XDestroyWindow(m_display, m_window);
|
// do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CXWindowsEventQueue::processSystemEvent(CEvent& event)
|
CXWindowsEventQueueBuffer::waitForEvent(double dtimeout)
|
||||||
{
|
|
||||||
event = CEvent(CEvent::kSystem, getSystemTarget(), &m_event);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CXWindowsEventQueue::processClientMessage(CEvent& event)
|
|
||||||
{
|
|
||||||
assert(m_event.xany.type == ClientMessage);
|
|
||||||
|
|
||||||
// handle user events specially
|
|
||||||
if (m_event.xclient.message_type == m_userEvent) {
|
|
||||||
// get event data
|
|
||||||
CEventData data = removeEventData(m_event.xclient.data.l[1]);
|
|
||||||
|
|
||||||
// create event
|
|
||||||
event = CEvent(static_cast<size_t>(m_event.xclient.data.l[0]),
|
|
||||||
data.first, data.second);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
processSystemEvent(event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CXWindowsEventQueue::waitForEvent(double dtimeout)
|
|
||||||
{
|
{
|
||||||
// use poll() to wait for a message from the X server or for timeout.
|
// use poll() to wait for a message from the X server or for timeout.
|
||||||
// this is a good deal more efficient than polling and sleeping.
|
// this is a good deal more efficient than polling and sleeping.
|
||||||
|
@ -132,25 +108,27 @@ CXWindowsEventQueue::waitForEvent(double dtimeout)
|
||||||
CThread::testCancel();
|
CThread::testCancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
IEventQueueBuffer::Type
|
||||||
CXWindowsEventQueue::doGetEvent(CEvent& event)
|
CXWindowsEventQueueBuffer::getEvent(CEvent& event, UInt32& dataID)
|
||||||
{
|
{
|
||||||
// get next event
|
// get next event
|
||||||
XNextEvent(m_display, &m_event);
|
XNextEvent(m_display, &m_event);
|
||||||
|
|
||||||
// process event
|
// process event
|
||||||
if (m_event.xany.type == ClientMessage) {
|
if (m_event.xany.type == ClientMessage &&
|
||||||
processClientMessage(event);
|
m_event.xclient.message_type == m_userEvent) {
|
||||||
|
dataID = static_cast<UInt32>(m_event.xclient.data.l[0]);
|
||||||
|
return kUser;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
processSystemEvent(event);
|
event = CEvent(CEvent::kSystem,
|
||||||
|
IEventQueue::getSystemTarget(), &m_event);
|
||||||
|
return kSystem;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CXWindowsEventQueue::doAddEvent(CEvent::Type type, UInt32 dataID)
|
CXWindowsEventQueueBuffer::addEvent(UInt32 dataID)
|
||||||
{
|
{
|
||||||
// send ourself a message
|
// send ourself a message
|
||||||
XEvent xevent;
|
XEvent xevent;
|
||||||
|
@ -158,25 +136,29 @@ CXWindowsEventQueue::doAddEvent(CEvent::Type type, UInt32 dataID)
|
||||||
xevent.xclient.window = m_window;
|
xevent.xclient.window = m_window;
|
||||||
xevent.xclient.message_type = m_userEvent;
|
xevent.xclient.message_type = m_userEvent;
|
||||||
xevent.xclient.format = 32;
|
xevent.xclient.format = 32;
|
||||||
xevent.xclient.data.l[0] = static_cast<long>(type);
|
xevent.xclient.data.l[0] = static_cast<long>(dataID);
|
||||||
xevent.xclient.data.l[1] = static_cast<long>(dataID);
|
if (XSendEvent(m_display, m_window, False, 0, &xevent) == 0) {
|
||||||
return (XSendEvent(m_display, m_window, False, 0, &xevent) != 0);
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// force waitForEvent() to return
|
||||||
|
XFlush(m_display);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CXWindowsEventQueue::doIsEmpty() const
|
CXWindowsEventQueueBuffer::isEmpty() const
|
||||||
{
|
{
|
||||||
return (XPending(m_display) == 0);
|
return (XPending(m_display) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
CEventQueueTimer*
|
CEventQueueTimer*
|
||||||
CXWindowsEventQueue::doNewTimer(double, bool) const
|
CXWindowsEventQueueBuffer::newTimer(double, bool) const
|
||||||
{
|
{
|
||||||
return new CEventQueueTimer();
|
return new CEventQueueTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CXWindowsEventQueue::doDeleteTimer(CEventQueueTimer* timer) const
|
CXWindowsEventQueueBuffer::deleteTimer(CEventQueueTimer* timer) const
|
||||||
{
|
{
|
||||||
delete timer;
|
delete timer;
|
||||||
}
|
}
|
|
@ -12,44 +12,30 @@
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef CXWINDOWSEVENTQUEUE_H
|
#ifndef CXWINDOWSEVENTQUEUEBUFFER_H
|
||||||
#define CXWINDOWSEVENTQUEUE_H
|
#define CXWINDOWSEVENTQUEUEBUFFER_H
|
||||||
|
|
||||||
#include "CEventQueue.h"
|
#include "IEventQueueBuffer.h"
|
||||||
#if defined(X_DISPLAY_MISSING)
|
#if defined(X_DISPLAY_MISSING)
|
||||||
# error X11 is required to build synergy
|
# error X11 is required to build synergy
|
||||||
#else
|
#else
|
||||||
# include <X11/Xlib.h>
|
# include <X11/Xlib.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//! Event queue for X11
|
//! Event queue buffer for X11
|
||||||
class CXWindowsEventQueue : public CEventQueue {
|
class CXWindowsEventQueueBuffer : public IEventQueueBuffer {
|
||||||
public:
|
public:
|
||||||
CXWindowsEventQueue(Display*);
|
CXWindowsEventQueueBuffer(Display*, Window);
|
||||||
virtual ~CXWindowsEventQueue();
|
virtual ~CXWindowsEventQueueBuffer();
|
||||||
|
|
||||||
//! @name manipulators
|
// IEventQueueBuffer overrides
|
||||||
//@{
|
|
||||||
|
|
||||||
//@}
|
|
||||||
//! @name accessors
|
|
||||||
//@{
|
|
||||||
|
|
||||||
//@}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
// CEventQueue overrides
|
|
||||||
virtual void waitForEvent(double timeout);
|
virtual void waitForEvent(double timeout);
|
||||||
virtual bool doGetEvent(CEvent& event);
|
virtual Type getEvent(CEvent& event, UInt32& dataID);
|
||||||
virtual bool doAddEvent(CEvent::Type type, UInt32 dataID);
|
virtual bool addEvent(UInt32 dataID);
|
||||||
virtual bool doIsEmpty() const;
|
virtual bool isEmpty() const;
|
||||||
virtual CEventQueueTimer*
|
virtual CEventQueueTimer*
|
||||||
doNewTimer(double duration, bool oneShot) const;
|
newTimer(double duration, bool oneShot) const;
|
||||||
virtual void doDeleteTimer(CEventQueueTimer*) const;
|
virtual void deleteTimer(CEventQueueTimer*) const;
|
||||||
|
|
||||||
private:
|
|
||||||
void processSystemEvent(CEvent& event);
|
|
||||||
void processClientMessage(CEvent& event);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Display* m_display;
|
Display* m_display;
|
File diff suppressed because it is too large
Load Diff
|
@ -17,9 +17,6 @@
|
||||||
|
|
||||||
#include "IPlatformScreen.h"
|
#include "IPlatformScreen.h"
|
||||||
#include "CXWindowsKeyMapper.h"
|
#include "CXWindowsKeyMapper.h"
|
||||||
#include "CMutex.h"
|
|
||||||
#include "CStopwatch.h"
|
|
||||||
#include "CPriorityQueue.h"
|
|
||||||
#include "stdvector.h"
|
#include "stdvector.h"
|
||||||
#if defined(X_DISPLAY_MISSING)
|
#if defined(X_DISPLAY_MISSING)
|
||||||
# error X11 is required to build synergy
|
# error X11 is required to build synergy
|
||||||
|
@ -29,43 +26,22 @@
|
||||||
|
|
||||||
class CXWindowsClipboard;
|
class CXWindowsClipboard;
|
||||||
class CXWindowsScreenSaver;
|
class CXWindowsScreenSaver;
|
||||||
class IJob;
|
|
||||||
class IScreenReceiver;
|
|
||||||
class IPrimaryScreenReceiver;
|
|
||||||
|
|
||||||
//! Implementation of IPlatformScreen for X11
|
//! Implementation of IPlatformScreen for X11
|
||||||
class CXWindowsScreen : public IPlatformScreen {
|
class CXWindowsScreen : public IPlatformScreen {
|
||||||
public:
|
public:
|
||||||
CXWindowsScreen(IScreenReceiver*, IPrimaryScreenReceiver*);
|
CXWindowsScreen(bool isPrimary);
|
||||||
virtual ~CXWindowsScreen();
|
virtual ~CXWindowsScreen();
|
||||||
|
|
||||||
//! @name manipulators
|
//! @name manipulators
|
||||||
//@{
|
//@{
|
||||||
|
|
||||||
//! Add timer
|
|
||||||
/*!
|
|
||||||
Add a job to invoke every timeout seconds. The job is called
|
|
||||||
with the display locked. If a job timeout expires twice or
|
|
||||||
more before the job can be called then the job is called just
|
|
||||||
once. The caller retains ownership of the job.
|
|
||||||
*/
|
|
||||||
void addTimer(IJob*, double timeout);
|
|
||||||
|
|
||||||
//! Remove timer
|
|
||||||
/*!
|
|
||||||
Remove a job. The caller retains ownership of the job.
|
|
||||||
*/
|
|
||||||
void removeTimer(IJob*);
|
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
// IPlatformScreen overrides
|
// IPlatformScreen overrides
|
||||||
virtual void open(IKeyState*);
|
virtual void setKeyState(IKeyState*);
|
||||||
virtual void close();
|
|
||||||
virtual void enable();
|
virtual void enable();
|
||||||
virtual void disable();
|
virtual void disable();
|
||||||
virtual void mainLoop();
|
|
||||||
virtual void exitMainLoop();
|
|
||||||
virtual void enter();
|
virtual void enter();
|
||||||
virtual bool leave();
|
virtual bool leave();
|
||||||
virtual bool setClipboard(ClipboardID, const IClipboard*);
|
virtual bool setClipboard(ClipboardID, const IClipboard*);
|
||||||
|
@ -76,17 +52,22 @@ public:
|
||||||
virtual void resetOptions();
|
virtual void resetOptions();
|
||||||
virtual void setOptions(const COptionsList& options);
|
virtual void setOptions(const COptionsList& options);
|
||||||
virtual void updateKeys();
|
virtual void updateKeys();
|
||||||
|
virtual void setSequenceNumber(UInt32);
|
||||||
virtual bool isPrimary() const;
|
virtual bool isPrimary() const;
|
||||||
virtual bool getClipboard(ClipboardID, IClipboard*) const;
|
|
||||||
virtual void getShape(SInt32&, SInt32&, SInt32&, SInt32&) const;
|
// IScreen overrides
|
||||||
virtual void getCursorPos(SInt32&, SInt32&) const;
|
virtual void* getEventTarget() const;
|
||||||
|
virtual bool getClipboard(ClipboardID id, IClipboard*) const;
|
||||||
|
virtual void getShape(SInt32& x, SInt32& y,
|
||||||
|
SInt32& width, SInt32& height) const;
|
||||||
|
virtual void getCursorPos(SInt32& x, SInt32& y) const;
|
||||||
|
|
||||||
// IPrimaryScreen overrides
|
// IPrimaryScreen overrides
|
||||||
virtual void reconfigure(UInt32 activeSides);
|
virtual void reconfigure(UInt32 activeSides);
|
||||||
virtual void warpCursor(SInt32 x, SInt32 y);
|
virtual void warpCursor(SInt32 x, SInt32 y);
|
||||||
virtual UInt32 addOneShotTimer(double timeout);
|
|
||||||
virtual SInt32 getJumpZoneSize() const;
|
virtual SInt32 getJumpZoneSize() const;
|
||||||
virtual bool isAnyMouseButtonDown() const;
|
virtual bool isAnyMouseButtonDown() const;
|
||||||
|
virtual void getCursorCenter(SInt32& x, SInt32& y) const;
|
||||||
virtual const char* getKeyName(KeyButton) const;
|
virtual const char* getKeyName(KeyButton) const;
|
||||||
|
|
||||||
// ISecondaryScreen overrides
|
// ISecondaryScreen overrides
|
||||||
|
@ -101,18 +82,16 @@ public:
|
||||||
bool isAutoRepeat) const;
|
bool isAutoRepeat) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// process events before dispatching to receiver
|
// event sending
|
||||||
void onEvent(XEvent* event);
|
void sendEvent(CEvent::Type, void* = NULL);
|
||||||
|
void sendClipboardEvent(CEvent::Type, ClipboardID);
|
||||||
|
|
||||||
|
// event handling
|
||||||
|
void handleSystemEvent(const CEvent&, void*);
|
||||||
|
|
||||||
// create the transparent cursor
|
// create the transparent cursor
|
||||||
Cursor createBlankCursor() const;
|
Cursor createBlankCursor() const;
|
||||||
|
|
||||||
// remove a timer without locking
|
|
||||||
void removeTimerNoLock(IJob*);
|
|
||||||
|
|
||||||
// process timers
|
|
||||||
bool processTimers();
|
|
||||||
|
|
||||||
// determine the clipboard from the X selection. returns
|
// determine the clipboard from the X selection. returns
|
||||||
// kClipboardEnd if no such clipboard.
|
// kClipboardEnd if no such clipboard.
|
||||||
ClipboardID getClipboardID(Atom selection) const;
|
ClipboardID getClipboardID(Atom selection) const;
|
||||||
|
@ -125,40 +104,10 @@ private:
|
||||||
void destroyClipboardRequest(Window window);
|
void destroyClipboardRequest(Window window);
|
||||||
|
|
||||||
// X I/O error handler
|
// X I/O error handler
|
||||||
|
void onError();
|
||||||
static int ioErrorHandler(Display*);
|
static int ioErrorHandler(Display*);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// a timer priority queue element
|
|
||||||
class CTimer {
|
|
||||||
public:
|
|
||||||
CTimer(IJob* job, double startTime, double resetTime);
|
|
||||||
~CTimer();
|
|
||||||
|
|
||||||
// manipulators
|
|
||||||
|
|
||||||
void run();
|
|
||||||
|
|
||||||
void reset();
|
|
||||||
|
|
||||||
CTimer& operator-=(double);
|
|
||||||
|
|
||||||
// accessors
|
|
||||||
|
|
||||||
IJob* getJob() const
|
|
||||||
{
|
|
||||||
return m_job;
|
|
||||||
}
|
|
||||||
|
|
||||||
operator double() const;
|
|
||||||
|
|
||||||
bool operator<(const CTimer&) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
IJob* m_job;
|
|
||||||
double m_timeout;
|
|
||||||
double m_time;
|
|
||||||
double m_startTime;
|
|
||||||
};
|
|
||||||
class CKeyEventInfo {
|
class CKeyEventInfo {
|
||||||
public:
|
public:
|
||||||
int m_event;
|
int m_event;
|
||||||
|
@ -167,9 +116,9 @@ private:
|
||||||
KeyCode m_keycode;
|
KeyCode m_keycode;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool isQuitEvent(XEvent*) const;
|
Display* openDisplay() const;
|
||||||
|
void saveShape();
|
||||||
Window createWindow() const;
|
Window openWindow() const;
|
||||||
void openIM();
|
void openIM();
|
||||||
|
|
||||||
bool grabMouseAndKeyboard();
|
bool grabMouseAndKeyboard();
|
||||||
|
@ -193,21 +142,13 @@ private:
|
||||||
static Bool findKeyEvent(Display*, XEvent* xevent, XPointer arg);
|
static Bool findKeyEvent(Display*, XEvent* xevent, XPointer arg);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef CPriorityQueue<CTimer> CTimerPriorityQueue;
|
|
||||||
|
|
||||||
// true if screen is being used as a primary screen, false otherwise
|
// true if screen is being used as a primary screen, false otherwise
|
||||||
bool m_isPrimary;
|
bool m_isPrimary;
|
||||||
|
|
||||||
// X is not thread safe
|
|
||||||
CMutex m_mutex;
|
|
||||||
|
|
||||||
Display* m_display;
|
Display* m_display;
|
||||||
Window m_root;
|
Window m_root;
|
||||||
Window m_window;
|
Window m_window;
|
||||||
|
|
||||||
IScreenReceiver* m_receiver;
|
|
||||||
IPrimaryScreenReceiver* m_primaryReceiver;
|
|
||||||
|
|
||||||
// true if mouse has entered the screen
|
// true if mouse has entered the screen
|
||||||
bool m_isOnScreen;
|
bool m_isOnScreen;
|
||||||
|
|
||||||
|
@ -230,20 +171,11 @@ private:
|
||||||
|
|
||||||
// clipboards
|
// clipboards
|
||||||
CXWindowsClipboard* m_clipboard[kClipboardEnd];
|
CXWindowsClipboard* m_clipboard[kClipboardEnd];
|
||||||
|
UInt32 m_sequenceNumber;
|
||||||
// the quit message
|
|
||||||
Atom m_atomQuit;
|
|
||||||
|
|
||||||
// screen saver stuff
|
// screen saver stuff
|
||||||
CXWindowsScreenSaver* m_screensaver;
|
CXWindowsScreenSaver* m_screensaver;
|
||||||
bool m_screensaverNotify;
|
bool m_screensaverNotify;
|
||||||
Atom m_atomScreensaver;
|
|
||||||
|
|
||||||
// timers, the stopwatch used to time, and a mutex for the timers
|
|
||||||
CTimerPriorityQueue m_timers;
|
|
||||||
CStopwatch m_time;
|
|
||||||
CMutex m_timersMutex;
|
|
||||||
CTimer* m_oneShotTimer;
|
|
||||||
|
|
||||||
// logical to physical button mapping. m_buttons[i] gives the
|
// logical to physical button mapping. m_buttons[i] gives the
|
||||||
// physical button for logical button i+1.
|
// physical button for logical button i+1.
|
||||||
|
|
|
@ -13,10 +13,12 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "CXWindowsScreenSaver.h"
|
#include "CXWindowsScreenSaver.h"
|
||||||
#include "CXWindowsScreen.h"
|
|
||||||
#include "CXWindowsUtil.h"
|
#include "CXWindowsUtil.h"
|
||||||
|
#include "IPlatformScreen.h"
|
||||||
#include "CLog.h"
|
#include "CLog.h"
|
||||||
#include "TMethodJob.h"
|
#include "CEvent.h"
|
||||||
|
#include "IEventQueue.h"
|
||||||
|
#include "TMethodEventJob.h"
|
||||||
#include <X11/Xatom.h>
|
#include <X11/Xatom.h>
|
||||||
#if defined(HAVE_X11_EXTENSIONS_XTEST_H)
|
#if defined(HAVE_X11_EXTENSIONS_XTEST_H)
|
||||||
# include <X11/extensions/XTest.h>
|
# include <X11/extensions/XTest.h>
|
||||||
|
@ -29,20 +31,16 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
CXWindowsScreenSaver::CXWindowsScreenSaver(
|
CXWindowsScreenSaver::CXWindowsScreenSaver(
|
||||||
CXWindowsScreen* screen, Display* display) :
|
Display* display, Window window, void* eventTarget) :
|
||||||
m_screen(screen),
|
|
||||||
m_display(display),
|
m_display(display),
|
||||||
m_notify(None),
|
m_xscreensaverSink(window),
|
||||||
|
m_eventTarget(eventTarget),
|
||||||
m_xscreensaver(None),
|
m_xscreensaver(None),
|
||||||
m_xscreensaverActive(false),
|
m_xscreensaverActive(false),
|
||||||
m_disabled(false),
|
m_disabled(false),
|
||||||
m_suppressDisable(false),
|
m_suppressDisable(false),
|
||||||
m_disableJobInstalled(false)
|
m_disableTimer(NULL)
|
||||||
{
|
{
|
||||||
// screen saver disable callback
|
|
||||||
m_disableJob = new TMethodJob<CXWindowsScreenSaver>(this,
|
|
||||||
&CXWindowsScreenSaver::disableCallback);
|
|
||||||
|
|
||||||
// get atoms
|
// get atoms
|
||||||
m_atomScreenSaver = XInternAtom(m_display,
|
m_atomScreenSaver = XInternAtom(m_display,
|
||||||
"SCREENSAVER", False);
|
"SCREENSAVER", False);
|
||||||
|
@ -52,24 +50,6 @@ CXWindowsScreenSaver::CXWindowsScreenSaver(
|
||||||
"ACTIVATE", False);
|
"ACTIVATE", False);
|
||||||
m_atomScreenSaverDeactivate = XInternAtom(m_display,
|
m_atomScreenSaverDeactivate = XInternAtom(m_display,
|
||||||
"DEACTIVATE", False);
|
"DEACTIVATE", False);
|
||||||
m_atomSynergyScreenSaver = XInternAtom(m_display,
|
|
||||||
"SYNERGY_SCREENSAVER", False);
|
|
||||||
|
|
||||||
// create dummy window to receive xscreensaver responses. this
|
|
||||||
// shouldn't be necessary (we should be able to send responses
|
|
||||||
// to None) but it doesn't hurt.
|
|
||||||
XSetWindowAttributes attr;
|
|
||||||
attr.event_mask = 0;//PropertyChangeMask;
|
|
||||||
attr.do_not_propagate_mask = 0;
|
|
||||||
attr.override_redirect = True;
|
|
||||||
m_xscreensaverSink = XCreateWindow(m_display,
|
|
||||||
DefaultRootWindow(m_display),
|
|
||||||
0, 0, 1, 1, 0, 0,
|
|
||||||
InputOnly, CopyFromParent,
|
|
||||||
CWDontPropagate | CWEventMask |
|
|
||||||
CWOverrideRedirect,
|
|
||||||
&attr);
|
|
||||||
LOG((CLOG_DEBUG "xscreensaver sink window is 0x%08x", m_xscreensaverSink));
|
|
||||||
|
|
||||||
// watch top-level windows for changes
|
// watch top-level windows for changes
|
||||||
{
|
{
|
||||||
|
@ -94,28 +74,39 @@ CXWindowsScreenSaver::CXWindowsScreenSaver(
|
||||||
// get the built-in settings
|
// get the built-in settings
|
||||||
XGetScreenSaver(m_display, &m_timeout, &m_interval,
|
XGetScreenSaver(m_display, &m_timeout, &m_interval,
|
||||||
&m_preferBlanking, &m_allowExposures);
|
&m_preferBlanking, &m_allowExposures);
|
||||||
|
|
||||||
|
// install disable timer event handler
|
||||||
|
EVENTQUEUE->adoptHandler(CEvent::kTimer, this,
|
||||||
|
new TMethodEventJob<CXWindowsScreenSaver>(this,
|
||||||
|
&CXWindowsScreenSaver::handleDisableTimer));
|
||||||
}
|
}
|
||||||
|
|
||||||
CXWindowsScreenSaver::~CXWindowsScreenSaver()
|
CXWindowsScreenSaver::~CXWindowsScreenSaver()
|
||||||
{
|
{
|
||||||
// clear watch list
|
|
||||||
clearWatchForXScreenSaver();
|
|
||||||
|
|
||||||
// stop watching root for events
|
|
||||||
CXWindowsUtil::CErrorLock lock(m_display);
|
|
||||||
Window root = DefaultRootWindow(m_display);
|
|
||||||
XSelectInput(m_display, root, m_rootEventMask);
|
|
||||||
|
|
||||||
// destroy dummy sink window
|
|
||||||
XDestroyWindow(m_display, m_xscreensaverSink);
|
|
||||||
|
|
||||||
// done with disable job
|
// done with disable job
|
||||||
m_screen->removeTimer(m_disableJob);
|
if (m_disableTimer != NULL) {
|
||||||
delete m_disableJob;
|
EVENTQUEUE->deleteTimer(m_disableTimer);
|
||||||
|
}
|
||||||
|
EVENTQUEUE->removeHandler(CEvent::kTimer, this);
|
||||||
|
|
||||||
|
if (m_display != NULL) {
|
||||||
|
XSetScreenSaver(m_display, m_timeout, m_interval,
|
||||||
|
m_preferBlanking, m_allowExposures);
|
||||||
|
clearWatchForXScreenSaver();
|
||||||
|
CXWindowsUtil::CErrorLock lock(m_display);
|
||||||
|
XSelectInput(m_display, DefaultRootWindow(m_display), m_rootEventMask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CXWindowsScreenSaver::destroy()
|
||||||
|
{
|
||||||
|
m_display = NULL;
|
||||||
|
delete this;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CXWindowsScreenSaver::onPreDispatch(const XEvent* xevent)
|
CXWindowsScreenSaver::handleXEvent(const XEvent* xevent)
|
||||||
{
|
{
|
||||||
switch (xevent->type) {
|
switch (xevent->type) {
|
||||||
case CreateNotify:
|
case CreateNotify:
|
||||||
|
@ -175,18 +166,12 @@ CXWindowsScreenSaver::onPreDispatch(const XEvent* xevent)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
CXWindowsScreenSaver::setNotify(Window notify)
|
|
||||||
{
|
|
||||||
m_notify = notify;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
CXWindowsScreenSaver::enable()
|
CXWindowsScreenSaver::enable()
|
||||||
{
|
{
|
||||||
// for xscreensaver
|
// for xscreensaver
|
||||||
m_disabled = false;
|
m_disabled = false;
|
||||||
updateDisableJob();
|
updateDisableTimer();
|
||||||
|
|
||||||
// for built-in X screen saver
|
// for built-in X screen saver
|
||||||
XSetScreenSaver(m_display, m_timeout, m_interval,
|
XSetScreenSaver(m_display, m_timeout, m_interval,
|
||||||
|
@ -198,7 +183,7 @@ CXWindowsScreenSaver::disable()
|
||||||
{
|
{
|
||||||
// for xscreensaver
|
// for xscreensaver
|
||||||
m_disabled = true;
|
m_disabled = true;
|
||||||
updateDisableJob();
|
updateDisableTimer();
|
||||||
|
|
||||||
// use built-in X screen saver
|
// use built-in X screen saver
|
||||||
XGetScreenSaver(m_display, &m_timeout, &m_interval,
|
XGetScreenSaver(m_display, &m_timeout, &m_interval,
|
||||||
|
@ -213,7 +198,7 @@ CXWindowsScreenSaver::activate()
|
||||||
{
|
{
|
||||||
// remove disable job timer
|
// remove disable job timer
|
||||||
m_suppressDisable = true;
|
m_suppressDisable = true;
|
||||||
updateDisableJob();
|
updateDisableTimer();
|
||||||
|
|
||||||
// try xscreensaver
|
// try xscreensaver
|
||||||
findXScreenSaver();
|
findXScreenSaver();
|
||||||
|
@ -231,7 +216,7 @@ CXWindowsScreenSaver::deactivate()
|
||||||
{
|
{
|
||||||
// reinstall disable job timer
|
// reinstall disable job timer
|
||||||
m_suppressDisable = false;
|
m_suppressDisable = false;
|
||||||
updateDisableJob();
|
updateDisableTimer();
|
||||||
|
|
||||||
// try xscreensaver
|
// try xscreensaver
|
||||||
findXScreenSaver();
|
findXScreenSaver();
|
||||||
|
@ -256,27 +241,6 @@ CXWindowsScreenSaver::isActive() const
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
CXWindowsScreenSaver::sendNotify(bool activated)
|
|
||||||
{
|
|
||||||
if (m_notify != None) {
|
|
||||||
XEvent event;
|
|
||||||
event.xclient.type = ClientMessage;
|
|
||||||
event.xclient.display = m_display;
|
|
||||||
event.xclient.window = m_notify;
|
|
||||||
event.xclient.message_type = m_atomSynergyScreenSaver;
|
|
||||||
event.xclient.format = 32;
|
|
||||||
event.xclient.data.l[0] = activated ? 1 : 0;
|
|
||||||
event.xclient.data.l[1] = 0;
|
|
||||||
event.xclient.data.l[2] = 0;
|
|
||||||
event.xclient.data.l[3] = 0;
|
|
||||||
event.xclient.data.l[4] = 0;
|
|
||||||
|
|
||||||
CXWindowsUtil::CErrorLock lock(m_display);
|
|
||||||
XSendEvent(m_display, m_notify, False, 0, &event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CXWindowsScreenSaver::findXScreenSaver()
|
CXWindowsScreenSaver::findXScreenSaver()
|
||||||
{
|
{
|
||||||
|
@ -351,9 +315,18 @@ CXWindowsScreenSaver::setXScreenSaverActive(bool activated)
|
||||||
// from activating since that'll just pop up the password
|
// from activating since that'll just pop up the password
|
||||||
// dialog if locking is enabled.
|
// dialog if locking is enabled.
|
||||||
m_suppressDisable = activated;
|
m_suppressDisable = activated;
|
||||||
updateDisableJob();
|
updateDisableTimer();
|
||||||
|
|
||||||
sendNotify(activated);
|
if (activated) {
|
||||||
|
EVENTQUEUE->addEvent(CEvent(
|
||||||
|
IPlatformScreen::getScreensaverActivatedEvent(),
|
||||||
|
m_eventTarget));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
EVENTQUEUE->addEvent(CEvent(
|
||||||
|
IPlatformScreen::getScreensaverDeactivatedEvent(),
|
||||||
|
m_eventTarget));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -441,23 +414,20 @@ CXWindowsScreenSaver::addWatchXScreenSaver(Window window)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CXWindowsScreenSaver::updateDisableJob()
|
CXWindowsScreenSaver::updateDisableTimer()
|
||||||
{
|
{
|
||||||
assert(m_disableJob != NULL);
|
if (m_disabled && !m_suppressDisable && m_disableTimer == NULL) {
|
||||||
|
|
||||||
if (m_disabled && !m_suppressDisable && !m_disableJobInstalled) {
|
|
||||||
// 5 seconds should be plenty often to suppress the screen saver
|
// 5 seconds should be plenty often to suppress the screen saver
|
||||||
m_disableJobInstalled = true;
|
m_disableTimer = EVENTQUEUE->newTimer(5.0, this);
|
||||||
m_screen->addTimer(m_disableJob, 5.0);
|
|
||||||
}
|
}
|
||||||
else if ((!m_disabled || m_suppressDisable) && m_disableJobInstalled) {
|
else if ((!m_disabled || m_suppressDisable) && m_disableTimer != NULL) {
|
||||||
m_disableJobInstalled = false;
|
EVENTQUEUE->deleteTimer(m_disableTimer);
|
||||||
m_screen->removeTimer(m_disableJob);
|
m_disableTimer = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CXWindowsScreenSaver::disableCallback(void*)
|
CXWindowsScreenSaver::handleDisableTimer(const CEvent&, void*)
|
||||||
{
|
{
|
||||||
// send fake mouse motion directly to xscreensaver
|
// send fake mouse motion directly to xscreensaver
|
||||||
if (m_xscreensaver != None) {
|
if (m_xscreensaver != None) {
|
||||||
|
|
|
@ -23,16 +23,13 @@
|
||||||
# include <X11/Xlib.h>
|
# include <X11/Xlib.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
class IJob;
|
class CEvent;
|
||||||
class CXWindowsScreen;
|
class CEventQueueTimer;
|
||||||
|
|
||||||
//! X11 screen saver implementation
|
//! X11 screen saver implementation
|
||||||
class CXWindowsScreenSaver : public IScreenSaver {
|
class CXWindowsScreenSaver : public IScreenSaver {
|
||||||
public:
|
public:
|
||||||
// note -- the caller must ensure that Display* passed to c'tor isn't
|
CXWindowsScreenSaver(Display*, Window, void* eventTarget);
|
||||||
// being used in another call to Xlib when calling any method on this
|
|
||||||
// object (including during the c'tor and d'tor).
|
|
||||||
CXWindowsScreenSaver(CXWindowsScreen*, Display*);
|
|
||||||
virtual ~CXWindowsScreenSaver();
|
virtual ~CXWindowsScreenSaver();
|
||||||
|
|
||||||
//! @name manipulators
|
//! @name manipulators
|
||||||
|
@ -40,22 +37,17 @@ public:
|
||||||
|
|
||||||
//! Event filtering
|
//! Event filtering
|
||||||
/*!
|
/*!
|
||||||
Called for each event before event translation and dispatch. Return
|
Should be called for each system event before event translation and
|
||||||
true to skip translation and dispatch. Subclasses should call the
|
dispatch. Returns true to skip translation and dispatch.
|
||||||
superclass's version first and return true if it returns true.
|
|
||||||
*/
|
*/
|
||||||
bool onPreDispatch(const XEvent*);
|
bool handleXEvent(const XEvent*);
|
||||||
|
|
||||||
//! Set notify target
|
//! Destroy without the display
|
||||||
/*!
|
/*!
|
||||||
Tells this object to send a ClientMessage to the given window
|
Tells this object to delete itself without using the X11 display.
|
||||||
when the screen saver activates or deactivates. Only one window
|
It may leak some resources as a result.
|
||||||
can be notified at a time. The message type is the "SCREENSAVER"
|
|
||||||
atom, the format is 32, and the data.l[0] member is non-zero
|
|
||||||
if activated, zero if deactivated. Pass None to disable
|
|
||||||
notification.
|
|
||||||
*/
|
*/
|
||||||
void setNotify(Window);
|
void destroy();
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
|
@ -67,9 +59,6 @@ public:
|
||||||
virtual bool isActive() const;
|
virtual bool isActive() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// send a notification
|
|
||||||
void sendNotify(bool activated);
|
|
||||||
|
|
||||||
// find and set the running xscreensaver's window. returns true iff
|
// find and set the running xscreensaver's window. returns true iff
|
||||||
// found.
|
// found.
|
||||||
bool findXScreenSaver();
|
bool findXScreenSaver();
|
||||||
|
@ -98,25 +87,22 @@ private:
|
||||||
void addWatchXScreenSaver(Window window);
|
void addWatchXScreenSaver(Window window);
|
||||||
|
|
||||||
// install/uninstall the job used to suppress the screensaver
|
// install/uninstall the job used to suppress the screensaver
|
||||||
void updateDisableJob();
|
void updateDisableTimer();
|
||||||
|
|
||||||
// called periodically to prevent the screen saver from starting
|
// called periodically to prevent the screen saver from starting
|
||||||
void disableCallback(void*);
|
void handleDisableTimer(const CEvent&, void*);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef std::map<Window, long> CWatchList;
|
typedef std::map<Window, long> CWatchList;
|
||||||
|
|
||||||
// the event loop object
|
|
||||||
CXWindowsScreen* m_screen;
|
|
||||||
|
|
||||||
// the X display
|
// the X display
|
||||||
Display* m_display;
|
Display* m_display;
|
||||||
|
|
||||||
// old event mask on root window
|
// window to receive xscreensaver repsonses
|
||||||
long m_rootEventMask;
|
Window m_xscreensaverSink;
|
||||||
|
|
||||||
// window to notify on screen saver activation/deactivation
|
// the target for the events we generate
|
||||||
Window m_notify;
|
void* m_eventTarget;
|
||||||
|
|
||||||
// xscreensaver's window
|
// xscreensaver's window
|
||||||
Window m_xscreensaver;
|
Window m_xscreensaver;
|
||||||
|
@ -124,8 +110,8 @@ private:
|
||||||
// xscreensaver activation state
|
// xscreensaver activation state
|
||||||
bool m_xscreensaverActive;
|
bool m_xscreensaverActive;
|
||||||
|
|
||||||
// dummy window to receive xscreensaver repsonses
|
// old event mask on root window
|
||||||
Window m_xscreensaverSink;
|
long m_rootEventMask;
|
||||||
|
|
||||||
// potential xscreensaver windows being watched
|
// potential xscreensaver windows being watched
|
||||||
CWatchList m_watchWindows;
|
CWatchList m_watchWindows;
|
||||||
|
@ -135,7 +121,6 @@ private:
|
||||||
Atom m_atomScreenSaverVersion;
|
Atom m_atomScreenSaverVersion;
|
||||||
Atom m_atomScreenSaverActivate;
|
Atom m_atomScreenSaverActivate;
|
||||||
Atom m_atomScreenSaverDeactivate;
|
Atom m_atomScreenSaverDeactivate;
|
||||||
Atom m_atomSynergyScreenSaver;
|
|
||||||
|
|
||||||
// built-in screen saver settings
|
// built-in screen saver settings
|
||||||
int m_timeout;
|
int m_timeout;
|
||||||
|
@ -151,11 +136,8 @@ private:
|
||||||
// to activate the screen saver even if disabled.
|
// to activate the screen saver even if disabled.
|
||||||
bool m_suppressDisable;
|
bool m_suppressDisable;
|
||||||
|
|
||||||
// true iff the disabled job timer is installed
|
// the disable timer (NULL if not installed)
|
||||||
bool m_disableJobInstalled;
|
CEventQueueTimer* m_disableTimer;
|
||||||
|
|
||||||
// the job used to invoke disableCallback
|
|
||||||
IJob* m_disableJob;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -49,7 +49,7 @@ libplatform_a_SOURCES = \
|
||||||
CXWindowsClipboardTextConverter.cpp \
|
CXWindowsClipboardTextConverter.cpp \
|
||||||
CXWindowsClipboardUCS2Converter.cpp \
|
CXWindowsClipboardUCS2Converter.cpp \
|
||||||
CXWindowsClipboardUTF8Converter.cpp \
|
CXWindowsClipboardUTF8Converter.cpp \
|
||||||
CXWindowsEventQueue.cpp \
|
CXWindowsEventQueueBuffer.cpp \
|
||||||
CXWindowsKeyMapper.cpp \
|
CXWindowsKeyMapper.cpp \
|
||||||
CXWindowsScreen.cpp \
|
CXWindowsScreen.cpp \
|
||||||
CXWindowsScreenSaver.cpp \
|
CXWindowsScreenSaver.cpp \
|
||||||
|
@ -58,7 +58,7 @@ libplatform_a_SOURCES = \
|
||||||
CXWindowsClipboardTextConverter.h \
|
CXWindowsClipboardTextConverter.h \
|
||||||
CXWindowsClipboardUCS2Converter.h \
|
CXWindowsClipboardUCS2Converter.h \
|
||||||
CXWindowsClipboardUTF8Converter.h \
|
CXWindowsClipboardUTF8Converter.h \
|
||||||
CXWindowsEventQueue.h \
|
CXWindowsEventQueueBuffer.h \
|
||||||
CXWindowsKeyMapper.h \
|
CXWindowsKeyMapper.h \
|
||||||
CXWindowsScreen.h \
|
CXWindowsScreen.h \
|
||||||
CXWindowsScreenSaver.h \
|
CXWindowsScreenSaver.h \
|
||||||
|
|
|
@ -0,0 +1,189 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2004 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* This package is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* found in the file COPYING that should have accompanied this file.
|
||||||
|
*
|
||||||
|
* This package is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "CClientListener.h"
|
||||||
|
#include "CClientProxy.h"
|
||||||
|
#include "CClientProxyUnknown.h"
|
||||||
|
#include "CPacketStreamFilter.h"
|
||||||
|
#include "IStreamFilterFactory.h"
|
||||||
|
#include "IDataSocket.h"
|
||||||
|
#include "IListenSocket.h"
|
||||||
|
#include "ISocketFactory.h"
|
||||||
|
#include "XSocket.h"
|
||||||
|
#include "CLog.h"
|
||||||
|
#include "IEventQueue.h"
|
||||||
|
#include "TMethodEventJob.h"
|
||||||
|
|
||||||
|
//
|
||||||
|
// CClientListener
|
||||||
|
//
|
||||||
|
|
||||||
|
CEvent::Type CClientListener::s_connectedEvent = CEvent::kUnknown;
|
||||||
|
|
||||||
|
CClientListener::CClientListener(const CNetworkAddress& address,
|
||||||
|
ISocketFactory* socketFactory,
|
||||||
|
IStreamFilterFactory* streamFilterFactory) :
|
||||||
|
m_socketFactory(socketFactory),
|
||||||
|
m_streamFilterFactory(streamFilterFactory)
|
||||||
|
{
|
||||||
|
assert(m_socketFactory != NULL);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// create listen socket
|
||||||
|
m_listen = m_socketFactory->createListen();
|
||||||
|
|
||||||
|
// bind listen address
|
||||||
|
LOG((CLOG_DEBUG1 "binding listen socket"));
|
||||||
|
m_listen->bind(address);
|
||||||
|
}
|
||||||
|
catch (XSocketAddressInUse& e) {
|
||||||
|
delete m_listen;
|
||||||
|
delete m_socketFactory;
|
||||||
|
delete m_streamFilterFactory;
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
catch (XBase& e) {
|
||||||
|
delete m_listen;
|
||||||
|
delete m_socketFactory;
|
||||||
|
delete m_streamFilterFactory;
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
LOG((CLOG_DEBUG1 "listening for clients"));
|
||||||
|
|
||||||
|
// setup event handler
|
||||||
|
EVENTQUEUE->adoptHandler(IListenSocket::getConnectingEvent(), m_listen,
|
||||||
|
new TMethodEventJob<CClientListener>(this,
|
||||||
|
&CClientListener::handleClientConnecting));
|
||||||
|
}
|
||||||
|
|
||||||
|
CClientListener::~CClientListener()
|
||||||
|
{
|
||||||
|
LOG((CLOG_DEBUG1 "stop listening for clients"));
|
||||||
|
|
||||||
|
// discard already connected clients
|
||||||
|
for (CNewClients::iterator index = m_newClients.begin();
|
||||||
|
index != m_newClients.end(); ++index) {
|
||||||
|
CClientProxyUnknown* client = *index;
|
||||||
|
EVENTQUEUE->removeHandler(client);
|
||||||
|
delete client;
|
||||||
|
}
|
||||||
|
|
||||||
|
// discard waiting clients
|
||||||
|
CClientProxy* client = getNextClient();
|
||||||
|
while (client != NULL) {
|
||||||
|
delete client;
|
||||||
|
client = getNextClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
EVENTQUEUE->removeHandler(IListenSocket::getConnectingEvent(), m_listen);
|
||||||
|
delete m_listen;
|
||||||
|
delete m_socketFactory;
|
||||||
|
delete m_streamFilterFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
CClientProxy*
|
||||||
|
CClientListener::getNextClient()
|
||||||
|
{
|
||||||
|
CClientProxy* client = NULL;
|
||||||
|
if (!m_waitingClients.empty()) {
|
||||||
|
client = m_waitingClients.front();
|
||||||
|
m_waitingClients.pop_front();
|
||||||
|
EVENTQUEUE->removeHandler(CClientProxy::getDisconnectedEvent(), client);
|
||||||
|
}
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
|
||||||
|
CEvent::Type
|
||||||
|
CClientListener::getConnectedEvent()
|
||||||
|
{
|
||||||
|
return CEvent::registerTypeOnce(s_connectedEvent,
|
||||||
|
"CClientListener::connected");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CClientListener::handleClientConnecting(const CEvent&, void*)
|
||||||
|
{
|
||||||
|
// accept client connection
|
||||||
|
IStream* stream = m_listen->accept();
|
||||||
|
if (stream == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LOG((CLOG_NOTE "accepted client connection"));
|
||||||
|
|
||||||
|
// filter socket messages, including a packetizing filter
|
||||||
|
if (m_streamFilterFactory != NULL) {
|
||||||
|
stream = m_streamFilterFactory->create(stream, true);
|
||||||
|
}
|
||||||
|
stream = new CPacketStreamFilter(stream, true);
|
||||||
|
|
||||||
|
// create proxy for unknown client
|
||||||
|
CClientProxyUnknown* client = new CClientProxyUnknown(stream, 30.0);
|
||||||
|
m_newClients.insert(client);
|
||||||
|
|
||||||
|
// watch for events from unknown client
|
||||||
|
EVENTQUEUE->adoptHandler(CClientProxyUnknown::getSuccessEvent(), client,
|
||||||
|
new TMethodEventJob<CClientListener>(this,
|
||||||
|
&CClientListener::handleUnknownClient, client));
|
||||||
|
EVENTQUEUE->adoptHandler(CClientProxyUnknown::getFailureEvent(), client,
|
||||||
|
new TMethodEventJob<CClientListener>(this,
|
||||||
|
&CClientListener::handleUnknownClient, client));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CClientListener::handleUnknownClient(const CEvent&, void* vclient)
|
||||||
|
{
|
||||||
|
CClientProxyUnknown* unknownClient =
|
||||||
|
reinterpret_cast<CClientProxyUnknown*>(vclient);
|
||||||
|
|
||||||
|
// we should have the client in our new client list
|
||||||
|
assert(m_newClients.count(unknownClient) == 1);
|
||||||
|
|
||||||
|
// get the real client proxy and install it
|
||||||
|
CClientProxy* client = unknownClient->orphanClientProxy();
|
||||||
|
if (client != NULL) {
|
||||||
|
// handshake was successful
|
||||||
|
m_waitingClients.push_back(client);
|
||||||
|
EVENTQUEUE->addEvent(CEvent(getConnectedEvent(), this));
|
||||||
|
|
||||||
|
// watch for client to disconnect while it's in our queue
|
||||||
|
EVENTQUEUE->adoptHandler(CClientProxy::getDisconnectedEvent(), client,
|
||||||
|
new TMethodEventJob<CClientListener>(this,
|
||||||
|
&CClientListener::handleClientDisconnected,
|
||||||
|
client));
|
||||||
|
}
|
||||||
|
|
||||||
|
// now finished with unknown client
|
||||||
|
EVENTQUEUE->removeHandler(CClientProxyUnknown::getSuccessEvent(), client);
|
||||||
|
EVENTQUEUE->removeHandler(CClientProxyUnknown::getFailureEvent(), client);
|
||||||
|
m_newClients.erase(unknownClient);
|
||||||
|
delete unknownClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CClientListener::handleClientDisconnected(const CEvent&, void* vclient)
|
||||||
|
{
|
||||||
|
CClientProxy* client = reinterpret_cast<CClientProxy*>(vclient);
|
||||||
|
|
||||||
|
// find client in waiting clients queue
|
||||||
|
for (CWaitingClients::iterator i = m_waitingClients.begin(),
|
||||||
|
n = m_waitingClients.end(); i != n; ++i) {
|
||||||
|
if (*i == client) {
|
||||||
|
m_waitingClients.erase(i);
|
||||||
|
EVENTQUEUE->removeHandler(CClientProxy::getDisconnectedEvent(),
|
||||||
|
client);
|
||||||
|
delete client;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,76 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2004 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* This package is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* found in the file COPYING that should have accompanied this file.
|
||||||
|
*
|
||||||
|
* This package is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CCLIENTLISTENER_H
|
||||||
|
#define CCLIENTLISTENER_H
|
||||||
|
|
||||||
|
#include "CConfig.h"
|
||||||
|
#include "CEvent.h"
|
||||||
|
#include "stddeque.h"
|
||||||
|
#include "stdset.h"
|
||||||
|
|
||||||
|
class CClientProxy;
|
||||||
|
class CClientProxyUnknown;
|
||||||
|
class CNetworkAddress;
|
||||||
|
class IListenSocket;
|
||||||
|
class ISocketFactory;
|
||||||
|
class IStreamFilterFactory;
|
||||||
|
|
||||||
|
class CClientListener {
|
||||||
|
public:
|
||||||
|
// The factories are adopted.
|
||||||
|
CClientListener(const CNetworkAddress&,
|
||||||
|
ISocketFactory*, IStreamFilterFactory*);
|
||||||
|
~CClientListener();
|
||||||
|
|
||||||
|
//! @name accessors
|
||||||
|
//@{
|
||||||
|
|
||||||
|
//! Get next connected client
|
||||||
|
/*!
|
||||||
|
Returns the next connected client and removes it from the internal
|
||||||
|
list. The client is responsible for deleting the returned client.
|
||||||
|
Returns NULL if no clients are available.
|
||||||
|
*/
|
||||||
|
CClientProxy* getNextClient();
|
||||||
|
|
||||||
|
//! Get connected event type
|
||||||
|
/*!
|
||||||
|
Returns the connected event type. This is sent whenever a
|
||||||
|
a client connects.
|
||||||
|
*/
|
||||||
|
static CEvent::Type getConnectedEvent();
|
||||||
|
|
||||||
|
//@}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// client connection event handlers
|
||||||
|
void handleClientConnecting(const CEvent&, void*);
|
||||||
|
void handleUnknownClient(const CEvent&, void*);
|
||||||
|
void handleClientDisconnected(const CEvent&, void*);
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef std::set<CClientProxyUnknown*> CNewClients;
|
||||||
|
typedef std::deque<CClientProxy*> CWaitingClients;
|
||||||
|
|
||||||
|
IListenSocket* m_listen;
|
||||||
|
ISocketFactory* m_socketFactory;
|
||||||
|
IStreamFilterFactory* m_streamFilterFactory;
|
||||||
|
CNewClients m_newClients;
|
||||||
|
CWaitingClients m_waitingClients;
|
||||||
|
|
||||||
|
static CEvent::Type s_connectedEvent;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -13,15 +13,18 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "CClientProxy.h"
|
#include "CClientProxy.h"
|
||||||
|
#include "CProtocolUtil.h"
|
||||||
#include "IStream.h"
|
#include "IStream.h"
|
||||||
|
#include "CLog.h"
|
||||||
|
|
||||||
//
|
//
|
||||||
// CClientProxy
|
// CClientProxy
|
||||||
//
|
//
|
||||||
|
|
||||||
CClientProxy::CClientProxy(IServer* server,
|
CEvent::Type CClientProxy::s_readyEvent = CEvent::kUnknown;
|
||||||
const CString& name, IStream* stream) :
|
CEvent::Type CClientProxy::s_disconnectedEvent = CEvent::kUnknown;
|
||||||
m_server(server),
|
|
||||||
|
CClientProxy::CClientProxy(const CString& name, IStream* stream) :
|
||||||
m_name(name),
|
m_name(name),
|
||||||
m_stream(stream)
|
m_stream(stream)
|
||||||
{
|
{
|
||||||
|
@ -33,10 +36,14 @@ CClientProxy::~CClientProxy()
|
||||||
delete m_stream;
|
delete m_stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
IServer*
|
void
|
||||||
CClientProxy::getServer() const
|
CClientProxy::close(const char* msg)
|
||||||
{
|
{
|
||||||
return m_server;
|
LOG((CLOG_DEBUG1 "send close \"%s\" to \"%s\"", msg, getName().c_str()));
|
||||||
|
CProtocolUtil::writef(getStream(), msg);
|
||||||
|
|
||||||
|
// force the close to be sent before we return
|
||||||
|
getStream()->flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
IStream*
|
IStream*
|
||||||
|
@ -51,8 +58,22 @@ CClientProxy::getName() const
|
||||||
return m_name;
|
return m_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
const CMutex*
|
CEvent::Type
|
||||||
CClientProxy::getMutex() const
|
CClientProxy::getReadyEvent()
|
||||||
{
|
{
|
||||||
return &m_mutex;
|
return CEvent::registerTypeOnce(s_readyEvent,
|
||||||
|
"CClientProxy::ready");
|
||||||
|
}
|
||||||
|
|
||||||
|
CEvent::Type
|
||||||
|
CClientProxy::getDisconnectedEvent()
|
||||||
|
{
|
||||||
|
return CEvent::registerTypeOnce(s_disconnectedEvent,
|
||||||
|
"CClientProxy::disconnected");
|
||||||
|
}
|
||||||
|
|
||||||
|
void*
|
||||||
|
CClientProxy::getEventTarget() const
|
||||||
|
{
|
||||||
|
return static_cast<IScreen*>(const_cast<CClientProxy*>(this));
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,11 +16,10 @@
|
||||||
#define CCLIENTPROXY_H
|
#define CCLIENTPROXY_H
|
||||||
|
|
||||||
#include "IClient.h"
|
#include "IClient.h"
|
||||||
#include "CMutex.h"
|
#include "CEvent.h"
|
||||||
#include "CString.h"
|
#include "CString.h"
|
||||||
|
|
||||||
class IStream;
|
class IStream;
|
||||||
class IServer;
|
|
||||||
|
|
||||||
//! Generic proxy for client
|
//! Generic proxy for client
|
||||||
class CClientProxy : public IClient {
|
class CClientProxy : public IClient {
|
||||||
|
@ -28,17 +27,21 @@ public:
|
||||||
/*!
|
/*!
|
||||||
\c name is the name of the client.
|
\c name is the name of the client.
|
||||||
*/
|
*/
|
||||||
CClientProxy(IServer* server, const CString& name, IStream* adoptedStream);
|
CClientProxy(const CString& name, IStream* adoptedStream);
|
||||||
~CClientProxy();
|
~CClientProxy();
|
||||||
|
|
||||||
//! @name accessors
|
//! @name manipulators
|
||||||
//@{
|
//@{
|
||||||
|
|
||||||
//! Get server
|
//! Disconnect
|
||||||
/*!
|
/*!
|
||||||
Returns the server passed to the c'tor.
|
Ask the client to disconnect, using \p msg as the reason.
|
||||||
*/
|
*/
|
||||||
IServer* getServer() const;
|
void close(const char* msg);
|
||||||
|
|
||||||
|
//@}
|
||||||
|
//! @name accessors
|
||||||
|
//@{
|
||||||
|
|
||||||
//! Get stream
|
//! Get stream
|
||||||
/*!
|
/*!
|
||||||
|
@ -46,12 +49,31 @@ public:
|
||||||
*/
|
*/
|
||||||
IStream* getStream() const;
|
IStream* getStream() const;
|
||||||
|
|
||||||
|
//! Get ready event type
|
||||||
|
/*!
|
||||||
|
Returns the ready event type. This is sent when the client has
|
||||||
|
completed the initial handshake. Until it is sent, the client is
|
||||||
|
not fully connected.
|
||||||
|
*/
|
||||||
|
static CEvent::Type getReadyEvent();
|
||||||
|
|
||||||
|
//! Get disconnect event type
|
||||||
|
/*!
|
||||||
|
Returns the disconnect event type. This is sent when the client
|
||||||
|
disconnects or is disconnected. The target is getEventTarget().
|
||||||
|
*/
|
||||||
|
static CEvent::Type getDisconnectedEvent();
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
|
// IScreen
|
||||||
|
virtual void* getEventTarget() const;
|
||||||
|
virtual bool getClipboard(ClipboardID id, IClipboard*) const = 0;
|
||||||
|
virtual void getShape(SInt32& x, SInt32& y,
|
||||||
|
SInt32& width, SInt32& height) const = 0;
|
||||||
|
virtual void getCursorPos(SInt32& x, SInt32& y) const = 0;
|
||||||
|
|
||||||
// IClient overrides
|
// IClient overrides
|
||||||
virtual void open() = 0;
|
|
||||||
virtual void mainLoop() = 0;
|
|
||||||
virtual void close() = 0;
|
|
||||||
virtual void enter(SInt32 xAbs, SInt32 yAbs,
|
virtual void enter(SInt32 xAbs, SInt32 yAbs,
|
||||||
UInt32 seqNum, KeyModifierMask mask,
|
UInt32 seqNum, KeyModifierMask mask,
|
||||||
bool forScreensaver) = 0;
|
bool forScreensaver) = 0;
|
||||||
|
@ -71,25 +93,13 @@ public:
|
||||||
virtual void resetOptions() = 0;
|
virtual void resetOptions() = 0;
|
||||||
virtual void setOptions(const COptionsList& options) = 0;
|
virtual void setOptions(const COptionsList& options) = 0;
|
||||||
virtual CString getName() const;
|
virtual CString getName() const;
|
||||||
virtual SInt32 getJumpZoneSize() const = 0;
|
|
||||||
virtual void getShape(SInt32& x, SInt32& y,
|
|
||||||
SInt32& width, SInt32& height) const = 0;
|
|
||||||
virtual void getCursorPos(SInt32& x, SInt32& y) const = 0;
|
|
||||||
virtual void getCursorCenter(SInt32& x, SInt32& y) const = 0;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
//! Get mutex
|
|
||||||
/*!
|
|
||||||
Returns the mutex for this object. Subclasses should use this
|
|
||||||
mutex to protect their data.
|
|
||||||
*/
|
|
||||||
const CMutex* getMutex() const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CMutex m_mutex;
|
|
||||||
IServer* m_server;
|
|
||||||
CString m_name;
|
CString m_name;
|
||||||
IStream* m_stream;
|
IStream* m_stream;
|
||||||
|
|
||||||
|
static CEvent::Type s_readyEvent;
|
||||||
|
static CEvent::Type s_disconnectedEvent;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -13,12 +13,9 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "CClientProxy1_0.h"
|
#include "CClientProxy1_0.h"
|
||||||
#include "CServer.h"
|
|
||||||
#include "CClipboard.h"
|
|
||||||
#include "CProtocolUtil.h"
|
#include "CProtocolUtil.h"
|
||||||
#include "XSynergy.h"
|
#include "XSynergy.h"
|
||||||
#include "IStream.h"
|
#include "IStream.h"
|
||||||
#include "CLock.h"
|
|
||||||
#include "CLog.h"
|
#include "CLog.h"
|
||||||
#include "IEventQueue.h"
|
#include "IEventQueue.h"
|
||||||
#include "TMethodEventJob.h"
|
#include "TMethodEventJob.h"
|
||||||
|
@ -28,16 +25,12 @@
|
||||||
// CClientProxy1_0
|
// CClientProxy1_0
|
||||||
//
|
//
|
||||||
|
|
||||||
CClientProxy1_0::CClientProxy1_0(IServer* server,
|
CClientProxy1_0::CClientProxy1_0(const CString& name, IStream* stream) :
|
||||||
const CString& name, IStream* stream) :
|
CClientProxy(name, stream),
|
||||||
CClientProxy(server, name, stream),
|
|
||||||
m_heartbeatAlarm(kHeartRate * kHeartBeatsUntilDeath),
|
m_heartbeatAlarm(kHeartRate * kHeartBeatsUntilDeath),
|
||||||
m_heartbeatTimer(NULL)
|
m_heartbeatTimer(NULL),
|
||||||
|
m_parser(&CClientProxy1_0::parseHandshakeMessage)
|
||||||
{
|
{
|
||||||
for (UInt32 i = 0; i < kClipboardEnd; ++i) {
|
|
||||||
m_clipboardDirty[i] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// install event handlers
|
// install event handlers
|
||||||
EVENTQUEUE->adoptHandler(IStream::getInputReadyEvent(),
|
EVENTQUEUE->adoptHandler(IStream::getInputReadyEvent(),
|
||||||
stream->getEventTarget(),
|
stream->getEventTarget(),
|
||||||
|
@ -59,7 +52,8 @@ CClientProxy1_0::CClientProxy1_0(IServer* server,
|
||||||
new TMethodEventJob<CClientProxy1_0>(this,
|
new TMethodEventJob<CClientProxy1_0>(this,
|
||||||
&CClientProxy1_0::handleFlatline, NULL));
|
&CClientProxy1_0::handleFlatline, NULL));
|
||||||
|
|
||||||
// FIXME -- open() replacement must install initial heartbeat timer
|
LOG((CLOG_DEBUG1 "querying client \"%s\" info", getName().c_str()));
|
||||||
|
CProtocolUtil::writef(getStream(), kMsgQInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
CClientProxy1_0::~CClientProxy1_0()
|
CClientProxy1_0::~CClientProxy1_0()
|
||||||
|
@ -70,11 +64,9 @@ CClientProxy1_0::~CClientProxy1_0()
|
||||||
void
|
void
|
||||||
CClientProxy1_0::disconnect()
|
CClientProxy1_0::disconnect()
|
||||||
{
|
{
|
||||||
CLock lock(getMutex());
|
|
||||||
removeHandlers();
|
removeHandlers();
|
||||||
// FIXME -- send disconnect event (server should be listening for this)
|
|
||||||
getStream()->flush();
|
|
||||||
getStream()->close();
|
getStream()->close();
|
||||||
|
EVENTQUEUE->addEvent(CEvent(getDisconnectedEvent(), getEventTarget()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -98,7 +90,6 @@ CClientProxy1_0::removeHandlers()
|
||||||
void
|
void
|
||||||
CClientProxy1_0::addHeartbeatTimer()
|
CClientProxy1_0::addHeartbeatTimer()
|
||||||
{
|
{
|
||||||
CLock lock(getMutex());
|
|
||||||
if (m_heartbeatAlarm > 0.0) {
|
if (m_heartbeatAlarm > 0.0) {
|
||||||
m_heartbeatTimer = EVENTQUEUE->newOneShotTimer(m_heartbeatAlarm, this);
|
m_heartbeatTimer = EVENTQUEUE->newOneShotTimer(m_heartbeatAlarm, this);
|
||||||
}
|
}
|
||||||
|
@ -107,7 +98,6 @@ CClientProxy1_0::addHeartbeatTimer()
|
||||||
void
|
void
|
||||||
CClientProxy1_0::removeHeartbeatTimer()
|
CClientProxy1_0::removeHeartbeatTimer()
|
||||||
{
|
{
|
||||||
CLock lock(getMutex());
|
|
||||||
if (m_heartbeatTimer != NULL) {
|
if (m_heartbeatTimer != NULL) {
|
||||||
EVENTQUEUE->deleteTimer(m_heartbeatTimer);
|
EVENTQUEUE->deleteTimer(m_heartbeatTimer);
|
||||||
m_heartbeatTimer = NULL;
|
m_heartbeatTimer = NULL;
|
||||||
|
@ -130,7 +120,7 @@ CClientProxy1_0::handleData(const CEvent&, void*)
|
||||||
|
|
||||||
// parse message
|
// parse message
|
||||||
LOG((CLOG_DEBUG2 "msg from \"%s\": %c%c%c%c", getName().c_str(), code[0], code[1], code[2], code[3]));
|
LOG((CLOG_DEBUG2 "msg from \"%s\": %c%c%c%c", getName().c_str(), code[0], code[1], code[2], code[3]));
|
||||||
if (!parseMessage(code)) {
|
if (!(this->*m_parser)(code)) {
|
||||||
LOG((CLOG_ERR "invalid message from client \"%s\"", getName().c_str()));
|
LOG((CLOG_ERR "invalid message from client \"%s\"", getName().c_str()));
|
||||||
disconnect();
|
disconnect();
|
||||||
return;
|
return;
|
||||||
|
@ -145,11 +135,35 @@ CClientProxy1_0::handleData(const CEvent&, void*)
|
||||||
addHeartbeatTimer();
|
addHeartbeatTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CClientProxy1_0::parseHandshakeMessage(const UInt8* code)
|
||||||
|
{
|
||||||
|
if (memcmp(code, kMsgCNoop, 4) == 0) {
|
||||||
|
// discard no-ops
|
||||||
|
LOG((CLOG_DEBUG2 "no-op from", getName().c_str()));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (memcmp(code, kMsgDInfo, 4) == 0) {
|
||||||
|
// future messages get parsed by parseMessage
|
||||||
|
m_parser = &CClientProxy1_0::parseMessage;
|
||||||
|
if (recvInfo()) {
|
||||||
|
EVENTQUEUE->addEvent(CEvent(getReadyEvent(), getEventTarget()));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CClientProxy1_0::parseMessage(const UInt8* code)
|
CClientProxy1_0::parseMessage(const UInt8* code)
|
||||||
{
|
{
|
||||||
if (memcmp(code, kMsgDInfo, 4) == 0) {
|
if (memcmp(code, kMsgDInfo, 4) == 0) {
|
||||||
return recvInfo(true);
|
if (recvInfo()) {
|
||||||
|
EVENTQUEUE->addEvent(
|
||||||
|
CEvent(getShapeChangedEvent(), getEventTarget()));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
else if (memcmp(code, kMsgCNoop, 4) == 0) {
|
else if (memcmp(code, kMsgCNoop, 4) == 0) {
|
||||||
// discard no-ops
|
// discard no-ops
|
||||||
|
@ -168,14 +182,14 @@ CClientProxy1_0::parseMessage(const UInt8* code)
|
||||||
void
|
void
|
||||||
CClientProxy1_0::handleDisconnect(const CEvent&, void*)
|
CClientProxy1_0::handleDisconnect(const CEvent&, void*)
|
||||||
{
|
{
|
||||||
LOG((CLOG_NOTE "client \"%s\" disconnected", getName().c_str()));
|
LOG((CLOG_NOTE "client \"%s\" has disconnected", getName().c_str()));
|
||||||
disconnect();
|
disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CClientProxy1_0::handleWriteError(const CEvent&, void*)
|
CClientProxy1_0::handleWriteError(const CEvent&, void*)
|
||||||
{
|
{
|
||||||
LOG((CLOG_ERR "error writing to client \"%s\"", getName().c_str()));
|
LOG((CLOG_WARN "error writing to client \"%s\"", getName().c_str()));
|
||||||
disconnect();
|
disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,44 +201,28 @@ CClientProxy1_0::handleFlatline(const CEvent&, void*)
|
||||||
disconnect();
|
disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME -- replace this
|
bool
|
||||||
void
|
CClientProxy1_0::getClipboard(ClipboardID id, IClipboard* clipboard) const
|
||||||
CClientProxy1_0::open()
|
|
||||||
{
|
{
|
||||||
// send request
|
CClipboard::copy(clipboard, &m_clipboard[id].m_clipboard);
|
||||||
LOG((CLOG_DEBUG1 "querying client \"%s\" info", getName().c_str()));
|
return true;
|
||||||
CProtocolUtil::writef(getStream(), kMsgQInfo);
|
|
||||||
getStream()->flush();
|
|
||||||
|
|
||||||
// wait for and verify reply
|
|
||||||
UInt8 code[4];
|
|
||||||
for (;;) {
|
|
||||||
UInt32 n = getStream()->read(code, 4);
|
|
||||||
if (n == 4) {
|
|
||||||
if (memcmp(code, kMsgCNoop, 4) == 0) {
|
|
||||||
// discard heartbeats
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (memcmp(code, kMsgDInfo, 4) == 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw XBadClient();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle reply
|
|
||||||
recvInfo(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME -- replace this
|
|
||||||
void
|
void
|
||||||
CClientProxy1_0::close()
|
CClientProxy1_0::getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) const
|
||||||
{
|
{
|
||||||
LOG((CLOG_DEBUG1 "send close to \"%s\"", getName().c_str()));
|
x = m_info.m_x;
|
||||||
CProtocolUtil::writef(getStream(), kMsgCClose);
|
y = m_info.m_y;
|
||||||
|
w = m_info.m_w;
|
||||||
|
h = m_info.m_h;
|
||||||
|
}
|
||||||
|
|
||||||
// force the close to be sent before we return
|
void
|
||||||
getStream()->flush();
|
CClientProxy1_0::getCursorPos(SInt32& x, SInt32& y) const
|
||||||
|
{
|
||||||
|
assert(0 && "shouldn't be called");
|
||||||
|
x = m_info.m_mx;
|
||||||
|
y = m_info.m_my;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -250,10 +248,9 @@ void
|
||||||
CClientProxy1_0::setClipboard(ClipboardID id, const CString& data)
|
CClientProxy1_0::setClipboard(ClipboardID id, const CString& data)
|
||||||
{
|
{
|
||||||
// ignore if this clipboard is already clean
|
// ignore if this clipboard is already clean
|
||||||
CLock lock(getMutex());
|
if (m_clipboard[id].m_dirty) {
|
||||||
if (m_clipboardDirty[id]) {
|
|
||||||
// this clipboard is now clean
|
// this clipboard is now clean
|
||||||
m_clipboardDirty[id] = false;
|
m_clipboard[id].m_dirty = false;
|
||||||
|
|
||||||
LOG((CLOG_DEBUG "send clipboard %d to \"%s\" size=%d", id, getName().c_str(), data.size()));
|
LOG((CLOG_DEBUG "send clipboard %d to \"%s\" size=%d", id, getName().c_str(), data.size()));
|
||||||
CProtocolUtil::writef(getStream(), kMsgDClipboard, id, 0, &data);
|
CProtocolUtil::writef(getStream(), kMsgDClipboard, id, 0, &data);
|
||||||
|
@ -267,15 +264,13 @@ CClientProxy1_0::grabClipboard(ClipboardID id)
|
||||||
CProtocolUtil::writef(getStream(), kMsgCClipboard, id, 0);
|
CProtocolUtil::writef(getStream(), kMsgCClipboard, id, 0);
|
||||||
|
|
||||||
// this clipboard is now dirty
|
// this clipboard is now dirty
|
||||||
CLock lock(getMutex());
|
m_clipboard[id].m_dirty = true;
|
||||||
m_clipboardDirty[id] = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CClientProxy1_0::setClipboardDirty(ClipboardID id, bool dirty)
|
CClientProxy1_0::setClipboardDirty(ClipboardID id, bool dirty)
|
||||||
{
|
{
|
||||||
CLock lock(getMutex());
|
m_clipboard[id].m_dirty = dirty;
|
||||||
m_clipboardDirty[id] = dirty;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -342,7 +337,6 @@ CClientProxy1_0::resetOptions()
|
||||||
CProtocolUtil::writef(getStream(), kMsgCResetOptions);
|
CProtocolUtil::writef(getStream(), kMsgCResetOptions);
|
||||||
|
|
||||||
// reset heart rate and death
|
// reset heart rate and death
|
||||||
CLock lock(getMutex());
|
|
||||||
m_heartbeatAlarm = kHeartRate * kHeartBeatsUntilDeath;
|
m_heartbeatAlarm = kHeartRate * kHeartBeatsUntilDeath;
|
||||||
removeHeartbeatTimer();
|
removeHeartbeatTimer();
|
||||||
addHeartbeatTimer();
|
addHeartbeatTimer();
|
||||||
|
@ -355,7 +349,6 @@ CClientProxy1_0::setOptions(const COptionsList& options)
|
||||||
CProtocolUtil::writef(getStream(), kMsgDSetOptions, &options);
|
CProtocolUtil::writef(getStream(), kMsgDSetOptions, &options);
|
||||||
|
|
||||||
// check options
|
// check options
|
||||||
CLock lock(getMutex());
|
|
||||||
for (UInt32 i = 0, n = options.size(); i < n; i += 2) {
|
for (UInt32 i = 0, n = options.size(); i < n; i += 2) {
|
||||||
if (options[i] == kOptionHeartbeat) {
|
if (options[i] == kOptionHeartbeat) {
|
||||||
double rate = 1.0e-3 * static_cast<double>(options[i + 1]);
|
double rate = 1.0e-3 * static_cast<double>(options[i + 1]);
|
||||||
|
@ -369,43 +362,9 @@ CClientProxy1_0::setOptions(const COptionsList& options)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SInt32
|
|
||||||
CClientProxy1_0::getJumpZoneSize() const
|
|
||||||
{
|
|
||||||
CLock lock(getMutex());
|
|
||||||
return m_info.m_zoneSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CClientProxy1_0::getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) const
|
|
||||||
{
|
|
||||||
CLock lock(getMutex());
|
|
||||||
x = m_info.m_x;
|
|
||||||
y = m_info.m_y;
|
|
||||||
w = m_info.m_w;
|
|
||||||
h = m_info.m_h;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CClientProxy1_0::getCursorPos(SInt32&, SInt32&) const
|
|
||||||
{
|
|
||||||
assert(0 && "shouldn't be called");
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CClientProxy1_0::getCursorCenter(SInt32& x, SInt32& y) const
|
|
||||||
{
|
|
||||||
CLock lock(getMutex());
|
|
||||||
x = m_info.m_mx;
|
|
||||||
y = m_info.m_my;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CClientProxy1_0::recvInfo(bool notify)
|
CClientProxy1_0::recvInfo()
|
||||||
{
|
{
|
||||||
{
|
|
||||||
CLock lock(getMutex());
|
|
||||||
|
|
||||||
// parse the message
|
// parse the message
|
||||||
SInt16 x, y, w, h, zoneSize, mx, my;
|
SInt16 x, y, w, h, zoneSize, mx, my;
|
||||||
if (!CProtocolUtil::readf(getStream(), kMsgDInfo + 4,
|
if (!CProtocolUtil::readf(getStream(), kMsgDInfo + 4,
|
||||||
|
@ -430,12 +389,6 @@ CClientProxy1_0::recvInfo(bool notify)
|
||||||
m_info.m_zoneSize = zoneSize;
|
m_info.m_zoneSize = zoneSize;
|
||||||
m_info.m_mx = mx;
|
m_info.m_mx = mx;
|
||||||
m_info.m_my = my;
|
m_info.m_my = my;
|
||||||
}
|
|
||||||
|
|
||||||
// tell server of change
|
|
||||||
if (notify) {
|
|
||||||
getServer()->onInfoChanged(getName(), m_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
// acknowledge receipt
|
// acknowledge receipt
|
||||||
LOG((CLOG_DEBUG1 "send info ack to \"%s\"", getName().c_str()));
|
LOG((CLOG_DEBUG1 "send info ack to \"%s\"", getName().c_str()));
|
||||||
|
@ -461,9 +414,17 @@ CClientProxy1_0::recvClipboard()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// send update. this calls us back to reset our clipboard dirty flag
|
// save clipboard
|
||||||
// so don't hold a lock during the call.
|
m_clipboard[id].m_clipboard.unmarshall(data, 0);
|
||||||
getServer()->onClipboardChanged(id, seqNum, data);
|
m_clipboard[id].m_sequenceNumber = seqNum;
|
||||||
|
|
||||||
|
// notify
|
||||||
|
CClipboardInfo* info = new CClipboardInfo;
|
||||||
|
info->m_id = id;
|
||||||
|
info->m_sequenceNumber = seqNum;
|
||||||
|
EVENTQUEUE->addEvent(CEvent(getClipboardChangedEvent(),
|
||||||
|
getEventTarget(), info));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -483,8 +444,25 @@ CClientProxy1_0::recvGrabClipboard()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// send update. this calls us back to reset our clipboard dirty flag
|
// notify
|
||||||
// so don't hold a lock during the call.
|
CClipboardInfo* info = new CClipboardInfo;
|
||||||
getServer()->onGrabClipboard(getName(), id, seqNum);
|
info->m_id = id;
|
||||||
|
info->m_sequenceNumber = seqNum;
|
||||||
|
EVENTQUEUE->addEvent(CEvent(getClipboardGrabbedEvent(),
|
||||||
|
getEventTarget(), info));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// CClientProxy1_0::CClientClipboard
|
||||||
|
//
|
||||||
|
|
||||||
|
CClientProxy1_0::CClientClipboard::CClientClipboard() :
|
||||||
|
m_clipboard(),
|
||||||
|
m_sequenceNumber(0),
|
||||||
|
m_dirty(true)
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#define CCLIENTPROXY1_0_H
|
#define CCLIENTPROXY1_0_H
|
||||||
|
|
||||||
#include "CClientProxy.h"
|
#include "CClientProxy.h"
|
||||||
|
#include "CClipboard.h"
|
||||||
#include "ProtocolTypes.h"
|
#include "ProtocolTypes.h"
|
||||||
|
|
||||||
class CEvent;
|
class CEvent;
|
||||||
|
@ -24,14 +25,16 @@ class CEventQueueTimer;
|
||||||
//! Proxy for client implementing protocol version 1.0
|
//! Proxy for client implementing protocol version 1.0
|
||||||
class CClientProxy1_0 : public CClientProxy {
|
class CClientProxy1_0 : public CClientProxy {
|
||||||
public:
|
public:
|
||||||
CClientProxy1_0(IServer* server, const CString& name,
|
CClientProxy1_0(const CString& name, IStream* adoptedStream);
|
||||||
IStream* adoptedStream);
|
|
||||||
~CClientProxy1_0();
|
~CClientProxy1_0();
|
||||||
|
|
||||||
|
// IScreen
|
||||||
|
virtual bool getClipboard(ClipboardID id, IClipboard*) const;
|
||||||
|
virtual void getShape(SInt32& x, SInt32& y,
|
||||||
|
SInt32& width, SInt32& height) const;
|
||||||
|
virtual void getCursorPos(SInt32& x, SInt32& y) const;
|
||||||
|
|
||||||
// IClient overrides
|
// IClient overrides
|
||||||
virtual void open();
|
|
||||||
virtual void mainLoop();
|
|
||||||
virtual void close();
|
|
||||||
virtual void enter(SInt32 xAbs, SInt32 yAbs,
|
virtual void enter(SInt32 xAbs, SInt32 yAbs,
|
||||||
UInt32 seqNum, KeyModifierMask mask,
|
UInt32 seqNum, KeyModifierMask mask,
|
||||||
bool forScreensaver);
|
bool forScreensaver);
|
||||||
|
@ -50,13 +53,9 @@ public:
|
||||||
virtual void screensaver(bool activate);
|
virtual void screensaver(bool activate);
|
||||||
virtual void resetOptions();
|
virtual void resetOptions();
|
||||||
virtual void setOptions(const COptionsList& options);
|
virtual void setOptions(const COptionsList& options);
|
||||||
virtual SInt32 getJumpZoneSize() const;
|
|
||||||
virtual void getShape(SInt32& x, SInt32& y,
|
|
||||||
SInt32& width, SInt32& height) const;
|
|
||||||
virtual void getCursorPos(SInt32& x, SInt32& y) const;
|
|
||||||
virtual void getCursorCenter(SInt32& x, SInt32& y) const;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
virtual bool parseHandshakeMessage(const UInt8* code);
|
||||||
virtual bool parseMessage(const UInt8* code);
|
virtual bool parseMessage(const UInt8* code);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -70,15 +69,27 @@ private:
|
||||||
void handleWriteError(const CEvent&, void*);
|
void handleWriteError(const CEvent&, void*);
|
||||||
void handleFlatline(const CEvent&, void*);
|
void handleFlatline(const CEvent&, void*);
|
||||||
|
|
||||||
bool recvInfo(bool notify);
|
bool recvInfo();
|
||||||
bool recvClipboard();
|
bool recvClipboard();
|
||||||
bool recvGrabClipboard();
|
bool recvGrabClipboard();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
typedef bool (CClientProxy1_0::*MessageParser)(const UInt8*);
|
||||||
|
struct CClientClipboard {
|
||||||
|
public:
|
||||||
|
CClientClipboard();
|
||||||
|
|
||||||
|
public:
|
||||||
|
CClipboard m_clipboard;
|
||||||
|
UInt32 m_sequenceNumber;
|
||||||
|
bool m_dirty;
|
||||||
|
};
|
||||||
|
|
||||||
CClientInfo m_info;
|
CClientInfo m_info;
|
||||||
bool m_clipboardDirty[kClipboardEnd];
|
CClientClipboard m_clipboard[kClipboardEnd];
|
||||||
double m_heartbeatAlarm;
|
double m_heartbeatAlarm;
|
||||||
CEventQueueTimer* m_heartbeatTimer;
|
CEventQueueTimer* m_heartbeatTimer;
|
||||||
|
MessageParser m_parser;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -21,9 +21,8 @@
|
||||||
// CClientProxy1_1
|
// CClientProxy1_1
|
||||||
//
|
//
|
||||||
|
|
||||||
CClientProxy1_1::CClientProxy1_1(IServer* server,
|
CClientProxy1_1::CClientProxy1_1(const CString& name, IStream* stream) :
|
||||||
const CString& name, IStream* stream) :
|
CClientProxy1_0(name, stream)
|
||||||
CClientProxy1_0(server, name, stream)
|
|
||||||
{
|
{
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,8 +20,7 @@
|
||||||
//! Proxy for client implementing protocol version 1.1
|
//! Proxy for client implementing protocol version 1.1
|
||||||
class CClientProxy1_1 : public CClientProxy1_0 {
|
class CClientProxy1_1 : public CClientProxy1_0 {
|
||||||
public:
|
public:
|
||||||
CClientProxy1_1(IServer* server, const CString& name,
|
CClientProxy1_1(const CString& name, IStream* adoptedStream);
|
||||||
IStream* adoptedStream);
|
|
||||||
~CClientProxy1_1();
|
~CClientProxy1_1();
|
||||||
|
|
||||||
// IClient overrides
|
// IClient overrides
|
||||||
|
|
|
@ -0,0 +1,277 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2004 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* This package is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* found in the file COPYING that should have accompanied this file.
|
||||||
|
*
|
||||||
|
* This package is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "CClientProxyUnknown.h"
|
||||||
|
#include "CClientProxy1_0.h"
|
||||||
|
#include "CClientProxy1_1.h"
|
||||||
|
#include "ProtocolTypes.h"
|
||||||
|
#include "CProtocolUtil.h"
|
||||||
|
#include "XSynergy.h"
|
||||||
|
#include "IStream.h"
|
||||||
|
#include "XIO.h"
|
||||||
|
#include "CLog.h"
|
||||||
|
#include "CString.h"
|
||||||
|
#include "IEventQueue.h"
|
||||||
|
#include "TMethodEventJob.h"
|
||||||
|
|
||||||
|
//
|
||||||
|
// CClientProxyUnknown
|
||||||
|
//
|
||||||
|
|
||||||
|
CEvent::Type CClientProxyUnknown::s_successEvent = CEvent::kUnknown;
|
||||||
|
CEvent::Type CClientProxyUnknown::s_failureEvent = CEvent::kUnknown;
|
||||||
|
|
||||||
|
CClientProxyUnknown::CClientProxyUnknown(IStream* stream, double timeout) :
|
||||||
|
m_stream(stream),
|
||||||
|
m_proxy(NULL),
|
||||||
|
m_ready(false)
|
||||||
|
{
|
||||||
|
EVENTQUEUE->adoptHandler(CEvent::kTimer, this,
|
||||||
|
new TMethodEventJob<CClientProxyUnknown>(this,
|
||||||
|
&CClientProxyUnknown::handleTimeout, NULL));
|
||||||
|
m_timer = EVENTQUEUE->newOneShotTimer(timeout, this);
|
||||||
|
addStreamHandlers();
|
||||||
|
|
||||||
|
LOG((CLOG_DEBUG1 "saying hello"));
|
||||||
|
CProtocolUtil::writef(m_stream, kMsgHello,
|
||||||
|
kProtocolMajorVersion,
|
||||||
|
kProtocolMinorVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
CClientProxyUnknown::~CClientProxyUnknown()
|
||||||
|
{
|
||||||
|
removeHandlers();
|
||||||
|
removeTimer();
|
||||||
|
delete m_stream;
|
||||||
|
delete m_proxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
CClientProxy*
|
||||||
|
CClientProxyUnknown::orphanClientProxy()
|
||||||
|
{
|
||||||
|
if (m_ready) {
|
||||||
|
removeHandlers();
|
||||||
|
CClientProxy* proxy = m_proxy;
|
||||||
|
m_proxy = NULL;
|
||||||
|
return proxy;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CEvent::Type
|
||||||
|
CClientProxyUnknown::getSuccessEvent()
|
||||||
|
{
|
||||||
|
return CEvent::registerTypeOnce(s_successEvent,
|
||||||
|
"CClientProxy::success");
|
||||||
|
}
|
||||||
|
|
||||||
|
CEvent::Type
|
||||||
|
CClientProxyUnknown::getFailureEvent()
|
||||||
|
{
|
||||||
|
return CEvent::registerTypeOnce(s_failureEvent,
|
||||||
|
"CClientProxy::failure");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CClientProxyUnknown::sendSuccess()
|
||||||
|
{
|
||||||
|
m_ready = true;
|
||||||
|
removeTimer();
|
||||||
|
EVENTQUEUE->addEvent(CEvent(getSuccessEvent(), this));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CClientProxyUnknown::sendFailure()
|
||||||
|
{
|
||||||
|
delete m_proxy;
|
||||||
|
m_proxy = NULL;
|
||||||
|
m_ready = false;
|
||||||
|
removeHandlers();
|
||||||
|
removeTimer();
|
||||||
|
EVENTQUEUE->addEvent(CEvent(getFailureEvent(), this));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CClientProxyUnknown::addStreamHandlers()
|
||||||
|
{
|
||||||
|
assert(m_stream != NULL);
|
||||||
|
|
||||||
|
EVENTQUEUE->adoptHandler(IStream::getInputReadyEvent(),
|
||||||
|
m_stream->getEventTarget(),
|
||||||
|
new TMethodEventJob<CClientProxyUnknown>(this,
|
||||||
|
&CClientProxyUnknown::handleData));
|
||||||
|
EVENTQUEUE->adoptHandler(IStream::getOutputErrorEvent(),
|
||||||
|
m_stream->getEventTarget(),
|
||||||
|
new TMethodEventJob<CClientProxyUnknown>(this,
|
||||||
|
&CClientProxyUnknown::handleWriteError));
|
||||||
|
EVENTQUEUE->adoptHandler(IStream::getInputShutdownEvent(),
|
||||||
|
m_stream->getEventTarget(),
|
||||||
|
new TMethodEventJob<CClientProxyUnknown>(this,
|
||||||
|
&CClientProxyUnknown::handleDisconnect));
|
||||||
|
EVENTQUEUE->adoptHandler(IStream::getOutputShutdownEvent(),
|
||||||
|
m_stream->getEventTarget(),
|
||||||
|
new TMethodEventJob<CClientProxyUnknown>(this,
|
||||||
|
&CClientProxyUnknown::handleWriteError));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CClientProxyUnknown::addProxyHandlers()
|
||||||
|
{
|
||||||
|
assert(m_proxy != NULL);
|
||||||
|
|
||||||
|
EVENTQUEUE->adoptHandler(CClientProxy::getReadyEvent(),
|
||||||
|
m_proxy,
|
||||||
|
new TMethodEventJob<CClientProxyUnknown>(this,
|
||||||
|
&CClientProxyUnknown::handleReady));
|
||||||
|
EVENTQUEUE->adoptHandler(CClientProxy::getDisconnectedEvent(),
|
||||||
|
m_proxy,
|
||||||
|
new TMethodEventJob<CClientProxyUnknown>(this,
|
||||||
|
&CClientProxyUnknown::handleDisconnect));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CClientProxyUnknown::removeHandlers()
|
||||||
|
{
|
||||||
|
if (m_stream != NULL) {
|
||||||
|
EVENTQUEUE->removeHandler(IStream::getInputReadyEvent(),
|
||||||
|
m_stream->getEventTarget());
|
||||||
|
EVENTQUEUE->removeHandler(IStream::getOutputErrorEvent(),
|
||||||
|
m_stream->getEventTarget());
|
||||||
|
EVENTQUEUE->removeHandler(IStream::getInputShutdownEvent(),
|
||||||
|
m_stream->getEventTarget());
|
||||||
|
EVENTQUEUE->removeHandler(IStream::getOutputShutdownEvent(),
|
||||||
|
m_stream->getEventTarget());
|
||||||
|
}
|
||||||
|
if (m_proxy != NULL) {
|
||||||
|
EVENTQUEUE->removeHandler(CClientProxy::getReadyEvent(),
|
||||||
|
m_proxy);
|
||||||
|
EVENTQUEUE->removeHandler(CClientProxy::getDisconnectedEvent(),
|
||||||
|
m_proxy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CClientProxyUnknown::removeTimer()
|
||||||
|
{
|
||||||
|
if (m_timer != NULL) {
|
||||||
|
EVENTQUEUE->deleteTimer(m_timer);
|
||||||
|
EVENTQUEUE->removeHandler(CEvent::kTimer, this);
|
||||||
|
m_timer = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CClientProxyUnknown::handleData(const CEvent&, void*)
|
||||||
|
{
|
||||||
|
LOG((CLOG_DEBUG1 "parsing hello reply"));
|
||||||
|
|
||||||
|
CString name("<unknown>");
|
||||||
|
try {
|
||||||
|
// limit the maximum length of the hello
|
||||||
|
UInt32 n = m_stream->getSize();
|
||||||
|
if (n > kMaxHelloLength) {
|
||||||
|
LOG((CLOG_DEBUG1 "hello reply too long"));
|
||||||
|
throw XBadClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse the reply to hello
|
||||||
|
SInt16 major, minor;
|
||||||
|
if (!CProtocolUtil::readf(m_stream, kMsgHelloBack,
|
||||||
|
&major, &minor, &name)) {
|
||||||
|
throw XBadClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
// disallow invalid version numbers
|
||||||
|
if (major <= 0 || minor < 0) {
|
||||||
|
throw XIncompatibleClient(major, minor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove stream event handlers. the proxy we're about to create
|
||||||
|
// may install its own handlers and we don't want to accidentally
|
||||||
|
// remove those later.
|
||||||
|
removeHandlers();
|
||||||
|
|
||||||
|
// create client proxy for highest version supported by the client
|
||||||
|
if (major == 1) {
|
||||||
|
switch (minor) {
|
||||||
|
case 0:
|
||||||
|
m_proxy = new CClientProxy1_0(name, m_stream);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
m_proxy = new CClientProxy1_1(name, m_stream);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// hangup (with error) if version isn't supported
|
||||||
|
if (m_proxy == NULL) {
|
||||||
|
throw XIncompatibleClient(major, minor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// the proxy is created and now proxy now owns the stream
|
||||||
|
LOG((CLOG_DEBUG1 "created proxy for client \"%s\" version %d.%d", name.c_str(), major, minor));
|
||||||
|
m_stream = NULL;
|
||||||
|
|
||||||
|
// wait until the proxy signals that it's ready or has disconnected
|
||||||
|
addProxyHandlers();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
catch (XIncompatibleClient& e) {
|
||||||
|
// client is incompatible
|
||||||
|
LOG((CLOG_WARN "client \"%s\" has incompatible version %d.%d)", name.c_str(), e.getMajor(), e.getMinor()));
|
||||||
|
CProtocolUtil::writef(m_stream,
|
||||||
|
kMsgEIncompatible,
|
||||||
|
kProtocolMajorVersion, kProtocolMinorVersion);
|
||||||
|
}
|
||||||
|
catch (XBadClient&) {
|
||||||
|
// client not behaving
|
||||||
|
LOG((CLOG_WARN "protocol error from client \"%s\"", name.c_str()));
|
||||||
|
CProtocolUtil::writef(m_stream, kMsgEBad);
|
||||||
|
}
|
||||||
|
catch (XBase& e) {
|
||||||
|
// misc error
|
||||||
|
LOG((CLOG_WARN "error communicating with client \"%s\": %s", name.c_str(), e.what()));
|
||||||
|
}
|
||||||
|
sendFailure();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CClientProxyUnknown::handleWriteError(const CEvent&, void*)
|
||||||
|
{
|
||||||
|
LOG((CLOG_NOTE "error communicating with new client"));
|
||||||
|
sendFailure();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CClientProxyUnknown::handleTimeout(const CEvent&, void*)
|
||||||
|
{
|
||||||
|
LOG((CLOG_NOTE "new client is unresponsive"));
|
||||||
|
sendFailure();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CClientProxyUnknown::handleDisconnect(const CEvent&, void*)
|
||||||
|
{
|
||||||
|
LOG((CLOG_NOTE "new client disconnected"));
|
||||||
|
sendFailure();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CClientProxyUnknown::handleReady(const CEvent&, void*)
|
||||||
|
{
|
||||||
|
sendSuccess();
|
||||||
|
}
|
|
@ -0,0 +1,83 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2004 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* This package is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* found in the file COPYING that should have accompanied this file.
|
||||||
|
*
|
||||||
|
* This package is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CCLIENTPROXYUNKNOWN_H
|
||||||
|
#define CCLIENTPROXYUNKNOWN_H
|
||||||
|
|
||||||
|
#include "CEvent.h"
|
||||||
|
|
||||||
|
class CClientProxy;
|
||||||
|
class CEventQueueTimer;
|
||||||
|
class IStream;
|
||||||
|
|
||||||
|
class CClientProxyUnknown {
|
||||||
|
public:
|
||||||
|
CClientProxyUnknown(IStream* stream, double timeout);
|
||||||
|
~CClientProxyUnknown();
|
||||||
|
|
||||||
|
//! @name manipulators
|
||||||
|
//@{
|
||||||
|
|
||||||
|
//! Get the client proxy
|
||||||
|
/*!
|
||||||
|
Returns the client proxy created after a successful handshake
|
||||||
|
(i.e. when this object sends a success event). Returns NULL
|
||||||
|
if the handshake is unsuccessful or incomplete.
|
||||||
|
*/
|
||||||
|
CClientProxy* orphanClientProxy();
|
||||||
|
|
||||||
|
//@}
|
||||||
|
//! @name accessors
|
||||||
|
//@{
|
||||||
|
|
||||||
|
//! Get success event type
|
||||||
|
/*!
|
||||||
|
Returns the success event type. This is sent when the client has
|
||||||
|
correctly responded to the hello message. The target is this.
|
||||||
|
*/
|
||||||
|
static CEvent::Type getSuccessEvent();
|
||||||
|
|
||||||
|
//! Get failure event type
|
||||||
|
/*!
|
||||||
|
Returns the failure event type. This is sent when a client fails
|
||||||
|
to correctly respond to the hello message. The target is this.
|
||||||
|
*/
|
||||||
|
static CEvent::Type getFailureEvent();
|
||||||
|
|
||||||
|
//@}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void sendSuccess();
|
||||||
|
void sendFailure();
|
||||||
|
void addStreamHandlers();
|
||||||
|
void addProxyHandlers();
|
||||||
|
void removeHandlers();
|
||||||
|
void removeTimer();
|
||||||
|
void handleData(const CEvent&, void*);
|
||||||
|
void handleWriteError(const CEvent&, void*);
|
||||||
|
void handleTimeout(const CEvent&, void*);
|
||||||
|
void handleDisconnect(const CEvent&, void*);
|
||||||
|
void handleReady(const CEvent&, void*);
|
||||||
|
|
||||||
|
private:
|
||||||
|
IStream* m_stream;
|
||||||
|
CEventQueueTimer* m_timer;
|
||||||
|
CClientProxy* m_proxy;
|
||||||
|
bool m_ready;
|
||||||
|
|
||||||
|
static CEvent::Type s_successEvent;
|
||||||
|
static CEvent::Type s_failureEvent;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -446,11 +446,9 @@ CConfig::getOptions(const CString& name) const
|
||||||
bool
|
bool
|
||||||
CConfig::operator==(const CConfig& x) const
|
CConfig::operator==(const CConfig& x) const
|
||||||
{
|
{
|
||||||
/* FIXME -- no compare available for CNetworkAddress
|
|
||||||
if (m_synergyAddress != x.m_synergyAddress) {
|
if (m_synergyAddress != x.m_synergyAddress) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
if (m_map.size() != x.m_map.size()) {
|
if (m_map.size() != x.m_map.size()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,10 +14,6 @@
|
||||||
|
|
||||||
#include "CPrimaryClient.h"
|
#include "CPrimaryClient.h"
|
||||||
#include "CScreen.h"
|
#include "CScreen.h"
|
||||||
#include "IScreenFactory.h"
|
|
||||||
#include "IServer.h"
|
|
||||||
#include "XScreen.h"
|
|
||||||
#include "XSynergy.h"
|
|
||||||
#include "CClipboard.h"
|
#include "CClipboard.h"
|
||||||
#include "CLog.h"
|
#include "CLog.h"
|
||||||
|
|
||||||
|
@ -25,66 +21,31 @@
|
||||||
// CPrimaryClient
|
// CPrimaryClient
|
||||||
//
|
//
|
||||||
|
|
||||||
CPrimaryClient::CPrimaryClient(IScreenFactory* screenFactory,
|
CPrimaryClient::CPrimaryClient(const CString& name, CScreen* screen) :
|
||||||
IServer* server,
|
|
||||||
IPrimaryScreenReceiver* receiver,
|
|
||||||
const CString& name) :
|
|
||||||
m_server(server),
|
|
||||||
m_name(name),
|
m_name(name),
|
||||||
m_seqNum(0)
|
m_screen(screen)
|
||||||
{
|
{
|
||||||
assert(m_server != NULL);
|
// all clipboards are clean
|
||||||
|
for (UInt32 i = 0; i < kClipboardEnd; ++i) {
|
||||||
// create screen
|
m_clipboardDirty[i] = false;
|
||||||
LOG((CLOG_DEBUG1 "creating primary screen"));
|
|
||||||
if (screenFactory != NULL) {
|
|
||||||
IPlatformScreen* platformScreen =
|
|
||||||
screenFactory->create(this, receiver);
|
|
||||||
if (platformScreen != NULL) {
|
|
||||||
m_screen = new CScreen(platformScreen, this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (m_screen == NULL) {
|
|
||||||
throw XScreenOpenFailure();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CPrimaryClient::~CPrimaryClient()
|
CPrimaryClient::~CPrimaryClient()
|
||||||
{
|
{
|
||||||
LOG((CLOG_DEBUG1 "destroying primary screen"));
|
|
||||||
delete m_screen;
|
delete m_screen;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
CPrimaryClient::exitMainLoop()
|
|
||||||
{
|
|
||||||
m_screen->exitMainLoop();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
CPrimaryClient::reconfigure(UInt32 activeSides)
|
CPrimaryClient::reconfigure(UInt32 activeSides)
|
||||||
{
|
{
|
||||||
m_screen->reconfigure(activeSides);
|
m_screen->reconfigure(activeSides);
|
||||||
}
|
}
|
||||||
|
|
||||||
UInt32
|
|
||||||
CPrimaryClient::addOneShotTimer(double timeout)
|
|
||||||
{
|
|
||||||
return m_screen->addOneShotTimer(timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
CPrimaryClient::getClipboard(ClipboardID id, CString& data) const
|
CPrimaryClient::getCursorCenter(SInt32& x, SInt32& y) const
|
||||||
{
|
{
|
||||||
CClipboard clipboard;
|
m_screen->getCursorCenter(x, y);
|
||||||
m_screen->getClipboard(id, &clipboard);
|
|
||||||
data = clipboard.marshall();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
CPrimaryClient::isLockedToScreen() const
|
|
||||||
{
|
|
||||||
return m_screen->isLockedToScreen();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
KeyModifierMask
|
KeyModifierMask
|
||||||
|
@ -93,64 +54,41 @@ CPrimaryClient::getToggleMask() const
|
||||||
return m_screen->getActiveModifiers();
|
return m_screen->getActiveModifiers();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
bool
|
||||||
CPrimaryClient::onError()
|
CPrimaryClient::isLockedToScreen() const
|
||||||
{
|
{
|
||||||
// forward to server
|
return m_screen->isLockedToScreen();
|
||||||
m_server->onError();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void*
|
||||||
CPrimaryClient::onInfoChanged(const CClientInfo& info)
|
CPrimaryClient::getEventTarget() const
|
||||||
{
|
{
|
||||||
m_info = info;
|
return m_screen->getEventTarget();
|
||||||
try {
|
|
||||||
m_server->onInfoChanged(getName(), m_info);
|
|
||||||
}
|
|
||||||
catch (XBadClient&) {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CPrimaryClient::onGrabClipboard(ClipboardID id)
|
CPrimaryClient::getClipboard(ClipboardID id, IClipboard* clipboard) const
|
||||||
{
|
{
|
||||||
try {
|
return m_screen->getClipboard(id, clipboard);
|
||||||
return m_server->onGrabClipboard(getName(), id, m_seqNum);
|
|
||||||
}
|
|
||||||
catch (XBadClient&) {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SInt32
|
||||||
|
CPrimaryClient::getJumpZoneSize() const
|
||||||
|
{
|
||||||
|
return m_screen->getJumpZoneSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CPrimaryClient::onClipboardChanged(ClipboardID id, const CString& data)
|
CPrimaryClient::getShape(SInt32& x, SInt32& y,
|
||||||
|
SInt32& width, SInt32& height) const
|
||||||
{
|
{
|
||||||
m_server->onClipboardChanged(id, m_seqNum, data);
|
m_screen->getShape(x, y, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CPrimaryClient::open()
|
CPrimaryClient::getCursorPos(SInt32& x, SInt32& y) const
|
||||||
{
|
{
|
||||||
// all clipboards are clean
|
m_screen->getCursorPos(x, y);
|
||||||
for (UInt32 i = 0; i < kClipboardEnd; ++i) {
|
|
||||||
m_clipboardDirty[i] = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// now open the screen
|
|
||||||
m_screen->open();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CPrimaryClient::mainLoop()
|
|
||||||
{
|
|
||||||
m_screen->mainLoop();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CPrimaryClient::close()
|
|
||||||
{
|
|
||||||
m_screen->close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -169,8 +107,7 @@ void
|
||||||
CPrimaryClient::enter(SInt32 xAbs, SInt32 yAbs,
|
CPrimaryClient::enter(SInt32 xAbs, SInt32 yAbs,
|
||||||
UInt32 seqNum, KeyModifierMask, bool screensaver)
|
UInt32 seqNum, KeyModifierMask, bool screensaver)
|
||||||
{
|
{
|
||||||
// note -- we must not call any server methods except onError().
|
m_screen->setSequenceNumber(seqNum);
|
||||||
m_seqNum = seqNum;
|
|
||||||
if (!screensaver) {
|
if (!screensaver) {
|
||||||
m_screen->warpCursor(xAbs, yAbs);
|
m_screen->warpCursor(xAbs, yAbs);
|
||||||
}
|
}
|
||||||
|
@ -180,15 +117,12 @@ CPrimaryClient::enter(SInt32 xAbs, SInt32 yAbs,
|
||||||
bool
|
bool
|
||||||
CPrimaryClient::leave()
|
CPrimaryClient::leave()
|
||||||
{
|
{
|
||||||
// note -- we must not call any server methods except onError().
|
|
||||||
return m_screen->leave();
|
return m_screen->leave();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CPrimaryClient::setClipboard(ClipboardID id, const CString& data)
|
CPrimaryClient::setClipboard(ClipboardID id, const CString& data)
|
||||||
{
|
{
|
||||||
// note -- we must not call any server methods except onError().
|
|
||||||
|
|
||||||
// ignore if this clipboard is already clean
|
// ignore if this clipboard is already clean
|
||||||
if (m_clipboardDirty[id]) {
|
if (m_clipboardDirty[id]) {
|
||||||
// this clipboard is now clean
|
// this clipboard is now clean
|
||||||
|
@ -284,31 +218,3 @@ CPrimaryClient::getName() const
|
||||||
{
|
{
|
||||||
return m_name;
|
return m_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
SInt32
|
|
||||||
CPrimaryClient::getJumpZoneSize() const
|
|
||||||
{
|
|
||||||
return m_info.m_zoneSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CPrimaryClient::getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) const
|
|
||||||
{
|
|
||||||
x = m_info.m_x;
|
|
||||||
y = m_info.m_y;
|
|
||||||
w = m_info.m_w;
|
|
||||||
h = m_info.m_h;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CPrimaryClient::getCursorPos(SInt32&, SInt32&) const
|
|
||||||
{
|
|
||||||
assert(0 && "shouldn't be called");
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CPrimaryClient::getCursorCenter(SInt32& x, SInt32& y) const
|
|
||||||
{
|
|
||||||
x = m_info.m_mx;
|
|
||||||
y = m_info.m_my;
|
|
||||||
}
|
|
||||||
|
|
|
@ -16,14 +16,9 @@
|
||||||
#define CPRIMARYCLIENT_H
|
#define CPRIMARYCLIENT_H
|
||||||
|
|
||||||
#include "IClient.h"
|
#include "IClient.h"
|
||||||
#include "IScreenReceiver.h"
|
|
||||||
#include "ProtocolTypes.h"
|
#include "ProtocolTypes.h"
|
||||||
|
|
||||||
class CScreen;
|
class CScreen;
|
||||||
class IClipboard;
|
|
||||||
class IScreenFactory;
|
|
||||||
class IPrimaryScreenReceiver;
|
|
||||||
class IServer;
|
|
||||||
|
|
||||||
//! Primary screen as pseudo-client
|
//! Primary screen as pseudo-client
|
||||||
/*!
|
/*!
|
||||||
|
@ -31,50 +26,34 @@ The primary screen does not have a client associated with it. This
|
||||||
class provides a pseudo-client to allow the primary screen to be
|
class provides a pseudo-client to allow the primary screen to be
|
||||||
treated as if it was on a client.
|
treated as if it was on a client.
|
||||||
*/
|
*/
|
||||||
class CPrimaryClient : public IScreenReceiver, public IClient {
|
class CPrimaryClient : public IClient {
|
||||||
public:
|
public:
|
||||||
/*!
|
/*!
|
||||||
\c name is the name of the server. The caller retains ownership of
|
\c name is the name of the server. \p screen is adopted.
|
||||||
\c factory. Throws XScreenOpenFailure or whatever the factory can
|
|
||||||
throw if the screen cannot be created.
|
|
||||||
*/
|
*/
|
||||||
CPrimaryClient(IScreenFactory* factory, IServer*,
|
CPrimaryClient(const CString& name, CScreen* screen);
|
||||||
IPrimaryScreenReceiver*, const CString& name);
|
|
||||||
~CPrimaryClient();
|
~CPrimaryClient();
|
||||||
|
|
||||||
//! @name manipulators
|
//! @name manipulators
|
||||||
//@{
|
//@{
|
||||||
|
|
||||||
//! Exit event loop
|
|
||||||
/*!
|
|
||||||
Force mainLoop() to return. This call can return before
|
|
||||||
mainLoop() does (i.e. asynchronously). This may only be
|
|
||||||
called between a successful open() and close().
|
|
||||||
*/
|
|
||||||
void exitMainLoop();
|
|
||||||
|
|
||||||
//! Update configuration
|
//! Update configuration
|
||||||
/*!
|
/*!
|
||||||
Handles reconfiguration of jump zones.
|
Handles reconfiguration of jump zones.
|
||||||
*/
|
*/
|
||||||
void reconfigure(UInt32 activeSides);
|
void reconfigure(UInt32 activeSides);
|
||||||
|
|
||||||
//! Install a one-shot timer
|
|
||||||
/*!
|
|
||||||
Installs a one-shot timer for \c timeout seconds and returns the
|
|
||||||
id of the timer (which will be passed to \c onTimerExpired()).
|
|
||||||
*/
|
|
||||||
UInt32 addOneShotTimer(double timeout);
|
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
//! @name accessors
|
//! @name accessors
|
||||||
//@{
|
//@{
|
||||||
|
|
||||||
//! Get clipboard
|
//! Get cursor center position
|
||||||
/*!
|
/*!
|
||||||
Save the marshalled contents of the clipboard indicated by \c id.
|
Return the cursor center position which is where we park the
|
||||||
|
cursor to compute cursor motion deltas and should be far from
|
||||||
|
the edges of the screen, typically the center.
|
||||||
*/
|
*/
|
||||||
void getClipboard(ClipboardID, CString&) const;
|
void getCursorCenter(SInt32& x, SInt32& y) const;
|
||||||
|
|
||||||
//! Get toggle key state
|
//! Get toggle key state
|
||||||
/*!
|
/*!
|
||||||
|
@ -90,19 +69,19 @@ public:
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
// IScreenReceiver overrides
|
// FIXME -- these probably belong on IScreen
|
||||||
virtual void onError();
|
|
||||||
virtual void onInfoChanged(const CClientInfo&);
|
|
||||||
virtual bool onGrabClipboard(ClipboardID);
|
|
||||||
virtual void onClipboardChanged(ClipboardID, const CString&);
|
|
||||||
|
|
||||||
// XXX -- these go in IClient
|
|
||||||
virtual void enable();
|
virtual void enable();
|
||||||
virtual void disable();
|
virtual void disable();
|
||||||
|
|
||||||
|
// IScreen overrides
|
||||||
|
virtual void* getEventTarget() const;
|
||||||
|
virtual bool getClipboard(ClipboardID id, IClipboard*) const;
|
||||||
|
virtual SInt32 getJumpZoneSize() const;
|
||||||
|
virtual void getShape(SInt32& x, SInt32& y,
|
||||||
|
SInt32& width, SInt32& height) const;
|
||||||
|
virtual void getCursorPos(SInt32& x, SInt32& y) const;
|
||||||
|
|
||||||
// IClient overrides
|
// IClient overrides
|
||||||
virtual void open();
|
|
||||||
virtual void mainLoop();
|
|
||||||
virtual void close();
|
|
||||||
virtual void enter(SInt32 xAbs, SInt32 yAbs,
|
virtual void enter(SInt32 xAbs, SInt32 yAbs,
|
||||||
UInt32 seqNum, KeyModifierMask mask,
|
UInt32 seqNum, KeyModifierMask mask,
|
||||||
bool forScreensaver);
|
bool forScreensaver);
|
||||||
|
@ -122,18 +101,10 @@ public:
|
||||||
virtual void resetOptions();
|
virtual void resetOptions();
|
||||||
virtual void setOptions(const COptionsList& options);
|
virtual void setOptions(const COptionsList& options);
|
||||||
virtual CString getName() const;
|
virtual CString getName() const;
|
||||||
virtual SInt32 getJumpZoneSize() const;
|
|
||||||
virtual void getShape(SInt32& x, SInt32& y,
|
|
||||||
SInt32& width, SInt32& height) const;
|
|
||||||
virtual void getCursorPos(SInt32& x, SInt32& y) const;
|
|
||||||
virtual void getCursorCenter(SInt32& x, SInt32& y) const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
IServer* m_server;
|
|
||||||
CScreen* m_screen;
|
|
||||||
CString m_name;
|
CString m_name;
|
||||||
UInt32 m_seqNum;
|
CScreen* m_screen;
|
||||||
CClientInfo m_info;
|
|
||||||
bool m_clipboardDirty[kClipboardEnd];
|
bool m_clipboardDirty[kClipboardEnd];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -15,84 +15,40 @@
|
||||||
#ifndef CSERVER_H
|
#ifndef CSERVER_H
|
||||||
#define CSERVER_H
|
#define CSERVER_H
|
||||||
|
|
||||||
#include "IServer.h"
|
|
||||||
#include "IPrimaryScreenReceiver.h"
|
|
||||||
#include "CConfig.h"
|
#include "CConfig.h"
|
||||||
#include "CClipboard.h"
|
#include "CClipboard.h"
|
||||||
#include "CCondVar.h"
|
#include "ClipboardTypes.h"
|
||||||
#include "CMutex.h"
|
#include "KeyTypes.h"
|
||||||
#include "CThread.h"
|
#include "MouseTypes.h"
|
||||||
#include "CJobList.h"
|
#include "CEvent.h"
|
||||||
#include "CStopwatch.h"
|
#include "CStopwatch.h"
|
||||||
#include "stdlist.h"
|
|
||||||
#include "stdmap.h"
|
#include "stdmap.h"
|
||||||
|
#include "stdset.h"
|
||||||
#include "stdvector.h"
|
#include "stdvector.h"
|
||||||
|
|
||||||
class CClientProxy;
|
class CClientProxy;
|
||||||
|
class CClientProxyUnknown;
|
||||||
|
class CEventQueueTimer;
|
||||||
class CPrimaryClient;
|
class CPrimaryClient;
|
||||||
class IClient;
|
class IClient;
|
||||||
class IDataSocket;
|
|
||||||
class IScreenFactory;
|
|
||||||
class IServerProtocol;
|
|
||||||
class ISocketFactory;
|
|
||||||
class IStreamFilterFactory;
|
|
||||||
|
|
||||||
//! Synergy server
|
//! Synergy server
|
||||||
/*!
|
/*!
|
||||||
This class implements the top-level server algorithms for synergy.
|
This class implements the top-level server algorithms for synergy.
|
||||||
*/
|
*/
|
||||||
class CServer : public IServer, public IPrimaryScreenReceiver {
|
class CServer {
|
||||||
public:
|
public:
|
||||||
enum EStatus {
|
|
||||||
kNotRunning,
|
|
||||||
kRunning,
|
|
||||||
kServerNameUnknown,
|
|
||||||
kError,
|
|
||||||
kMaxStatus
|
|
||||||
};
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
The server will look itself up in the configuration using \c serverName
|
Start the server with the configuration \p config and the primary
|
||||||
as its name.
|
client (local screen) \p primaryClient. The client retains
|
||||||
|
ownership of \p primaryClient.
|
||||||
*/
|
*/
|
||||||
CServer(const CString& serverName);
|
CServer(const CConfig& config, CPrimaryClient* primaryClient);
|
||||||
~CServer();
|
~CServer();
|
||||||
|
|
||||||
//! @name manipulators
|
//! @name manipulators
|
||||||
//@{
|
//@{
|
||||||
|
|
||||||
//! Open server
|
|
||||||
/*!
|
|
||||||
Open the server. Throws XScreenUnavailable if the server's
|
|
||||||
screen cannot be opened but might be available after some time.
|
|
||||||
Otherwise throws some other exception if the server's screen or
|
|
||||||
the server cannot be opened and retrying won't help.
|
|
||||||
*/
|
|
||||||
void open();
|
|
||||||
|
|
||||||
//! Server main loop
|
|
||||||
/*!
|
|
||||||
Run server's event loop and return when exitMainLoop() is called.
|
|
||||||
This must be called between a successful open() and close().
|
|
||||||
|
|
||||||
(cancellation point)
|
|
||||||
*/
|
|
||||||
void mainLoop();
|
|
||||||
|
|
||||||
//! Exit event loop
|
|
||||||
/*!
|
|
||||||
Force mainLoop() to return. This call can return before
|
|
||||||
mainLoop() does (i.e. asynchronously). This may only be
|
|
||||||
called between a successful open() and close().
|
|
||||||
*/
|
|
||||||
void exitMainLoop();
|
|
||||||
|
|
||||||
//! Close server
|
|
||||||
/*!
|
|
||||||
Close the server.
|
|
||||||
*/
|
|
||||||
void close();
|
|
||||||
|
|
||||||
//! Set configuration
|
//! Set configuration
|
||||||
/*!
|
/*!
|
||||||
Change the server's configuration. Returns true iff the new
|
Change the server's configuration. Returns true iff the new
|
||||||
|
@ -101,67 +57,26 @@ public:
|
||||||
*/
|
*/
|
||||||
bool setConfig(const CConfig&);
|
bool setConfig(const CConfig&);
|
||||||
|
|
||||||
//! Set screen factory
|
//! Add a client
|
||||||
/*!
|
/*!
|
||||||
Sets the factory for creating screens. This must be set before
|
Adds \p client to the server. The client is adopted and will be
|
||||||
calling open(). This object takes ownership of the factory.
|
destroyed when the client disconnects or is disconnected.
|
||||||
*/
|
*/
|
||||||
void setScreenFactory(IScreenFactory*);
|
void adoptClient(IClient* client);
|
||||||
|
|
||||||
//! Set socket factory
|
//! Disconnect clients
|
||||||
/*!
|
/*!
|
||||||
Sets the factory used to create a socket to connect to the server.
|
Disconnect clients. This tells them to disconnect but does not wait
|
||||||
This must be set before calling mainLoop(). This object takes
|
for them to actually do so. The server sends the disconnected event
|
||||||
ownership of the factory.
|
when they're all disconnected (or immediately if none are connected).
|
||||||
|
The caller can also just destroy this object to force the disconnection.
|
||||||
*/
|
*/
|
||||||
void setSocketFactory(ISocketFactory*);
|
void disconnect();
|
||||||
|
|
||||||
//! Set stream filter factory
|
|
||||||
/*!
|
|
||||||
Sets the factory used to filter the socket streams used to
|
|
||||||
communicate with the server. This object takes ownership
|
|
||||||
of the factory.
|
|
||||||
*/
|
|
||||||
void setStreamFilterFactory(IStreamFilterFactory*);
|
|
||||||
|
|
||||||
//! Add a job to notify of status changes
|
|
||||||
/*!
|
|
||||||
The added job is run whenever the server's status changes in
|
|
||||||
certain externally visible ways. The client keeps ownership
|
|
||||||
of the job.
|
|
||||||
*/
|
|
||||||
void addStatusJob(IJob*);
|
|
||||||
|
|
||||||
//! Remove a job to notify of status changes
|
|
||||||
/*!
|
|
||||||
Removes a previously added status notification job. A job can
|
|
||||||
remove itself when called but must not remove any other jobs.
|
|
||||||
The client keeps ownership of the job.
|
|
||||||
*/
|
|
||||||
void removeStatusJob(IJob*);
|
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
//! @name accessors
|
//! @name accessors
|
||||||
//@{
|
//@{
|
||||||
|
|
||||||
//! Get configuration
|
|
||||||
/*!
|
|
||||||
Returns the current configuration.
|
|
||||||
*/
|
|
||||||
void getConfig(CConfig*) const;
|
|
||||||
|
|
||||||
//! Get canonical screen name
|
|
||||||
/*!
|
|
||||||
Returns the canonical version of a screen name.
|
|
||||||
*/
|
|
||||||
CString getCanonicalName(const CString& name) const;
|
|
||||||
|
|
||||||
//! Get name
|
|
||||||
/*!
|
|
||||||
Returns the server's name passed to the c'tor
|
|
||||||
*/
|
|
||||||
CString getPrimaryScreenName() const;
|
|
||||||
|
|
||||||
//! Get number of connected clients
|
//! Get number of connected clients
|
||||||
/*!
|
/*!
|
||||||
Returns the number of connected clients, including the server itself.
|
Returns the number of connected clients, including the server itself.
|
||||||
|
@ -174,33 +89,22 @@ public:
|
||||||
*/
|
*/
|
||||||
void getClients(std::vector<CString>& list) const;
|
void getClients(std::vector<CString>& list) const;
|
||||||
|
|
||||||
//! Get the status
|
//! Get error event type
|
||||||
/*!
|
/*!
|
||||||
Returns the current status and status message.
|
Returns the error event type. This is sent when the server fails
|
||||||
|
for some reason.
|
||||||
*/
|
*/
|
||||||
EStatus getStatus(CString* = NULL) const;
|
static CEvent::Type getErrorEvent();
|
||||||
|
|
||||||
|
//! Get disconnected event type
|
||||||
|
/*!
|
||||||
|
Returns the disconnected event type. This is sent when all the
|
||||||
|
clients have disconnected.
|
||||||
|
*/
|
||||||
|
static CEvent::Type getDisconnectedEvent();
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
// IServer overrides
|
|
||||||
virtual void onError();
|
|
||||||
virtual void onInfoChanged(const CString&, const CClientInfo&);
|
|
||||||
virtual bool onGrabClipboard(const CString&, ClipboardID, UInt32);
|
|
||||||
virtual void onClipboardChanged(ClipboardID, UInt32, const CString&);
|
|
||||||
|
|
||||||
// IPrimaryScreenReceiver overrides
|
|
||||||
virtual void onScreensaver(bool activated);
|
|
||||||
virtual void onOneShotTimerExpired(UInt32 id);
|
|
||||||
virtual void onKeyDown(KeyID, KeyModifierMask, KeyButton);
|
|
||||||
virtual void onKeyUp(KeyID, KeyModifierMask, KeyButton);
|
|
||||||
virtual void onKeyRepeat(KeyID, KeyModifierMask,
|
|
||||||
SInt32 count, KeyButton);
|
|
||||||
virtual void onMouseDown(ButtonID);
|
|
||||||
virtual void onMouseUp(ButtonID);
|
|
||||||
virtual bool onMouseMovePrimary(SInt32 x, SInt32 y);
|
|
||||||
virtual void onMouseMoveSecondary(SInt32 dx, SInt32 dy);
|
|
||||||
virtual void onMouseWheel(SInt32 delta);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
//! Handle special keys
|
//! Handle special keys
|
||||||
/*!
|
/*!
|
||||||
|
@ -208,36 +112,18 @@ protected:
|
||||||
*/
|
*/
|
||||||
bool onCommandKey(KeyID, KeyModifierMask, bool down);
|
bool onCommandKey(KeyID, KeyModifierMask, bool down);
|
||||||
|
|
||||||
//! Exit event loop and note an error condition
|
|
||||||
/*!
|
|
||||||
Force mainLoop() to return by throwing an exception. This call
|
|
||||||
can return before mainLoop() does (i.e. asynchronously). This
|
|
||||||
may only be called between a successful open() and close().
|
|
||||||
*/
|
|
||||||
void exitMainLoopWithError();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef std::list<CThread> CThreadList;
|
// get canonical name of client
|
||||||
|
CString getName(const IClient*) const;
|
||||||
// notify status jobs of a change
|
|
||||||
void runStatusJobs() const;
|
|
||||||
|
|
||||||
// set new status
|
|
||||||
void setStatus(EStatus, const char* msg = NULL);
|
|
||||||
|
|
||||||
// get the sides of the primary screen that have neighbors
|
// get the sides of the primary screen that have neighbors
|
||||||
UInt32 getActivePrimarySides() const;
|
UInt32 getActivePrimarySides() const;
|
||||||
|
|
||||||
// handle mouse motion
|
|
||||||
bool onMouseMovePrimaryNoLock(SInt32 x, SInt32 y);
|
|
||||||
void onMouseMoveSecondaryNoLock(SInt32 dx, SInt32 dy);
|
|
||||||
|
|
||||||
// set the clipboard
|
|
||||||
void onClipboardChangedNoLock(ClipboardID,
|
|
||||||
UInt32 seqNum, const CString& data);
|
|
||||||
|
|
||||||
// returns true iff mouse should be locked to the current screen
|
// returns true iff mouse should be locked to the current screen
|
||||||
bool isLockedToScreenNoLock() const;
|
bool isLockedToScreen() const;
|
||||||
|
|
||||||
|
// returns the jump zone of the client
|
||||||
|
SInt32 getJumpZoneSize(IClient*) const;
|
||||||
|
|
||||||
// change the active screen
|
// change the active screen
|
||||||
void switchScreen(IClient*,
|
void switchScreen(IClient*,
|
||||||
|
@ -260,57 +146,98 @@ private:
|
||||||
bool isSwitchOkay(IClient* dst, EDirection,
|
bool isSwitchOkay(IClient* dst, EDirection,
|
||||||
SInt32 x, SInt32 y);
|
SInt32 x, SInt32 y);
|
||||||
|
|
||||||
// update switch state due to a mouse move that doesn't try to
|
// update switch state due to a mouse move at \p x, \p y that
|
||||||
// switch screens.
|
// doesn't switch screens.
|
||||||
void onNoSwitch(bool inTapZone);
|
void noSwitch(SInt32 x, SInt32 y);
|
||||||
|
|
||||||
// reset switch wait state
|
// stop switch timers
|
||||||
void clearSwitchState();
|
void stopSwitch();
|
||||||
|
|
||||||
|
// start two tap switch timer
|
||||||
|
void startSwitchTwoTap();
|
||||||
|
|
||||||
|
// arm the two tap switch timer if \p x, \p y is outside the tap zone
|
||||||
|
void armSwitchTwoTap(SInt32 x, SInt32 y);
|
||||||
|
|
||||||
|
// stop the two tap switch timer
|
||||||
|
void stopSwitchTwoTap();
|
||||||
|
|
||||||
|
// returns true iff the two tap switch timer is started
|
||||||
|
bool isSwitchTwoTapStarted() const;
|
||||||
|
|
||||||
|
// returns true iff should switch because of two tap
|
||||||
|
bool shouldSwitchTwoTap() const;
|
||||||
|
|
||||||
|
// start delay switch timer
|
||||||
|
void startSwitchWait(SInt32 x, SInt32 y);
|
||||||
|
|
||||||
|
// stop delay switch timer
|
||||||
|
void stopSwitchWait();
|
||||||
|
|
||||||
|
// returns true iff the delay switch timer is started
|
||||||
|
bool isSwitchWaitStarted() const;
|
||||||
|
|
||||||
// send screen options to \c client
|
// send screen options to \c client
|
||||||
void sendOptions(IClient* client) const;
|
void sendOptions(IClient* client) const;
|
||||||
|
|
||||||
// open/close the primary screen
|
// process options from configuration
|
||||||
void openPrimaryScreen();
|
void processOptions();
|
||||||
void closePrimaryScreen();
|
|
||||||
|
|
||||||
// update the clipboard if owned by the primary screen
|
// event handlers
|
||||||
void updatePrimaryClipboard(ClipboardID);
|
void handleShapeChanged(const CEvent&, void*);
|
||||||
|
void handleClipboardGrabbed(const CEvent&, void*);
|
||||||
|
void handleClipboardChanged(const CEvent&, void*);
|
||||||
|
void handleKeyDownEvent(const CEvent&, void*);
|
||||||
|
void handleKeyUpEvent(const CEvent&, void*);
|
||||||
|
void handleKeyRepeatEvent(const CEvent&, void*);
|
||||||
|
void handleButtonDownEvent(const CEvent&, void*);
|
||||||
|
void handleButtonUpEvent(const CEvent&, void*);
|
||||||
|
void handleMotionPrimaryEvent(const CEvent&, void*);
|
||||||
|
void handleMotionSecondaryEvent(const CEvent&, void*);
|
||||||
|
void handleWheelEvent(const CEvent&, void*);
|
||||||
|
void handleScreensaverActivatedEvent(const CEvent&, void*);
|
||||||
|
void handleScreensaverDeactivatedEvent(const CEvent&, void*);
|
||||||
|
void handleSwitchWaitTimeout(const CEvent&, void*);
|
||||||
|
void handleClientDisconnected(const CEvent&, void*);
|
||||||
|
void handleClientCloseTimeout(const CEvent&, void*);
|
||||||
|
|
||||||
// close all clients that are *not* in config, not including the
|
// event processing
|
||||||
// primary client.
|
void onClipboardChanged(IClient* sender,
|
||||||
|
ClipboardID id, UInt32 seqNum);
|
||||||
|
void onScreensaver(bool activated);
|
||||||
|
void onKeyDown(KeyID, KeyModifierMask, KeyButton);
|
||||||
|
void onKeyUp(KeyID, KeyModifierMask, KeyButton);
|
||||||
|
void onKeyRepeat(KeyID, KeyModifierMask, SInt32, KeyButton);
|
||||||
|
void onMouseDown(ButtonID);
|
||||||
|
void onMouseUp(ButtonID);
|
||||||
|
bool onMouseMovePrimary(SInt32 x, SInt32 y);
|
||||||
|
void onMouseMoveSecondary(SInt32 dx, SInt32 dy);
|
||||||
|
void onMouseWheel(SInt32 delta);
|
||||||
|
|
||||||
|
// add client to list and attach event handlers for client
|
||||||
|
bool addClient(IClient*);
|
||||||
|
|
||||||
|
// remove client from list and detach event handlers for client
|
||||||
|
bool removeClient(IClient*);
|
||||||
|
|
||||||
|
// close a client
|
||||||
|
void closeClient(IClient*, const char* msg);
|
||||||
|
|
||||||
|
// close clients not in \p config
|
||||||
void closeClients(const CConfig& config);
|
void closeClients(const CConfig& config);
|
||||||
|
|
||||||
// start a thread, adding it to the list of threads
|
// close all clients whether they've completed the handshake or not,
|
||||||
CThread startThread(IJob* adopted);
|
// except the primary client
|
||||||
|
void closeAllClients();
|
||||||
|
|
||||||
// cancel running threads, waiting at most timeout seconds for
|
// remove clients from internal state
|
||||||
// them to finish.
|
void removeActiveClient(IClient*);
|
||||||
void stopThreads(double timeout = -1.0);
|
void removeOldClient(IClient*);
|
||||||
|
|
||||||
// reap threads, clearing finished threads from the thread list.
|
// force the cursor off of \p client
|
||||||
// doReapThreads does the work on the given thread list.
|
void forceLeaveClient(IClient* client);
|
||||||
void reapThreads();
|
|
||||||
void doReapThreads(CThreadList&);
|
|
||||||
|
|
||||||
// thread method to accept incoming client connections
|
|
||||||
void acceptClients(void*);
|
|
||||||
|
|
||||||
// thread method to do client interaction
|
|
||||||
void runClient(void*);
|
|
||||||
CClientProxy* handshakeClient(IDataSocket*);
|
|
||||||
|
|
||||||
// connection list maintenance
|
|
||||||
void addConnection(IClient*);
|
|
||||||
void removeConnection(const CString& name);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class XServerRethrow : public XBase {
|
|
||||||
protected:
|
|
||||||
// XBase overrides
|
|
||||||
virtual CString getWhat() const throw();
|
|
||||||
};
|
|
||||||
|
|
||||||
class CClipboardInfo {
|
class CClipboardInfo {
|
||||||
public:
|
public:
|
||||||
CClipboardInfo();
|
CClipboardInfo();
|
||||||
|
@ -322,52 +249,27 @@ private:
|
||||||
UInt32 m_clipboardSeqNum;
|
UInt32 m_clipboardSeqNum;
|
||||||
};
|
};
|
||||||
|
|
||||||
CMutex m_mutex;
|
|
||||||
|
|
||||||
// the name of the primary screen
|
|
||||||
CString m_name;
|
|
||||||
|
|
||||||
// true if we should exit the main loop by throwing an exception.
|
|
||||||
// this is used to propagate an exception from one of our threads
|
|
||||||
// to the mainLoop() thread. but, since we can't make a copy of
|
|
||||||
// the original exception, we return an arbitrary, unique
|
|
||||||
// exception type. the caller of mainLoop() cannot catch this
|
|
||||||
// exception except through XBase or ....
|
|
||||||
bool m_error;
|
|
||||||
|
|
||||||
// how long to wait to bind our socket until we give up
|
|
||||||
double m_bindTimeout;
|
|
||||||
|
|
||||||
// factories
|
|
||||||
IScreenFactory* m_screenFactory;
|
|
||||||
ISocketFactory* m_socketFactory;
|
|
||||||
IStreamFilterFactory* m_streamFilterFactory;
|
|
||||||
|
|
||||||
// running threads
|
|
||||||
CThreadList m_threads;
|
|
||||||
CThread* m_acceptClientThread;
|
|
||||||
|
|
||||||
// the screens
|
|
||||||
typedef std::map<CString, IClient*> CClientList;
|
|
||||||
typedef std::map<CString, CThread> CClientThreadList;
|
|
||||||
|
|
||||||
// all clients indexed by name
|
|
||||||
CClientList m_clients;
|
|
||||||
|
|
||||||
// run thread of all secondary screen clients. does not include the
|
|
||||||
// primary screen's run thread.
|
|
||||||
CClientThreadList m_clientThreads;
|
|
||||||
|
|
||||||
// the primary screen client
|
// the primary screen client
|
||||||
CPrimaryClient* m_primaryClient;
|
CPrimaryClient* m_primaryClient;
|
||||||
|
|
||||||
|
// all clients (including the primary client) indexed by name
|
||||||
|
typedef std::map<CString, IClient*> CClientList;
|
||||||
|
typedef std::set<IClient*> CClientSet;
|
||||||
|
CClientList m_clients;
|
||||||
|
CClientSet m_clientSet;
|
||||||
|
|
||||||
|
// all old connections that we're waiting to hangup
|
||||||
|
typedef std::map<IClient*, CEventQueueTimer*> COldClients;
|
||||||
|
COldClients m_oldClients;
|
||||||
|
|
||||||
// the client with focus
|
// the client with focus
|
||||||
IClient* m_active;
|
IClient* m_active;
|
||||||
|
|
||||||
// the sequence number of enter messages
|
// the sequence number of enter messages
|
||||||
UInt32 m_seqNum;
|
UInt32 m_seqNum;
|
||||||
|
|
||||||
// current mouse position (in absolute secondary screen coordinates)
|
// current mouse position (in absolute screen coordinates) on
|
||||||
|
// whichever screen is active
|
||||||
SInt32 m_x, m_y;
|
SInt32 m_x, m_y;
|
||||||
|
|
||||||
// current configuration
|
// current configuration
|
||||||
|
@ -387,8 +289,7 @@ private:
|
||||||
|
|
||||||
// state for delayed screen switching
|
// state for delayed screen switching
|
||||||
double m_switchWaitDelay;
|
double m_switchWaitDelay;
|
||||||
UInt32 m_switchWaitTimer;
|
CEventQueueTimer* m_switchWaitTimer;
|
||||||
bool m_switchWaitEngaged;
|
|
||||||
SInt32 m_switchWaitX, m_switchWaitY;
|
SInt32 m_switchWaitX, m_switchWaitY;
|
||||||
|
|
||||||
// state for double-tap screen switching
|
// state for double-tap screen switching
|
||||||
|
@ -398,19 +299,8 @@ private:
|
||||||
bool m_switchTwoTapArmed;
|
bool m_switchTwoTapArmed;
|
||||||
SInt32 m_switchTwoTapZone;
|
SInt32 m_switchTwoTapZone;
|
||||||
|
|
||||||
// the status change jobs and status
|
static CEvent::Type s_errorEvent;
|
||||||
CJobList m_statusJobs;
|
static CEvent::Type s_disconnectedEvent;
|
||||||
EStatus m_status;
|
|
||||||
CString m_statusMessage;
|
|
||||||
|
|
||||||
//---
|
|
||||||
/*
|
|
||||||
IListenSocket* m_listen;
|
|
||||||
|
|
||||||
typedef std::map<CProvisionalClient*,
|
|
||||||
CEventQueueTimer*> CProvisionalClients;
|
|
||||||
CProvisionalClients m_provisional;
|
|
||||||
*/
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -25,19 +25,21 @@ MAINTAINERCLEANFILES = \
|
||||||
|
|
||||||
noinst_LIBRARIES = libserver.a
|
noinst_LIBRARIES = libserver.a
|
||||||
libserver_a_SOURCES = \
|
libserver_a_SOURCES = \
|
||||||
|
CClientListener.cpp \
|
||||||
CClientProxy.cpp \
|
CClientProxy.cpp \
|
||||||
CClientProxy1_0.cpp \
|
CClientProxy1_0.cpp \
|
||||||
CClientProxy1_1.cpp \
|
CClientProxy1_1.cpp \
|
||||||
|
CClientProxyUnknown.cpp \
|
||||||
CConfig.cpp \
|
CConfig.cpp \
|
||||||
CPrimaryClient.cpp \
|
CPrimaryClient.cpp \
|
||||||
CProvisionalClient.cpp \
|
|
||||||
CServer.cpp \
|
CServer.cpp \
|
||||||
|
CClientListener.h \
|
||||||
CClientProxy.h \
|
CClientProxy.h \
|
||||||
CClientProxy1_0.h \
|
CClientProxy1_0.h \
|
||||||
CClientProxy1_1.h \
|
CClientProxy1_1.h \
|
||||||
|
CClientProxyUnknown.h \
|
||||||
CConfig.h \
|
CConfig.h \
|
||||||
CPrimaryClient.h \
|
CPrimaryClient.h \
|
||||||
CProvisionalClient.h \
|
|
||||||
CServer.h \
|
CServer.h \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
INCLUDES = \
|
INCLUDES = \
|
||||||
|
|
|
@ -73,7 +73,6 @@ CProtocolUtil::vwritef(IStream* stream,
|
||||||
}
|
}
|
||||||
|
|
||||||
// fill buffer
|
// fill buffer
|
||||||
// FIXME -- can we use alloca?
|
|
||||||
UInt8* buffer = new UInt8[size];
|
UInt8* buffer = new UInt8[size];
|
||||||
writef(buffer, fmt, args);
|
writef(buffer, fmt, args);
|
||||||
|
|
||||||
|
|
|
@ -14,41 +14,26 @@
|
||||||
|
|
||||||
#include "CScreen.h"
|
#include "CScreen.h"
|
||||||
#include "IPlatformScreen.h"
|
#include "IPlatformScreen.h"
|
||||||
#include "IScreenReceiver.h"
|
|
||||||
#include "ISecondaryScreen.h"
|
|
||||||
#include "ProtocolTypes.h"
|
#include "ProtocolTypes.h"
|
||||||
#include "CLock.h"
|
|
||||||
#include "CThread.h"
|
|
||||||
#include "CLog.h"
|
#include "CLog.h"
|
||||||
|
#include "IEventQueue.h"
|
||||||
|
|
||||||
//
|
//
|
||||||
// CScreen
|
// CScreen
|
||||||
//
|
//
|
||||||
|
|
||||||
CScreen::CScreen(IPlatformScreen* platformScreen, IScreenReceiver* receiver) :
|
CScreen::CScreen(IPlatformScreen* platformScreen) :
|
||||||
m_screen(platformScreen),
|
m_screen(platformScreen),
|
||||||
m_receiver(receiver),
|
|
||||||
m_isPrimary(platformScreen->isPrimary()),
|
m_isPrimary(platformScreen->isPrimary()),
|
||||||
m_enabled(false),
|
m_enabled(false),
|
||||||
m_entered(m_isPrimary),
|
m_entered(m_isPrimary),
|
||||||
m_toggleKeys(0),
|
m_toggleKeys(0),
|
||||||
m_screenSaverSync(true)
|
m_screenSaverSync(true)
|
||||||
{
|
{
|
||||||
// do nothing
|
assert(m_screen != NULL);
|
||||||
}
|
|
||||||
|
|
||||||
CScreen::~CScreen()
|
|
||||||
{
|
|
||||||
delete m_screen;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CScreen::open()
|
|
||||||
{
|
|
||||||
CLock lock(&m_mutex);
|
|
||||||
|
|
||||||
// open screen
|
// open screen
|
||||||
m_screen->open(this);
|
m_screen->setKeyState(this);
|
||||||
|
|
||||||
// reset options
|
// reset options
|
||||||
resetOptions();
|
resetOptions();
|
||||||
|
@ -56,23 +41,20 @@ CScreen::open()
|
||||||
LOG((CLOG_DEBUG "opened display"));
|
LOG((CLOG_DEBUG "opened display"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
CScreen::~CScreen()
|
||||||
CScreen::close()
|
|
||||||
{
|
{
|
||||||
CLock lock(&m_mutex);
|
if (m_enabled) {
|
||||||
|
disable();
|
||||||
|
}
|
||||||
assert(!m_enabled);
|
assert(!m_enabled);
|
||||||
assert(m_entered == m_isPrimary);
|
assert(m_entered == m_isPrimary);
|
||||||
|
delete m_screen;
|
||||||
// close screen
|
|
||||||
m_screen->close();
|
|
||||||
|
|
||||||
LOG((CLOG_DEBUG "closed display"));
|
LOG((CLOG_DEBUG "closed display"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CScreen::enable()
|
CScreen::enable()
|
||||||
{
|
{
|
||||||
CLock lock(&m_mutex);
|
|
||||||
assert(!m_enabled);
|
assert(!m_enabled);
|
||||||
|
|
||||||
m_screen->enable();
|
m_screen->enable();
|
||||||
|
@ -90,7 +72,6 @@ CScreen::enable()
|
||||||
void
|
void
|
||||||
CScreen::disable()
|
CScreen::disable()
|
||||||
{
|
{
|
||||||
CLock lock(&m_mutex);
|
|
||||||
assert(m_enabled);
|
assert(m_enabled);
|
||||||
|
|
||||||
if (!m_isPrimary && m_entered) {
|
if (!m_isPrimary && m_entered) {
|
||||||
|
@ -111,34 +92,9 @@ CScreen::disable()
|
||||||
m_enabled = false;
|
m_enabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
CScreen::mainLoop()
|
|
||||||
{
|
|
||||||
// change our priority
|
|
||||||
CThread::getCurrentThread().setPriority(-14);
|
|
||||||
|
|
||||||
// run event loop
|
|
||||||
try {
|
|
||||||
LOG((CLOG_DEBUG "entering event loop"));
|
|
||||||
m_screen->mainLoop();
|
|
||||||
LOG((CLOG_DEBUG "exiting event loop"));
|
|
||||||
}
|
|
||||||
catch (...) {
|
|
||||||
LOG((CLOG_DEBUG "exiting event loop"));
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CScreen::exitMainLoop()
|
|
||||||
{
|
|
||||||
m_screen->exitMainLoop();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
CScreen::enter()
|
CScreen::enter()
|
||||||
{
|
{
|
||||||
CLock lock(&m_mutex);
|
|
||||||
assert(m_entered == false);
|
assert(m_entered == false);
|
||||||
LOG((CLOG_INFO "entering screen"));
|
LOG((CLOG_INFO "entering screen"));
|
||||||
|
|
||||||
|
@ -157,7 +113,6 @@ CScreen::enter()
|
||||||
bool
|
bool
|
||||||
CScreen::leave()
|
CScreen::leave()
|
||||||
{
|
{
|
||||||
CLock lock(&m_mutex);
|
|
||||||
assert(m_entered == true);
|
assert(m_entered == true);
|
||||||
LOG((CLOG_INFO "leaving screen"));
|
LOG((CLOG_INFO "leaving screen"));
|
||||||
|
|
||||||
|
@ -209,8 +164,6 @@ CScreen::grabClipboard(ClipboardID id)
|
||||||
void
|
void
|
||||||
CScreen::screensaver(bool activate)
|
CScreen::screensaver(bool activate)
|
||||||
{
|
{
|
||||||
CLock lock(&m_mutex);
|
|
||||||
|
|
||||||
if (!m_isPrimary) {
|
if (!m_isPrimary) {
|
||||||
// activate/deactivation screen saver iff synchronization enabled
|
// activate/deactivation screen saver iff synchronization enabled
|
||||||
if (m_screenSaverSync) {
|
if (m_screenSaverSync) {
|
||||||
|
@ -222,7 +175,6 @@ CScreen::screensaver(bool activate)
|
||||||
void
|
void
|
||||||
CScreen::keyDown(KeyID id, KeyModifierMask mask, KeyButton button)
|
CScreen::keyDown(KeyID id, KeyModifierMask mask, KeyButton button)
|
||||||
{
|
{
|
||||||
CLock lock(&m_mutex);
|
|
||||||
assert(!m_isPrimary);
|
assert(!m_isPrimary);
|
||||||
|
|
||||||
// check for ctrl+alt+del emulation
|
// check for ctrl+alt+del emulation
|
||||||
|
@ -256,7 +208,6 @@ void
|
||||||
CScreen::keyRepeat(KeyID id,
|
CScreen::keyRepeat(KeyID id,
|
||||||
KeyModifierMask mask, SInt32 count, KeyButton button)
|
KeyModifierMask mask, SInt32 count, KeyButton button)
|
||||||
{
|
{
|
||||||
CLock lock(&m_mutex);
|
|
||||||
assert(!m_isPrimary);
|
assert(!m_isPrimary);
|
||||||
|
|
||||||
// if we haven't seen this button go down then ignore it
|
// if we haven't seen this button go down then ignore it
|
||||||
|
@ -316,7 +267,6 @@ CScreen::keyRepeat(KeyID id,
|
||||||
void
|
void
|
||||||
CScreen::keyUp(KeyID, KeyModifierMask, KeyButton button)
|
CScreen::keyUp(KeyID, KeyModifierMask, KeyButton button)
|
||||||
{
|
{
|
||||||
CLock lock(&m_mutex);
|
|
||||||
assert(!m_isPrimary);
|
assert(!m_isPrimary);
|
||||||
|
|
||||||
// if we haven't seen this button go down then ignore it
|
// if we haven't seen this button go down then ignore it
|
||||||
|
@ -372,8 +322,6 @@ CScreen::mouseWheel(SInt32 delta)
|
||||||
void
|
void
|
||||||
CScreen::resetOptions()
|
CScreen::resetOptions()
|
||||||
{
|
{
|
||||||
CLock lock(&m_mutex);
|
|
||||||
|
|
||||||
// reset options
|
// reset options
|
||||||
m_numLockHalfDuplex = false;
|
m_numLockHalfDuplex = false;
|
||||||
m_capsLockHalfDuplex = false;
|
m_capsLockHalfDuplex = false;
|
||||||
|
@ -394,8 +342,6 @@ CScreen::resetOptions()
|
||||||
void
|
void
|
||||||
CScreen::setOptions(const COptionsList& options)
|
CScreen::setOptions(const COptionsList& options)
|
||||||
{
|
{
|
||||||
CLock lock(&m_mutex);
|
|
||||||
|
|
||||||
// update options
|
// update options
|
||||||
bool oldScreenSaverSync = m_screenSaverSync;
|
bool oldScreenSaverSync = m_screenSaverSync;
|
||||||
for (UInt32 i = 0, n = options.size(); i < n; i += 2) {
|
for (UInt32 i = 0, n = options.size(); i < n; i += 2) {
|
||||||
|
@ -427,37 +373,18 @@ CScreen::setOptions(const COptionsList& options)
|
||||||
m_screen->setOptions(options);
|
m_screen->setOptions(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
UInt32
|
void
|
||||||
CScreen::addOneShotTimer(double timeout)
|
CScreen::setSequenceNumber(UInt32 seqNum)
|
||||||
{
|
{
|
||||||
return m_screen->addOneShotTimer(timeout);
|
return m_screen->setSequenceNumber(seqNum);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CScreen::isOnScreen() const
|
CScreen::isOnScreen() const
|
||||||
{
|
{
|
||||||
CLock lock(&m_mutex);
|
|
||||||
return m_entered;
|
return m_entered;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
CScreen::getClipboard(ClipboardID id,
|
|
||||||
IClipboard* clipboard) const
|
|
||||||
{
|
|
||||||
m_screen->getClipboard(id, clipboard);
|
|
||||||
}
|
|
||||||
|
|
||||||
SInt32
|
|
||||||
CScreen::getJumpZoneSize() const
|
|
||||||
{
|
|
||||||
if (!m_isPrimary) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return m_screen->getJumpZoneSize();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CScreen::isLockedToScreen() const
|
CScreen::isLockedToScreen() const
|
||||||
{
|
{
|
||||||
|
@ -488,6 +415,35 @@ CScreen::isLockedToScreen() const
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SInt32
|
||||||
|
CScreen::getJumpZoneSize() const
|
||||||
|
{
|
||||||
|
if (!m_isPrimary) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return m_screen->getJumpZoneSize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CScreen::getCursorCenter(SInt32& x, SInt32& y) const
|
||||||
|
{
|
||||||
|
m_screen->getCursorCenter(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void*
|
||||||
|
CScreen::getEventTarget() const
|
||||||
|
{
|
||||||
|
return m_screen;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CScreen::getClipboard(ClipboardID id, IClipboard* clipboard) const
|
||||||
|
{
|
||||||
|
return m_screen->getClipboard(id, clipboard);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CScreen::getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) const
|
CScreen::getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) const
|
||||||
{
|
{
|
||||||
|
@ -503,8 +459,6 @@ CScreen::getCursorPos(SInt32& x, SInt32& y) const
|
||||||
void
|
void
|
||||||
CScreen::updateKeys()
|
CScreen::updateKeys()
|
||||||
{
|
{
|
||||||
CLock lock(&m_mutex);
|
|
||||||
|
|
||||||
// clear key state
|
// clear key state
|
||||||
memset(m_keys, 0, sizeof(m_keys));
|
memset(m_keys, 0, sizeof(m_keys));
|
||||||
memset(m_fakeKeys, 0, sizeof(m_fakeKeys));
|
memset(m_fakeKeys, 0, sizeof(m_fakeKeys));
|
||||||
|
@ -522,8 +476,6 @@ CScreen::updateKeys()
|
||||||
void
|
void
|
||||||
CScreen::releaseKeys()
|
CScreen::releaseKeys()
|
||||||
{
|
{
|
||||||
CLock lock(&m_mutex);
|
|
||||||
|
|
||||||
// release keys that we've synthesized a press for and only those
|
// release keys that we've synthesized a press for and only those
|
||||||
// keys. we don't want to synthesize a release on a key the user
|
// keys. we don't want to synthesize a release on a key the user
|
||||||
// is still physically pressing.
|
// is still physically pressing.
|
||||||
|
@ -539,16 +491,12 @@ CScreen::releaseKeys()
|
||||||
void
|
void
|
||||||
CScreen::setKeyDown(KeyButton key)
|
CScreen::setKeyDown(KeyButton key)
|
||||||
{
|
{
|
||||||
CLock lock(&m_mutex);
|
|
||||||
|
|
||||||
m_keys[key & 0xffu] |= kDown;
|
m_keys[key & 0xffu] |= kDown;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CScreen::setToggled(KeyModifierMask mask)
|
CScreen::setToggled(KeyModifierMask mask)
|
||||||
{
|
{
|
||||||
CLock lock(&m_mutex);
|
|
||||||
|
|
||||||
if (!isToggle(mask)) {
|
if (!isToggle(mask)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -565,8 +513,6 @@ CScreen::setToggled(KeyModifierMask mask)
|
||||||
void
|
void
|
||||||
CScreen::addModifier(KeyModifierMask mask, KeyButtons& keys)
|
CScreen::addModifier(KeyModifierMask mask, KeyButtons& keys)
|
||||||
{
|
{
|
||||||
CLock lock(&m_mutex);
|
|
||||||
|
|
||||||
// the modifier must have associated keys
|
// the modifier must have associated keys
|
||||||
if (keys.empty()) {
|
if (keys.empty()) {
|
||||||
return;
|
return;
|
||||||
|
@ -608,8 +554,6 @@ CScreen::setToggleState(KeyModifierMask mask)
|
||||||
KeyButton
|
KeyButton
|
||||||
CScreen::isAnyKeyDown() const
|
CScreen::isAnyKeyDown() const
|
||||||
{
|
{
|
||||||
CLock lock(&m_mutex);
|
|
||||||
|
|
||||||
for (UInt32 i = 1; i < 256; ++i) {
|
for (UInt32 i = 1; i < 256; ++i) {
|
||||||
if ((m_keys[i] & kDown) != 0) {
|
if ((m_keys[i] & kDown) != 0) {
|
||||||
return static_cast<KeyButton>(i);
|
return static_cast<KeyButton>(i);
|
||||||
|
@ -621,8 +565,6 @@ CScreen::isAnyKeyDown() const
|
||||||
bool
|
bool
|
||||||
CScreen::isKeyDown(KeyButton key) const
|
CScreen::isKeyDown(KeyButton key) const
|
||||||
{
|
{
|
||||||
CLock lock(&m_mutex);
|
|
||||||
|
|
||||||
key &= 0xffu;
|
key &= 0xffu;
|
||||||
return (key != 0 && ((m_keys[key] & kDown) != 0));
|
return (key != 0 && ((m_keys[key] & kDown) != 0));
|
||||||
}
|
}
|
||||||
|
@ -638,8 +580,6 @@ CScreen::isToggle(KeyModifierMask mask) const
|
||||||
bool
|
bool
|
||||||
CScreen::isHalfDuplex(KeyModifierMask mask) const
|
CScreen::isHalfDuplex(KeyModifierMask mask) const
|
||||||
{
|
{
|
||||||
CLock lock(&m_mutex);
|
|
||||||
|
|
||||||
return ((mask == KeyModifierCapsLock && m_capsLockHalfDuplex) ||
|
return ((mask == KeyModifierCapsLock && m_capsLockHalfDuplex) ||
|
||||||
(mask == KeyModifierNumLock && m_numLockHalfDuplex));
|
(mask == KeyModifierNumLock && m_numLockHalfDuplex));
|
||||||
}
|
}
|
||||||
|
@ -647,8 +587,6 @@ CScreen::isHalfDuplex(KeyModifierMask mask) const
|
||||||
bool
|
bool
|
||||||
CScreen::isModifierActive(KeyModifierMask mask) const
|
CScreen::isModifierActive(KeyModifierMask mask) const
|
||||||
{
|
{
|
||||||
CLock lock(&m_mutex);
|
|
||||||
|
|
||||||
MaskToKeys::const_iterator i = m_maskToKeys.find(mask);
|
MaskToKeys::const_iterator i = m_maskToKeys.find(mask);
|
||||||
if (i == m_maskToKeys.end()) {
|
if (i == m_maskToKeys.end()) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -675,7 +613,6 @@ CScreen::isModifierActive(KeyModifierMask mask) const
|
||||||
KeyModifierMask
|
KeyModifierMask
|
||||||
CScreen::getActiveModifiers() const
|
CScreen::getActiveModifiers() const
|
||||||
{
|
{
|
||||||
CLock lock(&m_mutex);
|
|
||||||
if (m_isPrimary) {
|
if (m_isPrimary) {
|
||||||
// we don't keep primary key state up to date so get the
|
// we don't keep primary key state up to date so get the
|
||||||
// current state.
|
// current state.
|
||||||
|
@ -688,8 +625,6 @@ bool
|
||||||
CScreen::mapModifier(Keystrokes& keys, Keystrokes& undo,
|
CScreen::mapModifier(Keystrokes& keys, Keystrokes& undo,
|
||||||
KeyModifierMask mask, bool desireActive) const
|
KeyModifierMask mask, bool desireActive) const
|
||||||
{
|
{
|
||||||
CLock lock(&m_mutex);
|
|
||||||
|
|
||||||
// look up modifier
|
// look up modifier
|
||||||
MaskToKeys::const_iterator i = m_maskToKeys.find(mask);
|
MaskToKeys::const_iterator i = m_maskToKeys.find(mask);
|
||||||
if (i == m_maskToKeys.end()) {
|
if (i == m_maskToKeys.end()) {
|
||||||
|
@ -751,7 +686,6 @@ CScreen::mapModifier(Keystrokes& keys, Keystrokes& undo,
|
||||||
KeyModifierMask
|
KeyModifierMask
|
||||||
CScreen::getMaskForKey(KeyButton key) const
|
CScreen::getMaskForKey(KeyButton key) const
|
||||||
{
|
{
|
||||||
CLock lock(&m_mutex);
|
|
||||||
KeyToMask::const_iterator i = m_keyToMask.find(key);
|
KeyToMask::const_iterator i = m_keyToMask.find(key);
|
||||||
if (i == m_keyToMask.end()) {
|
if (i == m_keyToMask.end()) {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -767,12 +701,8 @@ CScreen::enablePrimary()
|
||||||
// get notified of screen saver activation/deactivation
|
// get notified of screen saver activation/deactivation
|
||||||
m_screen->openScreensaver(true);
|
m_screen->openScreensaver(true);
|
||||||
|
|
||||||
// collect and send screen info
|
// claim screen changed size
|
||||||
CClientInfo info;
|
EVENTQUEUE->addEvent(CEvent(getShapeChangedEvent(), getEventTarget()));
|
||||||
m_screen->getShape(info.m_x, info.m_y, info.m_w, info.m_h);
|
|
||||||
m_screen->getCursorPos(info.m_mx, info.m_my);
|
|
||||||
info.m_zoneSize = getJumpZoneSize();
|
|
||||||
m_receiver->onInfoChanged(info);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -12,45 +12,32 @@
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef CSECONDARYSCREEN_H
|
#ifndef CSCREEN_H
|
||||||
#define CSECONDARYSCREEN_H
|
#define CSCREEN_H
|
||||||
|
|
||||||
#include "IKeyState.h"
|
#include "IKeyState.h"
|
||||||
|
#include "IScreen.h"
|
||||||
#include "ClipboardTypes.h"
|
#include "ClipboardTypes.h"
|
||||||
#include "MouseTypes.h"
|
#include "MouseTypes.h"
|
||||||
#include "OptionTypes.h"
|
#include "OptionTypes.h"
|
||||||
#include "CMutex.h"
|
|
||||||
#include "stdmap.h"
|
#include "stdmap.h"
|
||||||
|
|
||||||
class IClipboard;
|
class IClipboard;
|
||||||
class IPlatformScreen;
|
class IPlatformScreen;
|
||||||
class IScreenReceiver;
|
|
||||||
|
|
||||||
//! Platform independent screen
|
//! Platform independent screen
|
||||||
/*!
|
/*!
|
||||||
This is a platform independent screen. It can work as either a
|
This is a platform independent screen. It can work as either a
|
||||||
primary or secondary screen.
|
primary or secondary screen.
|
||||||
*/
|
*/
|
||||||
class CScreen : public IKeyState {
|
class CScreen : public IScreen, public IKeyState {
|
||||||
public:
|
public:
|
||||||
CScreen(IPlatformScreen* platformScreen, IScreenReceiver*);
|
CScreen(IPlatformScreen* platformScreen);
|
||||||
virtual ~CScreen();
|
virtual ~CScreen();
|
||||||
|
|
||||||
//! @name manipulators
|
//! @name manipulators
|
||||||
//@{
|
//@{
|
||||||
|
|
||||||
//! Open screen
|
|
||||||
/*!
|
|
||||||
Opens the screen.
|
|
||||||
*/
|
|
||||||
void open();
|
|
||||||
|
|
||||||
//! Close screen
|
|
||||||
/*!
|
|
||||||
Closes the screen.
|
|
||||||
*/
|
|
||||||
void close();
|
|
||||||
|
|
||||||
//! Activate screen
|
//! Activate screen
|
||||||
/*!
|
/*!
|
||||||
Activate the screen, preparing it to report system and user events.
|
Activate the screen, preparing it to report system and user events.
|
||||||
|
@ -66,21 +53,6 @@ public:
|
||||||
*/
|
*/
|
||||||
void disable();
|
void disable();
|
||||||
|
|
||||||
//! Run event loop
|
|
||||||
/*!
|
|
||||||
Run the screen's event loop. This returns when it detects
|
|
||||||
the application should terminate or when exitMainLoop() is called.
|
|
||||||
mainLoop() may only be called between open() and close().
|
|
||||||
*/
|
|
||||||
void mainLoop();
|
|
||||||
|
|
||||||
//! Exit event loop
|
|
||||||
/*!
|
|
||||||
Force mainLoop() to return. This call can return before
|
|
||||||
mainLoop() does (i.e. asynchronously).
|
|
||||||
*/
|
|
||||||
void exitMainLoop();
|
|
||||||
|
|
||||||
//! Enter screen
|
//! Enter screen
|
||||||
/*!
|
/*!
|
||||||
Called when the user navigates to this screen.
|
Called when the user navigates to this screen.
|
||||||
|
@ -196,12 +168,11 @@ public:
|
||||||
*/
|
*/
|
||||||
void setOptions(const COptionsList& options);
|
void setOptions(const COptionsList& options);
|
||||||
|
|
||||||
//! Install a one-shot timer
|
//! Set clipboard sequence number
|
||||||
/*!
|
/*!
|
||||||
Installs a one-shot timer for \c timeout seconds and returns the
|
Sets the sequence number to use in subsequent clipboard events.
|
||||||
id of the timer.
|
|
||||||
*/
|
*/
|
||||||
UInt32 addOneShotTimer(double timeout);
|
void setSequenceNumber(UInt32);
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
//! @name accessors
|
//! @name accessors
|
||||||
|
@ -213,19 +184,6 @@ public:
|
||||||
*/
|
*/
|
||||||
bool isOnScreen() const;
|
bool isOnScreen() const;
|
||||||
|
|
||||||
//! Get clipboard
|
|
||||||
/*!
|
|
||||||
Saves the contents of the system clipboard indicated by \c id.
|
|
||||||
*/
|
|
||||||
void getClipboard(ClipboardID id, IClipboard*) const;
|
|
||||||
|
|
||||||
//! Get jump zone size
|
|
||||||
/*!
|
|
||||||
Returns the jump zone size, the size of the regions on the edges of
|
|
||||||
the screen that cause the cursor to jump to another screen.
|
|
||||||
*/
|
|
||||||
SInt32 getJumpZoneSize() const;
|
|
||||||
|
|
||||||
//! Get screen lock state
|
//! Get screen lock state
|
||||||
/*!
|
/*!
|
||||||
Returns true if there's any reason that the user should not be
|
Returns true if there's any reason that the user should not be
|
||||||
|
@ -236,22 +194,30 @@ public:
|
||||||
*/
|
*/
|
||||||
bool isLockedToScreen() const;
|
bool isLockedToScreen() const;
|
||||||
|
|
||||||
//! Get screen shape
|
//! Get jump zone size
|
||||||
/*!
|
/*!
|
||||||
Returns the position of the upper-left corner of the screen in \c x
|
Return the jump zone size, the size of the regions on the edges of
|
||||||
and \c y and the size of the screen in \c width and \c height.
|
the screen that cause the cursor to jump to another screen.
|
||||||
*/
|
*/
|
||||||
void getShape(SInt32& x, SInt32& y,
|
SInt32 getJumpZoneSize() const;
|
||||||
SInt32& width, SInt32& height) const;
|
|
||||||
|
|
||||||
//! Get cursor position
|
//! Get cursor center position
|
||||||
/*!
|
/*!
|
||||||
Returns the current position of the cursor in \c x,y.
|
Return the cursor center position which is where we park the
|
||||||
|
cursor to compute cursor motion deltas and should be far from
|
||||||
|
the edges of the screen, typically the center.
|
||||||
*/
|
*/
|
||||||
void getCursorPos(SInt32& x, SInt32& y) const;
|
void getCursorCenter(SInt32& x, SInt32& y) const;
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
|
// IScreen overrides
|
||||||
|
virtual void* getEventTarget() const;
|
||||||
|
virtual bool getClipboard(ClipboardID id, IClipboard*) const;
|
||||||
|
virtual void getShape(SInt32& x, SInt32& y,
|
||||||
|
SInt32& width, SInt32& height) const;
|
||||||
|
virtual void getCursorPos(SInt32& x, SInt32& y) const;
|
||||||
|
|
||||||
// IKeyState overrides
|
// IKeyState overrides
|
||||||
virtual void updateKeys();
|
virtual void updateKeys();
|
||||||
virtual void releaseKeys();
|
virtual void releaseKeys();
|
||||||
|
@ -307,14 +273,9 @@ private:
|
||||||
typedef std::map<KeyModifierMask, KeyButtons> MaskToKeys;
|
typedef std::map<KeyModifierMask, KeyButtons> MaskToKeys;
|
||||||
typedef std::map<KeyButton, KeyModifierMask> KeyToMask;
|
typedef std::map<KeyButton, KeyModifierMask> KeyToMask;
|
||||||
|
|
||||||
CMutex m_mutex;
|
|
||||||
|
|
||||||
// our platform dependent screen
|
// our platform dependent screen
|
||||||
IPlatformScreen* m_screen;
|
IPlatformScreen* m_screen;
|
||||||
|
|
||||||
// our screen receiver
|
|
||||||
IScreenReceiver* m_receiver;
|
|
||||||
|
|
||||||
// true if screen is being used as a primary screen, false otherwise
|
// true if screen is being used as a primary screen, false otherwise
|
||||||
bool m_isPrimary;
|
bool m_isPrimary;
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
#ifndef ICLIENT_H
|
#ifndef ICLIENT_H
|
||||||
#define ICLIENT_H
|
#define ICLIENT_H
|
||||||
|
|
||||||
#include "IInterface.h"
|
#include "IScreen.h"
|
||||||
#include "ClipboardTypes.h"
|
#include "ClipboardTypes.h"
|
||||||
#include "KeyTypes.h"
|
#include "KeyTypes.h"
|
||||||
#include "MouseTypes.h"
|
#include "MouseTypes.h"
|
||||||
|
@ -27,43 +27,18 @@
|
||||||
This interface defines the methods necessary for the server to
|
This interface defines the methods necessary for the server to
|
||||||
communicate with a client.
|
communicate with a client.
|
||||||
*/
|
*/
|
||||||
class IClient : public IInterface {
|
class IClient : public IScreen {
|
||||||
public:
|
public:
|
||||||
//! @name manipulators
|
//! @name manipulators
|
||||||
//@{
|
//@{
|
||||||
|
|
||||||
//! Open client
|
|
||||||
/*!
|
|
||||||
Open the client. Throw if the client cannot be opened. If the
|
|
||||||
screen cannot be opened but retrying later may succeed then throw
|
|
||||||
XScreenUnavailable.
|
|
||||||
*/
|
|
||||||
virtual void open() = 0;
|
|
||||||
|
|
||||||
//! Client main loop
|
|
||||||
/*!
|
|
||||||
Run client's event loop. This method is typically called in a
|
|
||||||
separate thread and is exited by cancelling the thread. This
|
|
||||||
must be called between a successful open() and close().
|
|
||||||
|
|
||||||
(cancellation point)
|
|
||||||
*/
|
|
||||||
virtual void mainLoop() = 0;
|
|
||||||
|
|
||||||
//! Close client
|
|
||||||
/*!
|
|
||||||
Close the client.
|
|
||||||
*/
|
|
||||||
virtual void close() = 0;
|
|
||||||
|
|
||||||
//! Enter screen
|
//! Enter screen
|
||||||
/*!
|
/*!
|
||||||
Enter the screen. The cursor should be warped to \c xAbs,yAbs.
|
Enter the screen. The cursor should be warped to \p xAbs,yAbs.
|
||||||
The client should record seqNum for future reporting of
|
\p mask is the expected toggle button state and the client should
|
||||||
clipboard changes. \c mask is the expected toggle button state
|
update its state to match. \p forScreensaver is true iff the
|
||||||
and the client should update its state to match. \c forScreensaver
|
screen is being entered because the screen saver is starting.
|
||||||
is true iff the screen is being entered because the screen saver is
|
Subsequent clipboard events should report \p seqNum.
|
||||||
starting.
|
|
||||||
*/
|
*/
|
||||||
virtual void enter(SInt32 xAbs, SInt32 yAbs,
|
virtual void enter(SInt32 xAbs, SInt32 yAbs,
|
||||||
UInt32 seqNum, KeyModifierMask mask,
|
UInt32 seqNum, KeyModifierMask mask,
|
||||||
|
@ -180,35 +155,14 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual CString getName() const = 0;
|
virtual CString getName() const = 0;
|
||||||
|
|
||||||
//! Get jump zone size
|
//@}
|
||||||
/*!
|
|
||||||
Called to get the jump zone size.
|
|
||||||
*/
|
|
||||||
virtual SInt32 getJumpZoneSize() const = 0;
|
|
||||||
|
|
||||||
//! Get screen shape
|
// IScreen overrides
|
||||||
/*!
|
virtual void* getEventTarget() const = 0;
|
||||||
Return the position of the upper-left corner of the screen in \c x and
|
virtual bool getClipboard(ClipboardID id, IClipboard*) const = 0;
|
||||||
\c y and the size of the screen in \c width and \c height.
|
|
||||||
*/
|
|
||||||
virtual void getShape(SInt32& x, SInt32& y,
|
virtual void getShape(SInt32& x, SInt32& y,
|
||||||
SInt32& width, SInt32& height) const = 0;
|
SInt32& width, SInt32& height) const = 0;
|
||||||
|
|
||||||
//! Get cursor position
|
|
||||||
/*!
|
|
||||||
Return the current position of the cursor in \c x and \c y.
|
|
||||||
*/
|
|
||||||
virtual void getCursorPos(SInt32& x, SInt32& y) const = 0;
|
virtual void getCursorPos(SInt32& x, SInt32& y) const = 0;
|
||||||
|
|
||||||
//! Get cursor center position
|
|
||||||
/*!
|
|
||||||
Return the cursor center position which is where we park the
|
|
||||||
cursor to compute cursor motion deltas and should be far from
|
|
||||||
the edges of the screen, typically the center.
|
|
||||||
*/
|
|
||||||
virtual void getCursorCenter(SInt32& x, SInt32& y) const = 0;
|
|
||||||
|
|
||||||
//@}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -0,0 +1,149 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2004 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* This package is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* found in the file COPYING that should have accompanied this file.
|
||||||
|
*
|
||||||
|
* This package is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "IPlatformScreen.h"
|
||||||
|
|
||||||
|
//
|
||||||
|
// IPlatformScreen
|
||||||
|
//
|
||||||
|
|
||||||
|
CEvent::Type IPlatformScreen::s_keyDownEvent = CEvent::kUnknown;
|
||||||
|
CEvent::Type IPlatformScreen::s_keyUpEvent = CEvent::kUnknown;
|
||||||
|
CEvent::Type IPlatformScreen::s_keyRepeatEvent = CEvent::kUnknown;
|
||||||
|
CEvent::Type IPlatformScreen::s_buttonDownEvent = CEvent::kUnknown;
|
||||||
|
CEvent::Type IPlatformScreen::s_buttonUpEvent = CEvent::kUnknown;
|
||||||
|
CEvent::Type IPlatformScreen::s_motionPrimaryEvent = CEvent::kUnknown;
|
||||||
|
CEvent::Type IPlatformScreen::s_motionSecondaryEvent = CEvent::kUnknown;
|
||||||
|
CEvent::Type IPlatformScreen::s_wheelEvent = CEvent::kUnknown;
|
||||||
|
CEvent::Type IPlatformScreen::s_ssActivatedEvent = CEvent::kUnknown;
|
||||||
|
CEvent::Type IPlatformScreen::s_ssDeactivatedEvent = CEvent::kUnknown;
|
||||||
|
|
||||||
|
CEvent::Type
|
||||||
|
IPlatformScreen::getKeyDownEvent()
|
||||||
|
{
|
||||||
|
return CEvent::registerTypeOnce(s_keyDownEvent,
|
||||||
|
"IPlatformScreen::keyDown");
|
||||||
|
}
|
||||||
|
|
||||||
|
CEvent::Type
|
||||||
|
IPlatformScreen::getKeyUpEvent()
|
||||||
|
{
|
||||||
|
return CEvent::registerTypeOnce(s_keyUpEvent,
|
||||||
|
"IPlatformScreen::keyUp");
|
||||||
|
}
|
||||||
|
|
||||||
|
CEvent::Type
|
||||||
|
IPlatformScreen::getKeyRepeatEvent()
|
||||||
|
{
|
||||||
|
return CEvent::registerTypeOnce(s_keyRepeatEvent,
|
||||||
|
"IPlatformScreen::keyRepeat");
|
||||||
|
}
|
||||||
|
|
||||||
|
CEvent::Type
|
||||||
|
IPlatformScreen::getButtonDownEvent()
|
||||||
|
{
|
||||||
|
return CEvent::registerTypeOnce(s_buttonDownEvent,
|
||||||
|
"IPlatformScreen::buttonDown");
|
||||||
|
}
|
||||||
|
|
||||||
|
CEvent::Type
|
||||||
|
IPlatformScreen::getButtonUpEvent()
|
||||||
|
{
|
||||||
|
return CEvent::registerTypeOnce(s_buttonUpEvent,
|
||||||
|
"IPlatformScreen::buttonUp");
|
||||||
|
}
|
||||||
|
|
||||||
|
CEvent::Type
|
||||||
|
IPlatformScreen::getMotionOnPrimaryEvent()
|
||||||
|
{
|
||||||
|
return CEvent::registerTypeOnce(s_motionPrimaryEvent,
|
||||||
|
"IPlatformScreen::motionPrimary");
|
||||||
|
}
|
||||||
|
|
||||||
|
CEvent::Type
|
||||||
|
IPlatformScreen::getMotionOnSecondaryEvent()
|
||||||
|
{
|
||||||
|
return CEvent::registerTypeOnce(s_motionSecondaryEvent,
|
||||||
|
"IPlatformScreen::motionSecondary");
|
||||||
|
}
|
||||||
|
|
||||||
|
CEvent::Type
|
||||||
|
IPlatformScreen::getWheelEvent()
|
||||||
|
{
|
||||||
|
return CEvent::registerTypeOnce(s_wheelEvent,
|
||||||
|
"IPlatformScreen::wheel");
|
||||||
|
}
|
||||||
|
|
||||||
|
CEvent::Type
|
||||||
|
IPlatformScreen::getScreensaverActivatedEvent()
|
||||||
|
{
|
||||||
|
return CEvent::registerTypeOnce(s_ssActivatedEvent,
|
||||||
|
"IPlatformScreen::screensaverActivated");
|
||||||
|
}
|
||||||
|
|
||||||
|
CEvent::Type
|
||||||
|
IPlatformScreen::getScreensaverDeactivatedEvent()
|
||||||
|
{
|
||||||
|
return CEvent::registerTypeOnce(s_ssDeactivatedEvent,
|
||||||
|
"IPlatformScreen::screensaverDeactivated");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// IPlatformScreen::CKeyInfo
|
||||||
|
//
|
||||||
|
|
||||||
|
IPlatformScreen::CKeyInfo::CKeyInfo(KeyID id,
|
||||||
|
KeyModifierMask mask, KeyButton button, SInt32 count) :
|
||||||
|
m_key(id),
|
||||||
|
m_mask(mask),
|
||||||
|
m_button(button),
|
||||||
|
m_count(count)
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// IPlatformScreen::CButtonInfo
|
||||||
|
//
|
||||||
|
|
||||||
|
IPlatformScreen::CButtonInfo::CButtonInfo(ButtonID id) :
|
||||||
|
m_button(id)
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// IPlatformScreen::CMotionInfo
|
||||||
|
//
|
||||||
|
|
||||||
|
IPlatformScreen::CMotionInfo::CMotionInfo(SInt32 x, SInt32 y) :
|
||||||
|
m_x(x),
|
||||||
|
m_y(y)
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// IPlatformScreen::CWheelInfo
|
||||||
|
//
|
||||||
|
|
||||||
|
IPlatformScreen::CWheelInfo::CWheelInfo(SInt32 wheel) :
|
||||||
|
m_wheel(wheel)
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
|
@ -15,10 +15,12 @@
|
||||||
#ifndef IPLATFORMSCREEN_H
|
#ifndef IPLATFORMSCREEN_H
|
||||||
#define IPLATFORMSCREEN_H
|
#define IPLATFORMSCREEN_H
|
||||||
|
|
||||||
|
#include "IScreen.h"
|
||||||
#include "IPrimaryScreen.h"
|
#include "IPrimaryScreen.h"
|
||||||
#include "ISecondaryScreen.h"
|
#include "ISecondaryScreen.h"
|
||||||
#include "ClipboardTypes.h"
|
#include "ClipboardTypes.h"
|
||||||
#include "OptionTypes.h"
|
#include "OptionTypes.h"
|
||||||
|
#include "CEvent.h"
|
||||||
|
|
||||||
class IClipboard;
|
class IClipboard;
|
||||||
class IKeyState;
|
class IKeyState;
|
||||||
|
@ -27,27 +29,60 @@ class IKeyState;
|
||||||
/*!
|
/*!
|
||||||
This interface defines the methods common to all platform dependent
|
This interface defines the methods common to all platform dependent
|
||||||
screen implementations that are used by both primary and secondary
|
screen implementations that are used by both primary and secondary
|
||||||
screens.
|
screens. A platform screen is expected to post the events defined
|
||||||
|
in \c IScreen when appropriate. It should also post events defined
|
||||||
|
in \c IPlatformScreen if acting as the primary screen. The target
|
||||||
|
on the events should be the value returned by \c getEventTarget().
|
||||||
*/
|
*/
|
||||||
class IPlatformScreen : public IPrimaryScreen, public ISecondaryScreen {
|
class IPlatformScreen : public IScreen,
|
||||||
|
public IPrimaryScreen, public ISecondaryScreen {
|
||||||
public:
|
public:
|
||||||
|
//! Key event data
|
||||||
|
class CKeyInfo {
|
||||||
|
public:
|
||||||
|
CKeyInfo(KeyID, KeyModifierMask, KeyButton, SInt32 count);
|
||||||
|
|
||||||
|
public:
|
||||||
|
KeyID m_key;
|
||||||
|
KeyModifierMask m_mask;
|
||||||
|
KeyButton m_button;
|
||||||
|
SInt32 m_count;
|
||||||
|
};
|
||||||
|
//! Button event data
|
||||||
|
class CButtonInfo {
|
||||||
|
public:
|
||||||
|
CButtonInfo(ButtonID);
|
||||||
|
|
||||||
|
public:
|
||||||
|
ButtonID m_button;
|
||||||
|
};
|
||||||
|
//! Motion event data
|
||||||
|
class CMotionInfo {
|
||||||
|
public:
|
||||||
|
CMotionInfo(SInt32 x, SInt32 y);
|
||||||
|
|
||||||
|
public:
|
||||||
|
SInt32 m_x;
|
||||||
|
SInt32 m_y;
|
||||||
|
};
|
||||||
|
//! Wheel motion event data
|
||||||
|
class CWheelInfo {
|
||||||
|
public:
|
||||||
|
CWheelInfo(SInt32);
|
||||||
|
|
||||||
|
public:
|
||||||
|
SInt32 m_wheel;
|
||||||
|
};
|
||||||
|
|
||||||
//! @name manipulators
|
//! @name manipulators
|
||||||
//@{
|
//@{
|
||||||
|
|
||||||
//! Open screen
|
//! Set the key state
|
||||||
/*!
|
/*!
|
||||||
Called to open and initialize the screen. Throw XScreenUnavailable
|
Sets the key state object. This object tracks keyboard state and
|
||||||
if the screen cannot be opened but retrying later may succeed.
|
the screen is expected to keep it up to date.
|
||||||
Otherwise throw some other XScreenOpenFailure exception.
|
|
||||||
*/
|
*/
|
||||||
virtual void open(IKeyState*) = 0;
|
virtual void setKeyState(IKeyState*) = 0;
|
||||||
|
|
||||||
//! Close screen
|
|
||||||
/*!
|
|
||||||
Called to close the screen. close() should quietly ignore calls
|
|
||||||
that don't have a matching successful call to open().
|
|
||||||
*/
|
|
||||||
virtual void close() = 0;
|
|
||||||
|
|
||||||
//! Enable screen
|
//! Enable screen
|
||||||
/*!
|
/*!
|
||||||
|
@ -64,21 +99,6 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual void disable() = 0;
|
virtual void disable() = 0;
|
||||||
|
|
||||||
//! Run event loop
|
|
||||||
/*!
|
|
||||||
Run the event loop and return when exitMainLoop() is called.
|
|
||||||
This must be called between a successful open() and close().
|
|
||||||
*/
|
|
||||||
virtual void mainLoop() = 0;
|
|
||||||
|
|
||||||
//! Exit event loop
|
|
||||||
/*!
|
|
||||||
Force mainLoop() to return. This call can return before
|
|
||||||
mainLoop() does (i.e. asynchronously). This may only be
|
|
||||||
called between a successful open() and close().
|
|
||||||
*/
|
|
||||||
virtual void exitMainLoop() = 0;
|
|
||||||
|
|
||||||
//! Enter screen
|
//! Enter screen
|
||||||
/*!
|
/*!
|
||||||
Called when the user navigates to this screen.
|
Called when the user navigates to this screen.
|
||||||
|
@ -102,22 +122,19 @@ public:
|
||||||
|
|
||||||
//! Check clipboard owner
|
//! Check clipboard owner
|
||||||
/*!
|
/*!
|
||||||
Check ownership of all clipboards and notify an IScreenReceiver (set
|
Check ownership of all clipboards and post grab events for any that
|
||||||
through some other interface) if any changed. This is used as a
|
have changed. This is used as a backup in case the system doesn't
|
||||||
backup in case the system doesn't reliably report clipboard ownership
|
reliably report clipboard ownership changes.
|
||||||
changes.
|
|
||||||
*/
|
*/
|
||||||
virtual void checkClipboards() = 0;
|
virtual void checkClipboards() = 0;
|
||||||
|
|
||||||
//! Open screen saver
|
//! Open screen saver
|
||||||
/*!
|
/*!
|
||||||
Open the screen saver. If \c notify is true then this object must
|
Open the screen saver. If \c notify is true then this object must
|
||||||
call an IScreenEventHandler's (set through some other interface)
|
send events when the screen saver activates or deactivates until
|
||||||
onScreenSaver() when the screensaver activates or deactivates until
|
\c closeScreensaver() is called. If \c notify is false then the
|
||||||
it's closed. If \c notify is false then the screen saver is
|
screen saver is disabled and restored on \c closeScreensaver().
|
||||||
disabled on open and restored on close.
|
|
||||||
*/
|
*/
|
||||||
// XXX -- pass an interface pointer, not a notify flag
|
|
||||||
virtual void openScreensaver(bool notify) = 0;
|
virtual void openScreensaver(bool notify) = 0;
|
||||||
|
|
||||||
//! Close screen saver
|
//! Close screen saver
|
||||||
|
@ -154,6 +171,12 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual void updateKeys() = 0;
|
virtual void updateKeys() = 0;
|
||||||
|
|
||||||
|
//! Set clipboard sequence number
|
||||||
|
/*!
|
||||||
|
Sets the sequence number to use in subsequent clipboard events.
|
||||||
|
*/
|
||||||
|
virtual void setSequenceNumber(UInt32) = 0;
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
//! @name accessors
|
//! @name accessors
|
||||||
//@{
|
//@{
|
||||||
|
@ -164,35 +187,49 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual bool isPrimary() const = 0;
|
virtual bool isPrimary() const = 0;
|
||||||
|
|
||||||
//! Get clipboard
|
//! Get key down event type. Event data is CKeyInfo*, count == 1.
|
||||||
|
static CEvent::Type getKeyDownEvent();
|
||||||
|
//! Get key up event type. Event data is CKeyInfo*, count == 1.
|
||||||
|
static CEvent::Type getKeyUpEvent();
|
||||||
|
//! Get key repeat event type. Event data is CKeyInfo*.
|
||||||
|
static CEvent::Type getKeyRepeatEvent();
|
||||||
|
//! Get button down event type. Event data is CButtonInfo*.
|
||||||
|
static CEvent::Type getButtonDownEvent();
|
||||||
|
//! Get button up event type. Event data is CButtonInfo*.
|
||||||
|
static CEvent::Type getButtonUpEvent();
|
||||||
|
//! Get mouse motion on the primary screen event type
|
||||||
/*!
|
/*!
|
||||||
Save the contents of the clipboard indicated by \c id and return
|
Event data is CMotionInfo* and the values are an absolute position.
|
||||||
true iff successful.
|
|
||||||
*/
|
*/
|
||||||
virtual bool getClipboard(ClipboardID id, IClipboard*) const = 0;
|
static CEvent::Type getMotionOnPrimaryEvent();
|
||||||
|
//! Get mouse motion on a secondary screen event type
|
||||||
//! Get screen shape
|
|
||||||
/*!
|
/*!
|
||||||
Return the position of the upper-left corner of the screen in \c x and
|
Event data is CMotionInfo* and the values are motion deltas not
|
||||||
\c y and the size of the screen in \c w (width) and \c h (height).
|
absolute coordinates.
|
||||||
*/
|
*/
|
||||||
virtual void getShape(SInt32& x, SInt32& y,
|
static CEvent::Type getMotionOnSecondaryEvent();
|
||||||
SInt32& w, SInt32& h) const = 0;
|
//! Get mouse wheel event type. Event data is CWheelInfo*.
|
||||||
|
static CEvent::Type getWheelEvent();
|
||||||
//! Get cursor position
|
//! Get screensaver activated event type
|
||||||
/*!
|
static CEvent::Type getScreensaverActivatedEvent();
|
||||||
Return the current position of the cursor in \c x and \c y.
|
//! Get screensaver deactivated event type
|
||||||
*/
|
static CEvent::Type getScreensaverDeactivatedEvent();
|
||||||
virtual void getCursorPos(SInt32& x, SInt32& y) const = 0;
|
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
|
// IScreen overrides
|
||||||
|
virtual void* getEventTarget() const = 0;
|
||||||
|
virtual bool getClipboard(ClipboardID id, IClipboard*) const = 0;
|
||||||
|
virtual void getShape(SInt32& x, SInt32& y,
|
||||||
|
SInt32& width, SInt32& height) const = 0;
|
||||||
|
virtual void getCursorPos(SInt32& x, SInt32& y) const = 0;
|
||||||
|
|
||||||
// IPrimaryScreen overrides
|
// IPrimaryScreen overrides
|
||||||
virtual void reconfigure(UInt32 activeSides) = 0;
|
virtual void reconfigure(UInt32 activeSides) = 0;
|
||||||
virtual void warpCursor(SInt32 x, SInt32 y) = 0;
|
virtual void warpCursor(SInt32 x, SInt32 y) = 0;
|
||||||
virtual UInt32 addOneShotTimer(double timeout) = 0;
|
|
||||||
virtual SInt32 getJumpZoneSize() const = 0;
|
virtual SInt32 getJumpZoneSize() const = 0;
|
||||||
virtual bool isAnyMouseButtonDown() const = 0;
|
virtual bool isAnyMouseButtonDown() const = 0;
|
||||||
|
virtual void getCursorCenter(SInt32& x, SInt32& y) const = 0;
|
||||||
virtual const char* getKeyName(KeyButton) const = 0;
|
virtual const char* getKeyName(KeyButton) const = 0;
|
||||||
|
|
||||||
// ISecondaryScreen overrides
|
// ISecondaryScreen overrides
|
||||||
|
@ -205,6 +242,18 @@ public:
|
||||||
const IKeyState& keyState, KeyID id,
|
const IKeyState& keyState, KeyID id,
|
||||||
KeyModifierMask desiredMask,
|
KeyModifierMask desiredMask,
|
||||||
bool isAutoRepeat) const = 0;
|
bool isAutoRepeat) const = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static CEvent::Type s_keyDownEvent;
|
||||||
|
static CEvent::Type s_keyUpEvent;
|
||||||
|
static CEvent::Type s_keyRepeatEvent;
|
||||||
|
static CEvent::Type s_buttonDownEvent;
|
||||||
|
static CEvent::Type s_buttonUpEvent;
|
||||||
|
static CEvent::Type s_motionPrimaryEvent;
|
||||||
|
static CEvent::Type s_motionSecondaryEvent;
|
||||||
|
static CEvent::Type s_wheelEvent;
|
||||||
|
static CEvent::Type s_ssActivatedEvent;
|
||||||
|
static CEvent::Type s_ssDeactivatedEvent;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -25,7 +25,6 @@ primary screen implementations.
|
||||||
*/
|
*/
|
||||||
class IPrimaryScreen : public IInterface {
|
class IPrimaryScreen : public IInterface {
|
||||||
public:
|
public:
|
||||||
// XXX -- may need an interface for sending events
|
|
||||||
//! @name manipulators
|
//! @name manipulators
|
||||||
//@{
|
//@{
|
||||||
|
|
||||||
|
@ -46,15 +45,6 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual void warpCursor(SInt32 x, SInt32 y) = 0;
|
virtual void warpCursor(SInt32 x, SInt32 y) = 0;
|
||||||
|
|
||||||
//! Install a one-shot timer
|
|
||||||
/*!
|
|
||||||
Installs a one-shot timer for \c timeout seconds and returns the
|
|
||||||
id of the timer.
|
|
||||||
*/
|
|
||||||
// XXX -- need to specify the receiver of the event. or we should
|
|
||||||
// pass a job. need a method to remove the timer?
|
|
||||||
virtual UInt32 addOneShotTimer(double timeout) = 0;
|
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
//! @name accessors
|
//! @name accessors
|
||||||
//@{
|
//@{
|
||||||
|
@ -72,6 +62,14 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual bool isAnyMouseButtonDown() const = 0;
|
virtual bool isAnyMouseButtonDown() const = 0;
|
||||||
|
|
||||||
|
//! Get cursor center position
|
||||||
|
/*!
|
||||||
|
Return the cursor center position which is where we park the
|
||||||
|
cursor to compute cursor motion deltas and should be far from
|
||||||
|
the edges of the screen, typically the center.
|
||||||
|
*/
|
||||||
|
virtual void getCursorCenter(SInt32& x, SInt32& y) const = 0;
|
||||||
|
|
||||||
//! Get name of key
|
//! Get name of key
|
||||||
/*!
|
/*!
|
||||||
Return a string describing the given key.
|
Return a string describing the given key.
|
||||||
|
|
|
@ -1,73 +0,0 @@
|
||||||
/*
|
|
||||||
* synergy -- mouse and keyboard sharing utility
|
|
||||||
* Copyright (C) 2002 Chris Schoeneman
|
|
||||||
*
|
|
||||||
* This package is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU General Public License
|
|
||||||
* found in the file COPYING that should have accompanied this file.
|
|
||||||
*
|
|
||||||
* This package is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef IPRIMARYSCREENRECEIVER_H
|
|
||||||
#define IPRIMARYSCREENRECEIVER_H
|
|
||||||
|
|
||||||
#include "IInterface.h"
|
|
||||||
#include "KeyTypes.h"
|
|
||||||
#include "MouseTypes.h"
|
|
||||||
|
|
||||||
//! Primary screen event receiver interface
|
|
||||||
/*!
|
|
||||||
The interface for receiving notification of events on the primary
|
|
||||||
screen. The server implements this interface to handle user input.
|
|
||||||
Platform dependent primary screen implementation will need to take
|
|
||||||
an IPrimaryScreenReceiver* and notify it of events.
|
|
||||||
*/
|
|
||||||
class IPrimaryScreenReceiver : public IInterface {
|
|
||||||
public:
|
|
||||||
//! Notify of screen saver change
|
|
||||||
/*!
|
|
||||||
Called when the screensaver is activated or deactivated.
|
|
||||||
*/
|
|
||||||
virtual void onScreensaver(bool activated) = 0;
|
|
||||||
|
|
||||||
//! Notify of one-shot timer expiration
|
|
||||||
/*!
|
|
||||||
Called when a one-shot timer expires.
|
|
||||||
*/
|
|
||||||
virtual void onOneShotTimerExpired(UInt32 id) = 0;
|
|
||||||
|
|
||||||
// call to notify of events. onMouseMovePrimary() returns
|
|
||||||
// true iff the mouse enters a jump zone and jumps.
|
|
||||||
//! Notify of key press
|
|
||||||
virtual void onKeyDown(KeyID, KeyModifierMask, KeyButton) = 0;
|
|
||||||
//! Notify of key release
|
|
||||||
virtual void onKeyUp(KeyID, KeyModifierMask, KeyButton) = 0;
|
|
||||||
//! Notify of key repeat
|
|
||||||
virtual void onKeyRepeat(KeyID, KeyModifierMask,
|
|
||||||
SInt32 count, KeyButton) = 0;
|
|
||||||
//! Notify of mouse button press
|
|
||||||
virtual void onMouseDown(ButtonID) = 0;
|
|
||||||
//! Notify of mouse button release
|
|
||||||
virtual void onMouseUp(ButtonID) = 0;
|
|
||||||
//! Notify of mouse motion
|
|
||||||
/*!
|
|
||||||
Called when the mouse has moved while on the primary screen. \c x
|
|
||||||
and \c y are the absolute screen position of the mouse. Return
|
|
||||||
true iff the mouse enters a jump zone and jumps.
|
|
||||||
*/
|
|
||||||
virtual bool onMouseMovePrimary(SInt32 x, SInt32 y) = 0;
|
|
||||||
//! Notify of mouse motion
|
|
||||||
/*!
|
|
||||||
Called when the mouse has moved while on the secondary screen.
|
|
||||||
\c dx and \c dy are the relative motion from the last position.
|
|
||||||
*/
|
|
||||||
virtual void onMouseMoveSecondary(SInt32 dx, SInt32 dy) = 0;
|
|
||||||
//! Notify of mouse wheen motion
|
|
||||||
virtual void onMouseWheel(SInt32 delta) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2004 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* This package is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* found in the file COPYING that should have accompanied this file.
|
||||||
|
*
|
||||||
|
* This package is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "IScreen.h"
|
||||||
|
|
||||||
|
//
|
||||||
|
// IScreen
|
||||||
|
//
|
||||||
|
|
||||||
|
CEvent::Type IScreen::s_errorEvent = CEvent::kUnknown;
|
||||||
|
CEvent::Type IScreen::s_shapeChangedEvent = CEvent::kUnknown;
|
||||||
|
CEvent::Type IScreen::s_clipboardGrabbedEvent = CEvent::kUnknown;
|
||||||
|
CEvent::Type IScreen::s_clipboardChangedEvent = CEvent::kUnknown;
|
||||||
|
|
||||||
|
CEvent::Type
|
||||||
|
IScreen::getErrorEvent()
|
||||||
|
{
|
||||||
|
return CEvent::registerTypeOnce(s_errorEvent,
|
||||||
|
"IScreen::error");
|
||||||
|
}
|
||||||
|
|
||||||
|
CEvent::Type
|
||||||
|
IScreen::getShapeChangedEvent()
|
||||||
|
{
|
||||||
|
return CEvent::registerTypeOnce(s_shapeChangedEvent,
|
||||||
|
"IScreen::shapeChanged");
|
||||||
|
}
|
||||||
|
|
||||||
|
CEvent::Type
|
||||||
|
IScreen::getClipboardGrabbedEvent()
|
||||||
|
{
|
||||||
|
return CEvent::registerTypeOnce(s_clipboardGrabbedEvent,
|
||||||
|
"IScreen::clipboardGrabbed");
|
||||||
|
}
|
||||||
|
|
||||||
|
CEvent::Type
|
||||||
|
IScreen::getClipboardChangedEvent()
|
||||||
|
{
|
||||||
|
return CEvent::registerTypeOnce(s_clipboardChangedEvent,
|
||||||
|
"IScreen::clipboardChanged");
|
||||||
|
}
|
|
@ -0,0 +1,106 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2003 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* This package is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* found in the file COPYING that should have accompanied this file.
|
||||||
|
*
|
||||||
|
* This package is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ISCREEN_H
|
||||||
|
#define ISCREEN_H
|
||||||
|
|
||||||
|
#include "IInterface.h"
|
||||||
|
#include "ClipboardTypes.h"
|
||||||
|
#include "CEvent.h"
|
||||||
|
|
||||||
|
class IClipboard;
|
||||||
|
|
||||||
|
//! Screen interface
|
||||||
|
/*!
|
||||||
|
This interface defines the methods common to all screens.
|
||||||
|
*/
|
||||||
|
class IScreen : public IInterface {
|
||||||
|
public:
|
||||||
|
struct CClipboardInfo {
|
||||||
|
public:
|
||||||
|
ClipboardID m_id;
|
||||||
|
UInt32 m_sequenceNumber;
|
||||||
|
};
|
||||||
|
|
||||||
|
//! @name accessors
|
||||||
|
//@{
|
||||||
|
|
||||||
|
//! Get event target
|
||||||
|
/*!
|
||||||
|
Returns the target used for events created by this object.
|
||||||
|
*/
|
||||||
|
virtual void* getEventTarget() const = 0;
|
||||||
|
|
||||||
|
//! Get clipboard
|
||||||
|
/*!
|
||||||
|
Save the contents of the clipboard indicated by \c id and return
|
||||||
|
true iff successful.
|
||||||
|
*/
|
||||||
|
virtual bool getClipboard(ClipboardID id, IClipboard*) const = 0;
|
||||||
|
|
||||||
|
//! Get screen shape
|
||||||
|
/*!
|
||||||
|
Return the position of the upper-left corner of the screen in \c x and
|
||||||
|
\c y and the size of the screen in \c width and \c height.
|
||||||
|
*/
|
||||||
|
virtual void getShape(SInt32& x, SInt32& y,
|
||||||
|
SInt32& width, SInt32& height) const = 0;
|
||||||
|
|
||||||
|
//! Get cursor position
|
||||||
|
/*!
|
||||||
|
Return the current position of the cursor in \c x and \c y.
|
||||||
|
*/
|
||||||
|
virtual void getCursorPos(SInt32& x, SInt32& y) const = 0;
|
||||||
|
|
||||||
|
//! Get error event type
|
||||||
|
/*!
|
||||||
|
Returns the error event type. This is sent whenever the screen has
|
||||||
|
failed for some reason (e.g. the X Windows server died).
|
||||||
|
*/
|
||||||
|
static CEvent::Type getErrorEvent();
|
||||||
|
|
||||||
|
//! Get shape changed event type
|
||||||
|
/*!
|
||||||
|
Returns the shape changed event type. This is sent whenever the
|
||||||
|
screen's shape changes, the cursor center moves, or the jump zone
|
||||||
|
size changes.
|
||||||
|
*/
|
||||||
|
static CEvent::Type getShapeChangedEvent();
|
||||||
|
|
||||||
|
//! Get clipboard grabbed event type
|
||||||
|
/*!
|
||||||
|
Returns the clipboard grabbed event type. This is sent whenever the
|
||||||
|
clipboard is grabbed by some other application so we don't own it
|
||||||
|
anymore. The data is a pointer to a CClipboardInfo.
|
||||||
|
*/
|
||||||
|
static CEvent::Type getClipboardGrabbedEvent();
|
||||||
|
|
||||||
|
//! Get clipboard changed event type
|
||||||
|
/*!
|
||||||
|
Returns the clipboard changed event type. This is sent whenever the
|
||||||
|
contents of the clipboard has changed. The data is a pointer to a
|
||||||
|
CClipboardInfo.
|
||||||
|
*/
|
||||||
|
static CEvent::Type getClipboardChangedEvent();
|
||||||
|
|
||||||
|
//@}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static CEvent::Type s_errorEvent;
|
||||||
|
static CEvent::Type s_shapeChangedEvent;
|
||||||
|
static CEvent::Type s_clipboardGrabbedEvent;
|
||||||
|
static CEvent::Type s_clipboardChangedEvent;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,41 +0,0 @@
|
||||||
/*
|
|
||||||
* synergy -- mouse and keyboard sharing utility
|
|
||||||
* Copyright (C) 2003 Chris Schoeneman
|
|
||||||
*
|
|
||||||
* This package is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU General Public License
|
|
||||||
* found in the file COPYING that should have accompanied this file.
|
|
||||||
*
|
|
||||||
* This package is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef ISCREENFACTORY_H
|
|
||||||
#define ISCREENFACTORY_H
|
|
||||||
|
|
||||||
#include "IInterface.h"
|
|
||||||
|
|
||||||
class IPrimaryScreenReceiver;
|
|
||||||
class IPlatformScreen;
|
|
||||||
class IScreenReceiver;
|
|
||||||
|
|
||||||
//! Primary screen factory interface
|
|
||||||
/*!
|
|
||||||
This interface provides factory methods to create primary and
|
|
||||||
secondary screens.
|
|
||||||
*/
|
|
||||||
class IScreenFactory : public IInterface {
|
|
||||||
public:
|
|
||||||
//! Create screen
|
|
||||||
/*!
|
|
||||||
Create and return a screen. The caller must delete the returned
|
|
||||||
object. The screen is a primary screen iff the IPrimaryScreenReceiver
|
|
||||||
is not NULL.
|
|
||||||
*/
|
|
||||||
virtual IPlatformScreen*
|
|
||||||
create(IScreenReceiver*, IPrimaryScreenReceiver*) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,65 +0,0 @@
|
||||||
/*
|
|
||||||
* synergy -- mouse and keyboard sharing utility
|
|
||||||
* Copyright (C) 2002 Chris Schoeneman
|
|
||||||
*
|
|
||||||
* This package is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU General Public License
|
|
||||||
* found in the file COPYING that should have accompanied this file.
|
|
||||||
*
|
|
||||||
* This package is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef ISCREENRECEIVER_H
|
|
||||||
#define ISCREENRECEIVER_H
|
|
||||||
|
|
||||||
#include "IInterface.h"
|
|
||||||
#include "ClipboardTypes.h"
|
|
||||||
#include "ProtocolTypes.h"
|
|
||||||
#include "CString.h"
|
|
||||||
|
|
||||||
//! Screen event receiver interface
|
|
||||||
/*!
|
|
||||||
This interface defines the methods common to most types that receive
|
|
||||||
events for changes to a screen. Note that the methods in this
|
|
||||||
interface are similar to the methods in IServer but have different
|
|
||||||
parameters. This interface is suitable for client-side types.
|
|
||||||
*/
|
|
||||||
class IScreenReceiver : public IInterface {
|
|
||||||
public:
|
|
||||||
//! Notify of error
|
|
||||||
/*!
|
|
||||||
Called when the screen is unexpectedly closing. This implies that
|
|
||||||
the screen is no longer usable and that the program should close
|
|
||||||
the screen and probably terminate.
|
|
||||||
*/
|
|
||||||
virtual void onError() = 0;
|
|
||||||
|
|
||||||
//! Notify of client screen change
|
|
||||||
/*!
|
|
||||||
Called when the client's info has changed. For example, when the
|
|
||||||
screen resolution has changed.
|
|
||||||
*/
|
|
||||||
virtual void onInfoChanged(const CClientInfo&) = 0;
|
|
||||||
|
|
||||||
//! Notify of clipboad grab
|
|
||||||
/*!
|
|
||||||
Called when the clipboard was grabbed by another program and,
|
|
||||||
therefore, we no longer own it. Returns true if the grab was
|
|
||||||
honored, false otherwise.
|
|
||||||
*/
|
|
||||||
virtual bool onGrabClipboard(ClipboardID) = 0;
|
|
||||||
|
|
||||||
//! Notify of new clipboard data
|
|
||||||
/*!
|
|
||||||
Called when the data on the clipboard has changed because some
|
|
||||||
other program has changed it. \c data will have marshalled
|
|
||||||
clipboard data.
|
|
||||||
*/
|
|
||||||
virtual void onClipboardChanged(ClipboardID,
|
|
||||||
const CString& data) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -16,6 +16,7 @@
|
||||||
#define ISCREENSAVER_H
|
#define ISCREENSAVER_H
|
||||||
|
|
||||||
#include "IInterface.h"
|
#include "IInterface.h"
|
||||||
|
#include "CEvent.h"
|
||||||
|
|
||||||
//! Screen saver interface
|
//! Screen saver interface
|
||||||
/*!
|
/*!
|
||||||
|
|
|
@ -1,75 +0,0 @@
|
||||||
/*
|
|
||||||
* synergy -- mouse and keyboard sharing utility
|
|
||||||
* Copyright (C) 2002 Chris Schoeneman
|
|
||||||
*
|
|
||||||
* This package is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU General Public License
|
|
||||||
* found in the file COPYING that should have accompanied this file.
|
|
||||||
*
|
|
||||||
* This package is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef ISERVER_H
|
|
||||||
#define ISERVER_H
|
|
||||||
|
|
||||||
#include "IInterface.h"
|
|
||||||
#include "ClipboardTypes.h"
|
|
||||||
#include "CString.h"
|
|
||||||
|
|
||||||
class CClientInfo;
|
|
||||||
|
|
||||||
//! Server interface
|
|
||||||
/*!
|
|
||||||
This interface defines the methods necessary for clients to
|
|
||||||
communicate with the server. Note that the methods in this
|
|
||||||
interface are similar to the methods in IScreenReceiver but
|
|
||||||
include extra parameters. This interface is suitable for
|
|
||||||
server-side client proxies. Client-side objects should use
|
|
||||||
the IScreenReceiver interface since the extra parameters are
|
|
||||||
meaningless on the client-side.
|
|
||||||
*/
|
|
||||||
class IServer : public IInterface {
|
|
||||||
public:
|
|
||||||
//! @name manipulators
|
|
||||||
//@{
|
|
||||||
|
|
||||||
//! Notify of error
|
|
||||||
/*!
|
|
||||||
Called when the screen is unexpectedly closing. This implies that
|
|
||||||
the screen is no longer usable and that the program should close
|
|
||||||
the screen and probably terminate.
|
|
||||||
*/
|
|
||||||
virtual void onError() = 0;
|
|
||||||
|
|
||||||
//! Notify of client screen change
|
|
||||||
/*!
|
|
||||||
Called when the client's info has changed.
|
|
||||||
*/
|
|
||||||
virtual void onInfoChanged(const CString& clientName,
|
|
||||||
const CClientInfo&) = 0;
|
|
||||||
|
|
||||||
//! Notify of clipboad grab
|
|
||||||
/*!
|
|
||||||
Called when the clipboard was grabbed by another program and,
|
|
||||||
therefore, we no longer own it. Returns true if the grab was
|
|
||||||
honored, false otherwise.
|
|
||||||
*/
|
|
||||||
virtual bool onGrabClipboard(const CString& clientName,
|
|
||||||
ClipboardID, UInt32 seqNum) = 0;
|
|
||||||
|
|
||||||
//! Notify of new clipboard data
|
|
||||||
/*!
|
|
||||||
Called when the data on the clipboard has changed because some
|
|
||||||
other program has changed it. \c data has the marshalled clipboard
|
|
||||||
data.
|
|
||||||
*/
|
|
||||||
virtual void onClipboardChanged(ClipboardID,
|
|
||||||
UInt32 seqNum, const CString& data) = 0;
|
|
||||||
|
|
||||||
//@}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -29,6 +29,8 @@ libsynergy_a_SOURCES = \
|
||||||
CPacketStreamFilter.cpp \
|
CPacketStreamFilter.cpp \
|
||||||
CProtocolUtil.cpp \
|
CProtocolUtil.cpp \
|
||||||
CScreen.cpp \
|
CScreen.cpp \
|
||||||
|
IPlatformScreen.cpp \
|
||||||
|
IScreen.cpp \
|
||||||
XScreen.cpp \
|
XScreen.cpp \
|
||||||
XSynergy.cpp \
|
XSynergy.cpp \
|
||||||
CClipboard.h \
|
CClipboard.h \
|
||||||
|
@ -41,12 +43,9 @@ libsynergy_a_SOURCES = \
|
||||||
IKeyState.h \
|
IKeyState.h \
|
||||||
IPlatformScreen.h \
|
IPlatformScreen.h \
|
||||||
IPrimaryScreen.h \
|
IPrimaryScreen.h \
|
||||||
IPrimaryScreenReceiver.h \
|
IScreen.h \
|
||||||
IScreenFactory.h \
|
|
||||||
IScreenReceiver.h \
|
|
||||||
IScreenSaver.h \
|
IScreenSaver.h \
|
||||||
ISecondaryScreen.h \
|
ISecondaryScreen.h \
|
||||||
IServer.h \
|
|
||||||
KeyTypes.h \
|
KeyTypes.h \
|
||||||
MouseTypes.h \
|
MouseTypes.h \
|
||||||
OptionTypes.h \
|
OptionTypes.h \
|
||||||
|
|
Loading…
Reference in New Issue