Initial commit of the synergy trunk sources from sf.net

This commit is contained in:
Sorin Sbarnea
2009-02-27 11:54:59 +00:00
commit 958fa80d1d
429 changed files with 96848 additions and 0 deletions

662
lib/client/CClient.cpp Normal file
View File

@@ -0,0 +1,662 @@
/*
* 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.
*/
#include "CClient.h"
#include "CServerProxy.h"
#include "CScreen.h"
#include "CClipboard.h"
#include "CPacketStreamFilter.h"
#include "CProtocolUtil.h"
#include "ProtocolTypes.h"
#include "XSynergy.h"
#include "IDataSocket.h"
#include "ISocketFactory.h"
#include "IStreamFilterFactory.h"
#include "CLog.h"
#include "IEventQueue.h"
#include "TMethodEventJob.h"
//
// CClient
//
CEvent::Type CClient::s_connectedEvent = CEvent::kUnknown;
CEvent::Type CClient::s_connectionFailedEvent = CEvent::kUnknown;
CEvent::Type CClient::s_disconnectedEvent = CEvent::kUnknown;
CClient::CClient(const CString& name, const CNetworkAddress& address,
ISocketFactory* socketFactory,
IStreamFilterFactory* streamFilterFactory,
CScreen* screen) :
m_name(name),
m_serverAddress(address),
m_socketFactory(socketFactory),
m_streamFilterFactory(streamFilterFactory),
m_screen(screen),
m_stream(NULL),
m_timer(NULL),
m_server(NULL),
m_ready(false),
m_active(false),
m_suspended(false),
m_connectOnResume(false)
{
assert(m_socketFactory != NULL);
assert(m_screen != NULL);
// register suspend/resume event handlers
EVENTQUEUE->adoptHandler(IScreen::getSuspendEvent(),
getEventTarget(),
new TMethodEventJob<CClient>(this,
&CClient::handleSuspend));
EVENTQUEUE->adoptHandler(IScreen::getResumeEvent(),
getEventTarget(),
new TMethodEventJob<CClient>(this,
&CClient::handleResume));
}
CClient::~CClient()
{
EVENTQUEUE->removeHandler(IScreen::getSuspendEvent(),
getEventTarget());
EVENTQUEUE->removeHandler(IScreen::getResumeEvent(),
getEventTarget());
cleanupTimer();
cleanupScreen();
cleanupConnecting();
cleanupConnection();
delete m_socketFactory;
delete m_streamFilterFactory;
}
void
CClient::connect()
{
if (m_stream != NULL) {
return;
}
if (m_suspended) {
m_connectOnResume = true;
return;
}
try {
// resolve the server hostname. do this every time we connect
// in case we couldn't resolve the address earlier or the address
// has changed (which can happen frequently if this is a laptop
// being shuttled between various networks). patch by Brent
// Priddy.
m_serverAddress.resolve();
// create the socket
IDataSocket* socket = m_socketFactory->create();
// filter socket messages, including a packetizing filter
m_stream = socket;
if (m_streamFilterFactory != NULL) {
m_stream = m_streamFilterFactory->create(m_stream, true);
}
m_stream = new CPacketStreamFilter(m_stream, true);
// connect
LOG((CLOG_DEBUG1 "connecting to server"));
setupConnecting();
setupTimer();
socket->connect(m_serverAddress);
}
catch (XBase& e) {
cleanupTimer();
cleanupConnecting();
delete m_stream;
m_stream = NULL;
LOG((CLOG_DEBUG1 "connection failed"));
sendConnectionFailedEvent(e.what());
return;
}
}
void
CClient::disconnect(const char* msg)
{
m_connectOnResume = false;
cleanupTimer();
cleanupScreen();
cleanupConnecting();
cleanupConnection();
if (msg != NULL) {
sendConnectionFailedEvent(msg);
}
else {
sendEvent(getDisconnectedEvent(), NULL);
}
}
void
CClient::handshakeComplete()
{
m_ready = true;
m_screen->enable();
sendEvent(getConnectedEvent(), NULL);
}
bool
CClient::isConnected() const
{
return (m_server != NULL);
}
bool
CClient::isConnecting() const
{
return (m_timer != NULL);
}
CNetworkAddress
CClient::getServerAddress() const
{
return m_serverAddress;
}
CEvent::Type
CClient::getConnectedEvent()
{
return CEvent::registerTypeOnce(s_connectedEvent,
"CClient::connected");
}
CEvent::Type
CClient::getConnectionFailedEvent()
{
return CEvent::registerTypeOnce(s_connectionFailedEvent,
"CClient::failed");
}
CEvent::Type
CClient::getDisconnectedEvent()
{
return CEvent::registerTypeOnce(s_disconnectedEvent,
"CClient::disconnected");
}
void*
CClient::getEventTarget() const
{
return m_screen->getEventTarget();
}
bool
CClient::getClipboard(ClipboardID id, IClipboard* clipboard) const
{
return m_screen->getClipboard(id, clipboard);
}
void
CClient::getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) const
{
m_screen->getShape(x, y, w, h);
}
void
CClient::getCursorPos(SInt32& x, SInt32& y) const
{
m_screen->getCursorPos(x, y);
}
void
CClient::enter(SInt32 xAbs, SInt32 yAbs, UInt32, KeyModifierMask mask, bool)
{
m_active = true;
m_screen->mouseMove(xAbs, yAbs);
m_screen->enter(mask);
}
bool
CClient::leave()
{
m_screen->leave();
m_active = false;
// send clipboards that we own and that have changed
for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
if (m_ownClipboard[id]) {
sendClipboard(id);
}
}
return true;
}
void
CClient::setClipboard(ClipboardID id, const IClipboard* clipboard)
{
m_screen->setClipboard(id, clipboard);
m_ownClipboard[id] = false;
m_sentClipboard[id] = false;
}
void
CClient::grabClipboard(ClipboardID id)
{
m_screen->grabClipboard(id);
m_ownClipboard[id] = false;
m_sentClipboard[id] = false;
}
void
CClient::setClipboardDirty(ClipboardID, bool)
{
assert(0 && "shouldn't be called");
}
void
CClient::keyDown(KeyID id, KeyModifierMask mask, KeyButton button)
{
m_screen->keyDown(id, mask, button);
}
void
CClient::keyRepeat(KeyID id, KeyModifierMask mask,
SInt32 count, KeyButton button)
{
m_screen->keyRepeat(id, mask, count, button);
}
void
CClient::keyUp(KeyID id, KeyModifierMask mask, KeyButton button)
{
m_screen->keyUp(id, mask, button);
}
void
CClient::mouseDown(ButtonID id)
{
m_screen->mouseDown(id);
}
void
CClient::mouseUp(ButtonID id)
{
m_screen->mouseUp(id);
}
void
CClient::mouseMove(SInt32 x, SInt32 y)
{
m_screen->mouseMove(x, y);
}
void
CClient::mouseRelativeMove(SInt32 dx, SInt32 dy)
{
m_screen->mouseRelativeMove(dx, dy);
}
void
CClient::mouseWheel(SInt32 xDelta, SInt32 yDelta)
{
m_screen->mouseWheel(xDelta, yDelta);
}
void
CClient::screensaver(bool activate)
{
m_screen->screensaver(activate);
}
void
CClient::resetOptions()
{
m_screen->resetOptions();
}
void
CClient::setOptions(const COptionsList& options)
{
m_screen->setOptions(options);
}
CString
CClient::getName() const
{
return m_name;
}
void
CClient::sendClipboard(ClipboardID id)
{
// note -- m_mutex must be locked on entry
assert(m_screen != NULL);
assert(m_server != NULL);
// get clipboard data. set the clipboard time to the last
// clipboard time before getting the data from the screen
// as the screen may detect an unchanged clipboard and
// avoid copying the data.
CClipboard clipboard;
if (clipboard.open(m_timeClipboard[id])) {
clipboard.close();
}
m_screen->getClipboard(id, &clipboard);
// check time
if (m_timeClipboard[id] == 0 ||
clipboard.getTime() != m_timeClipboard[id]) {
// save new time
m_timeClipboard[id] = clipboard.getTime();
// marshall the data
CString data = clipboard.marshall();
// save and send data if different or not yet sent
if (!m_sentClipboard[id] || data != m_dataClipboard[id]) {
m_sentClipboard[id] = true;
m_dataClipboard[id] = data;
m_server->onClipboardChanged(id, &clipboard);
}
}
}
void
CClient::sendEvent(CEvent::Type type, void* data)
{
EVENTQUEUE->addEvent(CEvent(type, getEventTarget(), data));
}
void
CClient::sendConnectionFailedEvent(const char* msg)
{
CFailInfo* info = (CFailInfo*)malloc(sizeof(CFailInfo) + strlen(msg));
info->m_retry = true;
strcpy(info->m_what, msg);
sendEvent(getConnectionFailedEvent(), info);
}
void
CClient::setupConnecting()
{
assert(m_stream != NULL);
EVENTQUEUE->adoptHandler(IDataSocket::getConnectedEvent(),
m_stream->getEventTarget(),
new TMethodEventJob<CClient>(this,
&CClient::handleConnected));
EVENTQUEUE->adoptHandler(IDataSocket::getConnectionFailedEvent(),
m_stream->getEventTarget(),
new TMethodEventJob<CClient>(this,
&CClient::handleConnectionFailed));
}
void
CClient::setupConnection()
{
assert(m_stream != NULL);
EVENTQUEUE->adoptHandler(ISocket::getDisconnectedEvent(),
m_stream->getEventTarget(),
new TMethodEventJob<CClient>(this,
&CClient::handleDisconnected));
EVENTQUEUE->adoptHandler(IStream::getInputReadyEvent(),
m_stream->getEventTarget(),
new TMethodEventJob<CClient>(this,
&CClient::handleHello));
EVENTQUEUE->adoptHandler(IStream::getOutputErrorEvent(),
m_stream->getEventTarget(),
new TMethodEventJob<CClient>(this,
&CClient::handleOutputError));
EVENTQUEUE->adoptHandler(IStream::getInputShutdownEvent(),
m_stream->getEventTarget(),
new TMethodEventJob<CClient>(this,
&CClient::handleDisconnected));
EVENTQUEUE->adoptHandler(IStream::getOutputShutdownEvent(),
m_stream->getEventTarget(),
new TMethodEventJob<CClient>(this,
&CClient::handleDisconnected));
}
void
CClient::setupScreen()
{
assert(m_server == NULL);
m_ready = false;
m_server = new CServerProxy(this, m_stream);
EVENTQUEUE->adoptHandler(IScreen::getShapeChangedEvent(),
getEventTarget(),
new TMethodEventJob<CClient>(this,
&CClient::handleShapeChanged));
EVENTQUEUE->adoptHandler(IScreen::getClipboardGrabbedEvent(),
getEventTarget(),
new TMethodEventJob<CClient>(this,
&CClient::handleClipboardGrabbed));
}
void
CClient::setupTimer()
{
assert(m_timer == NULL);
m_timer = EVENTQUEUE->newOneShotTimer(15.0, NULL);
EVENTQUEUE->adoptHandler(CEvent::kTimer, m_timer,
new TMethodEventJob<CClient>(this,
&CClient::handleConnectTimeout));
}
void
CClient::cleanupConnecting()
{
if (m_stream != NULL) {
EVENTQUEUE->removeHandler(IDataSocket::getConnectedEvent(),
m_stream->getEventTarget());
EVENTQUEUE->removeHandler(IDataSocket::getConnectionFailedEvent(),
m_stream->getEventTarget());
}
}
void
CClient::cleanupConnection()
{
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());
EVENTQUEUE->removeHandler(ISocket::getDisconnectedEvent(),
m_stream->getEventTarget());
delete m_stream;
m_stream = NULL;
}
}
void
CClient::cleanupScreen()
{
if (m_server != NULL) {
if (m_ready) {
m_screen->disable();
m_ready = false;
}
EVENTQUEUE->removeHandler(IScreen::getShapeChangedEvent(),
getEventTarget());
EVENTQUEUE->removeHandler(IScreen::getClipboardGrabbedEvent(),
getEventTarget());
delete m_server;
m_server = NULL;
}
}
void
CClient::cleanupTimer()
{
if (m_timer != NULL) {
EVENTQUEUE->removeHandler(CEvent::kTimer, m_timer);
EVENTQUEUE->deleteTimer(m_timer);
m_timer = NULL;
}
}
void
CClient::handleConnected(const CEvent&, void*)
{
LOG((CLOG_DEBUG1 "connected; wait for hello"));
cleanupConnecting();
setupConnection();
// reset clipboard state
for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
m_ownClipboard[id] = false;
m_sentClipboard[id] = false;
m_timeClipboard[id] = 0;
}
}
void
CClient::handleConnectionFailed(const CEvent& event, void*)
{
IDataSocket::CConnectionFailedInfo* info =
reinterpret_cast<IDataSocket::CConnectionFailedInfo*>(event.getData());
cleanupTimer();
cleanupConnecting();
delete m_stream;
m_stream = NULL;
LOG((CLOG_DEBUG1 "connection failed"));
sendConnectionFailedEvent(info->m_what);
}
void
CClient::handleConnectTimeout(const CEvent&, void*)
{
cleanupTimer();
cleanupConnecting();
cleanupConnection();
delete m_stream;
m_stream = NULL;
LOG((CLOG_DEBUG1 "connection timed out"));
sendConnectionFailedEvent("Timed out");
}
void
CClient::handleOutputError(const CEvent&, void*)
{
cleanupTimer();
cleanupScreen();
cleanupConnection();
LOG((CLOG_WARN "error sending to server"));
sendEvent(getDisconnectedEvent(), NULL);
}
void
CClient::handleDisconnected(const CEvent&, void*)
{
cleanupTimer();
cleanupScreen();
cleanupConnection();
LOG((CLOG_DEBUG1 "disconnected"));
sendEvent(getDisconnectedEvent(), NULL);
}
void
CClient::handleShapeChanged(const CEvent&, void*)
{
LOG((CLOG_DEBUG "resolution changed"));
m_server->onInfoChanged();
}
void
CClient::handleClipboardGrabbed(const CEvent& event, void*)
{
const IScreen::CClipboardInfo* info =
reinterpret_cast<const IScreen::CClipboardInfo*>(event.getData());
// grab ownership
m_server->onGrabClipboard(info->m_id);
// we now own the clipboard and it has not been sent to the server
m_ownClipboard[info->m_id] = true;
m_sentClipboard[info->m_id] = false;
m_timeClipboard[info->m_id] = 0;
// if we're not the active screen then send the clipboard now,
// otherwise we'll wait until we leave.
if (!m_active) {
sendClipboard(info->m_id);
}
}
void
CClient::handleHello(const CEvent&, void*)
{
SInt16 major, minor;
if (!CProtocolUtil::readf(m_stream, kMsgHello, &major, &minor)) {
sendConnectionFailedEvent("Protocol error from server");
cleanupTimer();
cleanupConnection();
return;
}
// check versions
LOG((CLOG_DEBUG1 "got hello version %d.%d", major, minor));
if (major < kProtocolMajorVersion ||
(major == kProtocolMajorVersion && minor < kProtocolMinorVersion)) {
sendConnectionFailedEvent(XIncompatibleClient(major, minor).what());
cleanupTimer();
cleanupConnection();
return;
}
// say hello back
LOG((CLOG_DEBUG1 "say hello version %d.%d", kProtocolMajorVersion, kProtocolMinorVersion));
CProtocolUtil::writef(m_stream, kMsgHelloBack,
kProtocolMajorVersion,
kProtocolMinorVersion, &m_name);
// now connected but waiting to complete handshake
setupScreen();
cleanupTimer();
// make sure we process any remaining messages later. we won't
// receive another event for already pending messages so we fake
// one.
if (m_stream->isReady()) {
EVENTQUEUE->addEvent(CEvent(IStream::getInputReadyEvent(),
m_stream->getEventTarget()));
}
}
void
CClient::handleSuspend(const CEvent&, void*)
{
LOG((CLOG_INFO "suspend"));
m_suspended = true;
bool wasConnected = isConnected();
disconnect(NULL);
m_connectOnResume = wasConnected;
}
void
CClient::handleResume(const CEvent&, void*)
{
LOG((CLOG_INFO "resume"));
m_suspended = false;
if (m_connectOnResume) {
m_connectOnResume = false;
connect();
}
}

198
lib/client/CClient.h Normal file
View File

@@ -0,0 +1,198 @@
/*
* 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 CCLIENT_H
#define CCLIENT_H
#include "IClient.h"
#include "IClipboard.h"
#include "CNetworkAddress.h"
class CEventQueueTimer;
class CScreen;
class CServerProxy;
class IDataSocket;
class ISocketFactory;
class IStream;
class IStreamFilterFactory;
//! Synergy client
/*!
This class implements the top-level client algorithms for synergy.
*/
class CClient : public IClient {
public:
class CFailInfo {
public:
bool m_retry;
char m_what[1];
};
/*!
This client will attempt to connect to the server using \p name
as its name and \p address as the server's address and \p factory
to create the socket. \p screen is the local screen.
*/
CClient(const CString& name, const CNetworkAddress& address,
ISocketFactory* socketFactory,
IStreamFilterFactory* streamFilterFactory,
CScreen* screen);
~CClient();
//! @name manipulators
//@{
//! Connect to server
/*!
Starts an attempt to connect to the server. This is ignored if
the client is trying to connect or is already connected.
*/
void connect();
//! Disconnect
/*!
Disconnects from the server with an optional error message.
*/
void disconnect(const char* msg);
//! Notify of handshake complete
/*!
Notifies the client that the connection handshake has completed.
*/
void handshakeComplete();
//@}
//! @name accessors
//@{
//! Test if connected
/*!
Returns true iff the client is successfully connected to the server.
*/
bool isConnected() const;
//! Test if connecting
/*!
Returns true iff the client is currently attempting to connect to
the server.
*/
bool isConnecting() const;
//! Get address of server
/*!
Returns the address of the server the client is connected (or wants
to connect) to.
*/
CNetworkAddress getServerAddress() const;
//! Get connected event type
/*!
Returns the connected event type. This is sent when the client has
successfully connected to the server.
*/
static CEvent::Type getConnectedEvent();
//! Get connection failed event type
/*!
Returns the connection failed event type. This is sent when the
server fails for some reason. The event data is a CFailInfo*.
*/
static CEvent::Type getConnectionFailedEvent();
//! Get disconnected event type
/*!
Returns the disconnected event type. This is sent when the client
has disconnected from the server (and only after having successfully
connected).
*/
static CEvent::Type getDisconnectedEvent();
//@}
// 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;
// IClient overrides
virtual void enter(SInt32 xAbs, SInt32 yAbs,
UInt32 seqNum, KeyModifierMask mask,
bool forScreensaver);
virtual bool leave();
virtual void setClipboard(ClipboardID, const IClipboard*);
virtual void grabClipboard(ClipboardID);
virtual void setClipboardDirty(ClipboardID, bool);
virtual void keyDown(KeyID, KeyModifierMask, KeyButton);
virtual void keyRepeat(KeyID, KeyModifierMask,
SInt32 count, KeyButton);
virtual void keyUp(KeyID, KeyModifierMask, KeyButton);
virtual void mouseDown(ButtonID);
virtual void mouseUp(ButtonID);
virtual void mouseMove(SInt32 xAbs, SInt32 yAbs);
virtual void mouseRelativeMove(SInt32 xRel, SInt32 yRel);
virtual void mouseWheel(SInt32 xDelta, SInt32 yDelta);
virtual void screensaver(bool activate);
virtual void resetOptions();
virtual void setOptions(const COptionsList& options);
virtual CString getName() const;
private:
void sendClipboard(ClipboardID);
void sendEvent(CEvent::Type, void*);
void sendConnectionFailedEvent(const char* msg);
void setupConnecting();
void setupConnection();
void setupScreen();
void setupTimer();
void cleanupConnecting();
void cleanupConnection();
void cleanupScreen();
void cleanupTimer();
void handleConnected(const CEvent&, void*);
void handleConnectionFailed(const CEvent&, void*);
void handleConnectTimeout(const CEvent&, void*);
void handleOutputError(const CEvent&, void*);
void handleDisconnected(const CEvent&, void*);
void handleShapeChanged(const CEvent&, void*);
void handleClipboardGrabbed(const CEvent&, void*);
void handleHello(const CEvent&, void*);
void handleSuspend(const CEvent& event, void*);
void handleResume(const CEvent& event, void*);
private:
CString m_name;
CNetworkAddress m_serverAddress;
ISocketFactory* m_socketFactory;
IStreamFilterFactory* m_streamFilterFactory;
CScreen* m_screen;
IStream* m_stream;
CEventQueueTimer* m_timer;
CServerProxy* m_server;
bool m_ready;
bool m_active;
bool m_suspended;
bool m_connectOnResume;
bool m_ownClipboard[kClipboardEnd];
bool m_sentClipboard[kClipboardEnd];
IClipboard::Time m_timeClipboard[kClipboardEnd];
CString m_dataClipboard[kClipboardEnd];
static CEvent::Type s_connectedEvent;
static CEvent::Type s_connectionFailedEvent;
static CEvent::Type s_disconnectedEvent;
};
#endif

816
lib/client/CServerProxy.cpp Normal file
View File

@@ -0,0 +1,816 @@
/*
* 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.
*/
#include "CServerProxy.h"
#include "CClient.h"
#include "CClipboard.h"
#include "CProtocolUtil.h"
#include "OptionTypes.h"
#include "ProtocolTypes.h"
#include "IStream.h"
#include "CLog.h"
#include "IEventQueue.h"
#include "TMethodEventJob.h"
#include "XBase.h"
#include <memory>
//
// CServerProxy
//
CServerProxy::CServerProxy(CClient* client, IStream* stream) :
m_client(client),
m_stream(stream),
m_seqNum(0),
m_compressMouse(false),
m_compressMouseRelative(false),
m_xMouse(0),
m_yMouse(0),
m_dxMouse(0),
m_dyMouse(0),
m_ignoreMouse(false),
m_keepAliveAlarm(0.0),
m_keepAliveAlarmTimer(NULL),
m_parser(&CServerProxy::parseHandshakeMessage)
{
assert(m_client != NULL);
assert(m_stream != NULL);
// initialize modifier translation table
for (KeyModifierID id = 0; id < kKeyModifierIDLast; ++id)
m_modifierTranslationTable[id] = id;
// handle data on stream
EVENTQUEUE->adoptHandler(IStream::getInputReadyEvent(),
m_stream->getEventTarget(),
new TMethodEventJob<CServerProxy>(this,
&CServerProxy::handleData));
// send heartbeat
setKeepAliveRate(kKeepAliveRate);
}
CServerProxy::~CServerProxy()
{
setKeepAliveRate(-1.0);
EVENTQUEUE->removeHandler(IStream::getInputReadyEvent(),
m_stream->getEventTarget());
}
void
CServerProxy::resetKeepAliveAlarm()
{
if (m_keepAliveAlarmTimer != NULL) {
EVENTQUEUE->removeHandler(CEvent::kTimer, m_keepAliveAlarmTimer);
EVENTQUEUE->deleteTimer(m_keepAliveAlarmTimer);
m_keepAliveAlarmTimer = NULL;
}
if (m_keepAliveAlarm > 0.0) {
m_keepAliveAlarmTimer =
EVENTQUEUE->newOneShotTimer(m_keepAliveAlarm, NULL);
EVENTQUEUE->adoptHandler(CEvent::kTimer, m_keepAliveAlarmTimer,
new TMethodEventJob<CServerProxy>(this,
&CServerProxy::handleKeepAliveAlarm));
}
}
void
CServerProxy::setKeepAliveRate(double rate)
{
m_keepAliveAlarm = rate * kKeepAlivesUntilDeath;
resetKeepAliveAlarm();
}
void
CServerProxy::handleData(const CEvent&, void*)
{
// handle messages until there are no more. first read message code.
UInt8 code[4];
UInt32 n = m_stream->read(code, 4);
while (n != 0) {
// verify we got an entire code
if (n != 4) {
LOG((CLOG_ERR "incomplete message from server: %d bytes", n));
m_client->disconnect("incomplete message from server");
return;
}
// parse message
LOG((CLOG_DEBUG2 "msg from server: %c%c%c%c", code[0], code[1], code[2], code[3]));
switch ((this->*m_parser)(code)) {
case kOkay:
break;
case kUnknown:
LOG((CLOG_ERR "invalid message from server: %c%c%c%c", code[0], code[1], code[2], code[3]));
m_client->disconnect("invalid message from server");
return;
case kDisconnect:
return;
}
// next message
n = m_stream->read(code, 4);
}
flushCompressedMouse();
}
CServerProxy::EResult
CServerProxy::parseHandshakeMessage(const UInt8* code)
{
if (memcmp(code, kMsgQInfo, 4) == 0) {
queryInfo();
}
else if (memcmp(code, kMsgCInfoAck, 4) == 0) {
infoAcknowledgment();
}
else if (memcmp(code, kMsgDSetOptions, 4) == 0) {
setOptions();
// handshake is complete
m_parser = &CServerProxy::parseMessage;
m_client->handshakeComplete();
}
else if (memcmp(code, kMsgCResetOptions, 4) == 0) {
resetOptions();
}
else if (memcmp(code, kMsgCKeepAlive, 4) == 0) {
// echo keep alives and reset alarm
CProtocolUtil::writef(m_stream, kMsgCKeepAlive);
resetKeepAliveAlarm();
}
else if (memcmp(code, kMsgCNoop, 4) == 0) {
// accept and discard no-op
}
else if (memcmp(code, kMsgCClose, 4) == 0) {
// server wants us to hangup
LOG((CLOG_DEBUG1 "recv close"));
m_client->disconnect(NULL);
return kDisconnect;
}
else if (memcmp(code, kMsgEIncompatible, 4) == 0) {
SInt32 major, minor;
CProtocolUtil::readf(m_stream,
kMsgEIncompatible + 4, &major, &minor);
LOG((CLOG_ERR "server has incompatible version %d.%d", major, minor));
m_client->disconnect("server has incompatible version");
return kDisconnect;
}
else if (memcmp(code, kMsgEBusy, 4) == 0) {
LOG((CLOG_ERR "server already has a connected client with name \"%s\"", m_client->getName().c_str()));
m_client->disconnect("server already has a connected client with our name");
return kDisconnect;
}
else if (memcmp(code, kMsgEUnknown, 4) == 0) {
LOG((CLOG_ERR "server refused client with name \"%s\"", m_client->getName().c_str()));
m_client->disconnect("server refused client with our name");
return kDisconnect;
}
else if (memcmp(code, kMsgEBad, 4) == 0) {
LOG((CLOG_ERR "server disconnected due to a protocol error"));
m_client->disconnect("server reported a protocol error");
return kDisconnect;
}
else {
return kUnknown;
}
return kOkay;
}
CServerProxy::EResult
CServerProxy::parseMessage(const UInt8* code)
{
if (memcmp(code, kMsgDMouseMove, 4) == 0) {
mouseMove();
}
else if (memcmp(code, kMsgDMouseRelMove, 4) == 0) {
mouseRelativeMove();
}
else if (memcmp(code, kMsgDMouseWheel, 4) == 0) {
mouseWheel();
}
else if (memcmp(code, kMsgDKeyDown, 4) == 0) {
keyDown();
}
else if (memcmp(code, kMsgDKeyUp, 4) == 0) {
keyUp();
}
else if (memcmp(code, kMsgDMouseDown, 4) == 0) {
mouseDown();
}
else if (memcmp(code, kMsgDMouseUp, 4) == 0) {
mouseUp();
}
else if (memcmp(code, kMsgDKeyRepeat, 4) == 0) {
keyRepeat();
}
else if (memcmp(code, kMsgCKeepAlive, 4) == 0) {
// echo keep alives and reset alarm
CProtocolUtil::writef(m_stream, kMsgCKeepAlive);
resetKeepAliveAlarm();
}
else if (memcmp(code, kMsgCNoop, 4) == 0) {
// accept and discard no-op
}
else if (memcmp(code, kMsgCEnter, 4) == 0) {
enter();
}
else if (memcmp(code, kMsgCLeave, 4) == 0) {
leave();
}
else if (memcmp(code, kMsgCClipboard, 4) == 0) {
grabClipboard();
}
else if (memcmp(code, kMsgCScreenSaver, 4) == 0) {
screensaver();
}
else if (memcmp(code, kMsgQInfo, 4) == 0) {
queryInfo();
}
else if (memcmp(code, kMsgCInfoAck, 4) == 0) {
infoAcknowledgment();
}
else if (memcmp(code, kMsgDClipboard, 4) == 0) {
setClipboard();
}
else if (memcmp(code, kMsgCResetOptions, 4) == 0) {
resetOptions();
}
else if (memcmp(code, kMsgDSetOptions, 4) == 0) {
setOptions();
}
else if (memcmp(code, kMsgCClose, 4) == 0) {
// server wants us to hangup
LOG((CLOG_DEBUG1 "recv close"));
m_client->disconnect(NULL);
return kDisconnect;
}
else if (memcmp(code, kMsgEBad, 4) == 0) {
LOG((CLOG_ERR "server disconnected due to a protocol error"));
m_client->disconnect("server reported a protocol error");
return kDisconnect;
}
else {
return kUnknown;
}
// send a reply. this is intended to work around a delay when
// running a linux server and an OS X (any BSD?) client. the
// client waits to send an ACK (if the system control flag
// net.inet.tcp.delayed_ack is 1) in hopes of piggybacking it
// on a data packet. we provide that packet here. i don't
// know why a delayed ACK should cause the server to wait since
// TCP_NODELAY is enabled.
CProtocolUtil::writef(m_stream, kMsgCNoop);
return kOkay;
}
void
CServerProxy::handleKeepAliveAlarm(const CEvent&, void*)
{
LOG((CLOG_NOTE "server is dead"));
m_client->disconnect("server is not responding");
}
void
CServerProxy::onInfoChanged()
{
// ignore mouse motion until we receive acknowledgment of our info
// change message.
m_ignoreMouse = true;
// send info update
queryInfo();
}
bool
CServerProxy::onGrabClipboard(ClipboardID id)
{
LOG((CLOG_DEBUG1 "sending clipboard %d changed", id));
CProtocolUtil::writef(m_stream, kMsgCClipboard, id, m_seqNum);
return true;
}
void
CServerProxy::onClipboardChanged(ClipboardID id, const IClipboard* clipboard)
{
CString data = IClipboard::marshall(clipboard);
LOG((CLOG_DEBUG1 "sending clipboard %d seqnum=%d, size=%d", id, m_seqNum, data.size()));
CProtocolUtil::writef(m_stream, kMsgDClipboard, id, m_seqNum, &data);
}
void
CServerProxy::flushCompressedMouse()
{
if (m_compressMouse) {
m_compressMouse = false;
m_client->mouseMove(m_xMouse, m_yMouse);
}
if (m_compressMouseRelative) {
m_compressMouseRelative = false;
m_client->mouseRelativeMove(m_dxMouse, m_dyMouse);
m_dxMouse = 0;
m_dyMouse = 0;
}
}
void
CServerProxy::sendInfo(const CClientInfo& info)
{
LOG((CLOG_DEBUG1 "sending info shape=%d,%d %dx%d", info.m_x, info.m_y, info.m_w, info.m_h));
CProtocolUtil::writef(m_stream, kMsgDInfo,
info.m_x, info.m_y,
info.m_w, info.m_h, 0,
info.m_mx, info.m_my);
}
KeyID
CServerProxy::translateKey(KeyID id) const
{
static const KeyID s_translationTable[kKeyModifierIDLast][2] = {
{ kKeyNone, kKeyNone },
{ kKeyShift_L, kKeyShift_R },
{ kKeyControl_L, kKeyControl_R },
{ kKeyAlt_L, kKeyAlt_R },
{ kKeyMeta_L, kKeyMeta_R },
{ kKeySuper_L, kKeySuper_R }
};
KeyModifierID id2 = kKeyModifierIDNull;
UInt32 side = 0;
switch (id) {
case kKeyShift_L:
id2 = kKeyModifierIDShift;
side = 0;
break;
case kKeyShift_R:
id2 = kKeyModifierIDShift;
side = 1;
break;
case kKeyControl_L:
id2 = kKeyModifierIDControl;
side = 0;
break;
case kKeyControl_R:
id2 = kKeyModifierIDControl;
side = 1;
break;
case kKeyAlt_L:
id2 = kKeyModifierIDAlt;
side = 0;
break;
case kKeyAlt_R:
id2 = kKeyModifierIDAlt;
side = 1;
break;
case kKeyMeta_L:
id2 = kKeyModifierIDMeta;
side = 0;
break;
case kKeyMeta_R:
id2 = kKeyModifierIDMeta;
side = 1;
break;
case kKeySuper_L:
id2 = kKeyModifierIDSuper;
side = 0;
break;
case kKeySuper_R:
id2 = kKeyModifierIDSuper;
side = 1;
break;
}
if (id2 != kKeyModifierIDNull) {
return s_translationTable[m_modifierTranslationTable[id2]][side];
}
else {
return id;
}
}
KeyModifierMask
CServerProxy::translateModifierMask(KeyModifierMask mask) const
{
static const KeyModifierMask s_masks[kKeyModifierIDLast] = {
0x0000,
KeyModifierShift,
KeyModifierControl,
KeyModifierAlt,
KeyModifierMeta,
KeyModifierSuper
};
KeyModifierMask newMask = mask & ~(KeyModifierShift |
KeyModifierControl |
KeyModifierAlt |
KeyModifierMeta |
KeyModifierSuper);
if ((mask & KeyModifierShift) != 0) {
newMask |= s_masks[m_modifierTranslationTable[kKeyModifierIDShift]];
}
if ((mask & KeyModifierControl) != 0) {
newMask |= s_masks[m_modifierTranslationTable[kKeyModifierIDControl]];
}
if ((mask & KeyModifierAlt) != 0) {
newMask |= s_masks[m_modifierTranslationTable[kKeyModifierIDAlt]];
}
if ((mask & KeyModifierMeta) != 0) {
newMask |= s_masks[m_modifierTranslationTable[kKeyModifierIDMeta]];
}
if ((mask & KeyModifierSuper) != 0) {
newMask |= s_masks[m_modifierTranslationTable[kKeyModifierIDSuper]];
}
return newMask;
}
void
CServerProxy::enter()
{
// parse
SInt16 x, y;
UInt16 mask;
UInt32 seqNum;
CProtocolUtil::readf(m_stream, kMsgCEnter + 4, &x, &y, &seqNum, &mask);
LOG((CLOG_DEBUG1 "recv enter, %d,%d %d %04x", x, y, seqNum, mask));
// discard old compressed mouse motion, if any
m_compressMouse = false;
m_compressMouseRelative = false;
m_dxMouse = 0;
m_dyMouse = 0;
m_seqNum = seqNum;
// forward
m_client->enter(x, y, seqNum, static_cast<KeyModifierMask>(mask), false);
}
void
CServerProxy::leave()
{
// parse
LOG((CLOG_DEBUG1 "recv leave"));
// send last mouse motion
flushCompressedMouse();
// forward
m_client->leave();
}
void
CServerProxy::setClipboard()
{
// parse
ClipboardID id;
UInt32 seqNum;
CString data;
CProtocolUtil::readf(m_stream, kMsgDClipboard + 4, &id, &seqNum, &data);
LOG((CLOG_DEBUG "recv clipboard %d size=%d", id, data.size()));
// validate
if (id >= kClipboardEnd) {
return;
}
// forward
CClipboard clipboard;
clipboard.unmarshall(data, 0);
m_client->setClipboard(id, &clipboard);
}
void
CServerProxy::grabClipboard()
{
// parse
ClipboardID id;
UInt32 seqNum;
CProtocolUtil::readf(m_stream, kMsgCClipboard + 4, &id, &seqNum);
LOG((CLOG_DEBUG "recv grab clipboard %d", id));
// validate
if (id >= kClipboardEnd) {
return;
}
// forward
m_client->grabClipboard(id);
}
void
CServerProxy::keyDown()
{
// get mouse up to date
flushCompressedMouse();
// parse
UInt16 id, mask, button;
CProtocolUtil::readf(m_stream, kMsgDKeyDown + 4, &id, &mask, &button);
LOG((CLOG_DEBUG1 "recv key down id=0x%08x, mask=0x%04x, button=0x%04x", id, mask, button));
// translate
KeyID id2 = translateKey(static_cast<KeyID>(id));
KeyModifierMask mask2 = translateModifierMask(
static_cast<KeyModifierMask>(mask));
if (id2 != static_cast<KeyID>(id) ||
mask2 != static_cast<KeyModifierMask>(mask))
LOG((CLOG_DEBUG1 "key down translated to id=0x%08x, mask=0x%04x", id2, mask2));
// forward
m_client->keyDown(id2, mask2, button);
}
void
CServerProxy::keyRepeat()
{
// get mouse up to date
flushCompressedMouse();
// parse
UInt16 id, mask, count, button;
CProtocolUtil::readf(m_stream, kMsgDKeyRepeat + 4,
&id, &mask, &count, &button);
LOG((CLOG_DEBUG1 "recv key repeat id=0x%08x, mask=0x%04x, count=%d, button=0x%04x", id, mask, count, button));
// translate
KeyID id2 = translateKey(static_cast<KeyID>(id));
KeyModifierMask mask2 = translateModifierMask(
static_cast<KeyModifierMask>(mask));
if (id2 != static_cast<KeyID>(id) ||
mask2 != static_cast<KeyModifierMask>(mask))
LOG((CLOG_DEBUG1 "key repeat translated to id=0x%08x, mask=0x%04x", id2, mask2));
// forward
m_client->keyRepeat(id2, mask2, count, button);
}
void
CServerProxy::keyUp()
{
// get mouse up to date
flushCompressedMouse();
// parse
UInt16 id, mask, button;
CProtocolUtil::readf(m_stream, kMsgDKeyUp + 4, &id, &mask, &button);
LOG((CLOG_DEBUG1 "recv key up id=0x%08x, mask=0x%04x, button=0x%04x", id, mask, button));
// translate
KeyID id2 = translateKey(static_cast<KeyID>(id));
KeyModifierMask mask2 = translateModifierMask(
static_cast<KeyModifierMask>(mask));
if (id2 != static_cast<KeyID>(id) ||
mask2 != static_cast<KeyModifierMask>(mask))
LOG((CLOG_DEBUG1 "key up translated to id=0x%08x, mask=0x%04x", id2, mask2));
// forward
m_client->keyUp(id2, mask2, button);
}
void
CServerProxy::mouseDown()
{
// get mouse up to date
flushCompressedMouse();
// parse
SInt8 id;
CProtocolUtil::readf(m_stream, kMsgDMouseDown + 4, &id);
LOG((CLOG_DEBUG1 "recv mouse down id=%d", id));
// forward
m_client->mouseDown(static_cast<ButtonID>(id));
}
void
CServerProxy::mouseUp()
{
// get mouse up to date
flushCompressedMouse();
// parse
SInt8 id;
CProtocolUtil::readf(m_stream, kMsgDMouseUp + 4, &id);
LOG((CLOG_DEBUG1 "recv mouse up id=%d", id));
// forward
m_client->mouseUp(static_cast<ButtonID>(id));
}
void
CServerProxy::mouseMove()
{
// parse
bool ignore;
SInt16 x, y;
CProtocolUtil::readf(m_stream, kMsgDMouseMove + 4, &x, &y);
// note if we should ignore the move
ignore = m_ignoreMouse;
// compress mouse motion events if more input follows
if (!ignore && !m_compressMouse && m_stream->isReady()) {
m_compressMouse = true;
}
// if compressing then ignore the motion but record it
if (m_compressMouse) {
m_compressMouseRelative = false;
ignore = true;
m_xMouse = x;
m_yMouse = y;
m_dxMouse = 0;
m_dyMouse = 0;
}
LOG((CLOG_DEBUG2 "recv mouse move %d,%d", x, y));
// forward
if (!ignore) {
m_client->mouseMove(x, y);
}
}
void
CServerProxy::mouseRelativeMove()
{
// parse
bool ignore;
SInt16 dx, dy;
CProtocolUtil::readf(m_stream, kMsgDMouseRelMove + 4, &dx, &dy);
// note if we should ignore the move
ignore = m_ignoreMouse;
// compress mouse motion events if more input follows
if (!ignore && !m_compressMouseRelative && m_stream->isReady()) {
m_compressMouseRelative = true;
}
// if compressing then ignore the motion but record it
if (m_compressMouseRelative) {
ignore = true;
m_dxMouse += dx;
m_dyMouse += dy;
}
LOG((CLOG_DEBUG2 "recv mouse relative move %d,%d", dx, dy));
// forward
if (!ignore) {
m_client->mouseRelativeMove(dx, dy);
}
}
void
CServerProxy::mouseWheel()
{
// get mouse up to date
flushCompressedMouse();
// parse
SInt16 xDelta, yDelta;
CProtocolUtil::readf(m_stream, kMsgDMouseWheel + 4, &xDelta, &yDelta);
LOG((CLOG_DEBUG2 "recv mouse wheel %+d,%+d", xDelta, yDelta));
// forward
m_client->mouseWheel(xDelta, yDelta);
}
void
CServerProxy::screensaver()
{
// parse
SInt8 on;
CProtocolUtil::readf(m_stream, kMsgCScreenSaver + 4, &on);
LOG((CLOG_DEBUG1 "recv screen saver on=%d", on));
// forward
m_client->screensaver(on != 0);
}
void
CServerProxy::resetOptions()
{
// parse
LOG((CLOG_DEBUG1 "recv reset options"));
// forward
m_client->resetOptions();
// reset keep alive
setKeepAliveRate(kKeepAliveRate);
// reset modifier translation table
for (KeyModifierID id = 0; id < kKeyModifierIDLast; ++id) {
m_modifierTranslationTable[id] = id;
}
}
void
CServerProxy::setOptions()
{
// parse
COptionsList options;
CProtocolUtil::readf(m_stream, kMsgDSetOptions + 4, &options);
LOG((CLOG_DEBUG1 "recv set options size=%d", options.size()));
// forward
m_client->setOptions(options);
// update modifier table
for (UInt32 i = 0, n = options.size(); i < n; i += 2) {
KeyModifierID id = kKeyModifierIDNull;
if (options[i] == kOptionModifierMapForShift) {
id = kKeyModifierIDShift;
}
else if (options[i] == kOptionModifierMapForControl) {
id = kKeyModifierIDControl;
}
else if (options[i] == kOptionModifierMapForAlt) {
id = kKeyModifierIDAlt;
}
else if (options[i] == kOptionModifierMapForMeta) {
id = kKeyModifierIDMeta;
}
else if (options[i] == kOptionModifierMapForSuper) {
id = kKeyModifierIDSuper;
}
else if (options[i] == kOptionHeartbeat) {
// update keep alive
setKeepAliveRate(1.0e-3 * static_cast<double>(options[i + 1]));
}
if (id != kKeyModifierIDNull) {
m_modifierTranslationTable[id] =
static_cast<KeyModifierID>(options[i + 1]);
LOG((CLOG_DEBUG1 "modifier %d mapped to %d", id, m_modifierTranslationTable[id]));
}
}
}
void
CServerProxy::queryInfo()
{
CClientInfo info;
m_client->getShape(info.m_x, info.m_y, info.m_w, info.m_h);
m_client->getCursorPos(info.m_mx, info.m_my);
sendInfo(info);
}
void
CServerProxy::infoAcknowledgment()
{
LOG((CLOG_DEBUG1 "recv info acknowledgment"));
m_ignoreMouse = false;
}

115
lib/client/CServerProxy.h Normal file
View File

@@ -0,0 +1,115 @@
/*
* 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 CSERVERPROXY_H
#define CSERVERPROXY_H
#include "ClipboardTypes.h"
#include "KeyTypes.h"
#include "CEvent.h"
class CClient;
class CClientInfo;
class CEventQueueTimer;
class IClipboard;
class IStream;
//! Proxy for server
/*!
This class acts a proxy for the server, converting calls into messages
to the server and messages from the server to calls on the client.
*/
class CServerProxy {
public:
/*!
Process messages from the server on \p stream and forward to
\p client.
*/
CServerProxy(CClient* client, IStream* stream);
~CServerProxy();
//! @name manipulators
//@{
void onInfoChanged();
bool onGrabClipboard(ClipboardID);
void onClipboardChanged(ClipboardID, const IClipboard*);
//@}
protected:
enum EResult { kOkay, kUnknown, kDisconnect };
EResult parseHandshakeMessage(const UInt8* code);
EResult parseMessage(const UInt8* code);
private:
// if compressing mouse motion then send the last motion now
void flushCompressedMouse();
void sendInfo(const CClientInfo&);
void resetKeepAliveAlarm();
void setKeepAliveRate(double);
// modifier key translation
KeyID translateKey(KeyID) const;
KeyModifierMask translateModifierMask(KeyModifierMask) const;
// event handlers
void handleData(const CEvent&, void*);
void handleKeepAliveAlarm(const CEvent&, void*);
// message handlers
void enter();
void leave();
void setClipboard();
void grabClipboard();
void keyDown();
void keyRepeat();
void keyUp();
void mouseDown();
void mouseUp();
void mouseMove();
void mouseRelativeMove();
void mouseWheel();
void screensaver();
void resetOptions();
void setOptions();
void queryInfo();
void infoAcknowledgment();
private:
typedef EResult (CServerProxy::*MessageParser)(const UInt8*);
CClient* m_client;
IStream* m_stream;
UInt32 m_seqNum;
bool m_compressMouse;
bool m_compressMouseRelative;
SInt32 m_xMouse, m_yMouse;
SInt32 m_dxMouse, m_dyMouse;
bool m_ignoreMouse;
KeyModifierID m_modifierTranslationTable[kKeyModifierIDLast];
double m_keepAliveAlarm;
CEventQueueTimer* m_keepAliveAlarmTimer;
MessageParser m_parser;
};
#endif

40
lib/client/Makefile.am Normal file
View File

@@ -0,0 +1,40 @@
# 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.
## Process this file with automake to produce Makefile.in
NULL =
EXTRA_DIST = \
Makefile.win \
$(NULL)
MAINTAINERCLEANFILES = \
Makefile.in \
$(NULL)
noinst_LIBRARIES = libclient.a
libclient_a_SOURCES = \
CClient.cpp \
CServerProxy.cpp \
CClient.h \
CServerProxy.h \
$(NULL)
INCLUDES = \
-I$(top_srcdir)/lib/common \
-I$(top_srcdir)/lib/arch \
-I$(top_srcdir)/lib/base \
-I$(top_srcdir)/lib/mt \
-I$(top_srcdir)/lib/io \
-I$(top_srcdir)/lib/net \
-I$(top_srcdir)/lib/synergy \
-I$(top_srcdir)/lib/platform \
$(NULL)

63
lib/client/Makefile.win Normal file
View File

@@ -0,0 +1,63 @@
# synergy -- mouse and keyboard sharing utility
# Copyright (C) 2007 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.
LIB_CLIENT_SRC = lib\client
LIB_CLIENT_DST = $(BUILD_DST)\$(LIB_CLIENT_SRC)
LIB_CLIENT_LIB = "$(LIB_CLIENT_DST)\client.lib"
LIB_CLIENT_CPP = \
"CClient.cpp" \
"CServerProxy.cpp" \
$(NULL)
LIB_CLIENT_OBJ = \
"$(LIB_CLIENT_DST)\CClient.obj" \
"$(LIB_CLIENT_DST)\CServerProxy.obj" \
$(NULL)
LIB_CLIENT_INC = \
/I"lib\common" \
/I"lib\arch" \
/I"lib\base" \
/I"lib\mt" \
/I"lib\io" \
/I"lib\net" \
/I"lib\synergy" \
/I"lib\platform" \
$(NULL)
CPP_FILES = $(CPP_FILES) $(LIB_CLIENT_CPP)
OBJ_FILES = $(OBJ_FILES) $(LIB_CLIENT_OBJ)
LIB_FILES = $(LIB_FILES) $(LIB_CLIENT_LIB)
# Dependency rules
$(LIB_CLIENT_OBJ): $(AUTODEP)
!if EXIST($(LIB_CLIENT_DST)\deps.mak)
!include $(LIB_CLIENT_DST)\deps.mak
!endif
# Build rules. Use batch-mode rules if possible.
!if DEFINED(_NMAKE_VER)
{$(LIB_CLIENT_SRC)\}.cpp{$(LIB_CLIENT_DST)\}.obj::
!else
{$(LIB_CLIENT_SRC)\}.cpp{$(LIB_CLIENT_DST)\}.obj:
!endif
@$(ECHO) Compile in $(LIB_CLIENT_SRC)
-@$(MKDIR) $(LIB_CLIENT_DST) 2>NUL:
$(cpp) $(cppdebug) $(cppflags) $(cppvarsmt) /showIncludes \
$(LIB_CLIENT_INC) \
/Fo$(LIB_CLIENT_DST)\ \
/Fd$(LIB_CLIENT_LIB:.lib=.pdb) \
$< | $(AUTODEP) $(LIB_CLIENT_SRC) $(LIB_CLIENT_DST)
$(LIB_CLIENT_LIB): $(LIB_CLIENT_OBJ)
@$(ECHO) Link $(@F)
$(implib) $(ildebug) $(ilflags) \
/out:$@ \
$**
$(AUTODEP) $(LIB_CLIENT_SRC) $(LIB_CLIENT_DST) $(**:.obj=.d)