From 23f948d55afa5856a0db3bf88bdb5e4bb1cfae4b Mon Sep 17 00:00:00 2001 From: crs Date: Mon, 8 Oct 2001 19:24:46 +0000 Subject: [PATCH] checkpoint. first cut of client and server apps. not tested yet but they compile and *should* work as is. --- Makefile | 3 + notes | 1 - synergy/CClient.cpp | 106 ++++++++---- synergy/CClient.h | 14 +- synergy/CServer.cpp | 11 +- synergy/CXWindowsPrimaryScreen.cpp | 1 - synergy/CXWindowsSecondaryScreen.cpp | 231 +++++++++++++++++++++++++++ synergy/CXWindowsSecondaryScreen.h | 44 +++++ synergy/ISecondaryScreen.h | 2 + synergy/Makefile | 11 +- synergy/client.cpp | 21 +++ synergy/server.cpp | 29 ++++ 12 files changed, 434 insertions(+), 40 deletions(-) create mode 100644 synergy/CXWindowsSecondaryScreen.cpp create mode 100644 synergy/CXWindowsSecondaryScreen.h create mode 100644 synergy/client.cpp create mode 100644 synergy/server.cpp diff --git a/Makefile b/Makefile index d3ee18df..8c3dfeb5 100644 --- a/Makefile +++ b/Makefile @@ -42,6 +42,7 @@ LCXXINCS = \ -I$(DEPTH)/mt \ -I$(DEPTH)/io \ -I$(DEPTH)/net \ + -I$(DEPTH)/synergy \ $(NULL) CXXFILES = test.cpp @@ -49,6 +50,7 @@ CXXFILES = test.cpp # libraries we depend on # DEPLIBS = \ + $(LIBDIR)/libsynergy.a \ $(LIBDIR)/libnet.a \ $(LIBDIR)/libio.a \ $(LIBDIR)/libmt.a \ @@ -61,3 +63,4 @@ LLDLIBS = \ test: $(OBJECTS) $(DEPLIBS) $(CXX) $(CXXFLAGS) -o $@ $(OBJECTS) $(LDFLAGS) + diff --git a/notes b/notes index 0effd884..b0845048 100644 --- a/notes +++ b/notes @@ -9,7 +9,6 @@ CServer * put mutex locks wherever necessary (like accessing m_active) CClient - * need thread to handle screen * need methods for screen event handler to call as appropriate server client diff --git a/synergy/CClient.cpp b/synergy/CClient.cpp index bd4e011b..1a20bc1e 100644 --- a/synergy/CClient.cpp +++ b/synergy/CClient.cpp @@ -2,15 +2,22 @@ #include "CInputPacketStream.h" #include "COutputPacketStream.h" #include "CProtocolUtil.h" +#include "ISecondaryScreen.h" +#include "ProtocolTypes.h" #include "CTimerThread.h" +#include "XSynergy.h" #include +#include // // CClient // CClient::CClient(const CString& clientName) : - m_name(clientName) + m_name(clientName), + m_input(NULL), + m_output(NULL), + m_screen(NULL) { } @@ -19,6 +26,7 @@ CClient::~CClient() } #include "CTCPSocket.h" +#include "CXWindowsSecondaryScreen.h" void CClient::run(const CNetworkAddress& serverAddress) { std::auto_ptr socket; @@ -84,12 +92,18 @@ void CClient::run(const CNetworkAddress& serverAddress) } // connect to screen - // FIXME -- make object that closes and destroys screen in - // it's d'tor. screen must not be handling event queue by - // the time the streams are destroyed. - - // handle messages from server + std::auto_ptr screenCleaner; try { + m_screen = new CXWindowsSecondaryScreen; + screenCleaner.reset(new CScreenCleaner(this, m_screen)); + } + catch (XBase& e) { + fprintf(stderr, "cannot open screen: %s\n", e.what()); + return; + } + + try { + // handle messages from server for (;;) { // wait for reply UInt8 code[4]; @@ -108,46 +122,46 @@ void CClient::run(const CNetworkAddress& serverAddress) // parse message if (memcmp(code, kMsgDMouseMove, 4) == 0) { - onMouseMove(input.get()); + onMouseMove(); } else if (memcmp(code, kMsgDMouseWheel, 4) == 0) { - onMouseWheel(input.get()); + onMouseWheel(); } else if (memcmp(code, kMsgDKeyDown, 4) == 0) { - onKeyDown(input.get()); + onKeyDown(); } else if (memcmp(code, kMsgDKeyUp, 4) == 0) { - onKeyUp(input.get()); + onKeyUp(); } else if (memcmp(code, kMsgDMouseDown, 4) == 0) { - onMouseDown(input.get()); + onMouseDown(); } else if (memcmp(code, kMsgDMouseUp, 4) == 0) { - onMouseUp(input.get()); + onMouseUp(); } else if (memcmp(code, kMsgDKeyRepeat, 4) == 0) { - onKeyRepeat(input.get()); + onKeyRepeat(); } else if (memcmp(code, kMsgCEnter, 4) == 0) { - onEnter(input.get()); + onEnter(); } else if (memcmp(code, kMsgCLeave, 4) == 0) { - onLeave(input.get()); + onLeave(); } else if (memcmp(code, kMsgCClipboard, 4) == 0) { - onGrabClipboard(input.get()); + onGrabClipboard(); } else if (memcmp(code, kMsgCScreenSaver, 4) == 0) { - onScreenSaver(input.get()); + onScreenSaver(); } else if (memcmp(code, kMsgQInfo, 4) == 0) { - onQueryInfo(input.get()); + onQueryInfo(); } else if (memcmp(code, kMsgQClipboard, 4) == 0) { - onQueryClipboard(input.get()); + onQueryClipboard(); } else if (memcmp(code, kMsgDClipboard, 4) == 0) { - onSetClipboard(input.get()); + onSetClipboard(); } else if (memcmp(code, kMsgCClose, 4) == 0) { // server wants us to hangup @@ -159,14 +173,17 @@ void CClient::run(const CNetworkAddress& serverAddress) break; } } - - // done with socket - m_socket->close(); } catch (XBase& e) { fprintf(stderr, "error: %s\n", e.what()); return; } + + // done with screen + screenCleaner.reset(); + + // done with socket + socket->close(); } void CClient::onEnter() @@ -196,7 +213,7 @@ void CClient::onScreenSaver() void CClient::onQueryInfo() { SInt32 w, h; - m_screen->getSize(w, h); + m_screen->getSize(&w, &h); SInt32 zoneSize = m_screen->getJumpZoneSize(); CProtocolUtil::writef(m_output, kMsgDInfo, w, h, zoneSize); } @@ -215,16 +232,16 @@ void CClient::onKeyDown() { SInt32 id, mask; CProtocolUtil::readf(m_input, kMsgDKeyDown + 4, &id, &mask); - m_screen->onKeyDown(reinterpret_cast(id), - reinterpret_cast(mask)); + m_screen->onKeyDown(static_cast(id), + static_cast(mask)); } void CClient::onKeyRepeat() { SInt32 id, mask, count; CProtocolUtil::readf(m_input, kMsgDKeyRepeat + 4, &id, &mask, &count); - m_screen->onKeyRepeat(reinterpret_cast(id), - reinterpret_cast(mask), + m_screen->onKeyRepeat(static_cast(id), + static_cast(mask), count); } @@ -232,22 +249,22 @@ void CClient::onKeyUp() { SInt32 id, mask; CProtocolUtil::readf(m_input, kMsgDKeyUp + 4, &id, &mask); - m_screen->onKeyUp(reinterpret_cast(id), - reinterpret_cast(mask)); + m_screen->onKeyUp(static_cast(id), + static_cast(mask)); } void CClient::onMouseDown() { SInt32 id; CProtocolUtil::readf(m_input, kMsgDMouseDown + 4, &id); - m_screen->onMouseDown(reinterpret_cast(id)); + m_screen->onMouseDown(static_cast(id)); } void CClient::onMouseUp() { SInt32 id; CProtocolUtil::readf(m_input, kMsgDMouseUp + 4, &id); - m_screen->onMouseUp(reinterpret_cast(id)); + m_screen->onMouseUp(static_cast(id)); } void CClient::onMouseMove() @@ -263,3 +280,28 @@ void CClient::onMouseWheel() CProtocolUtil::readf(m_input, kMsgDMouseWheel + 4, &delta); m_screen->onMouseWheel(delta); } + + +// +// CClient::CScreenCleaner +// + +CClient::CScreenCleaner::CScreenCleaner(CClient* client, + ISecondaryScreen* screen) : + m_screen(screen) +{ + assert(m_screen != NULL); + try { + m_screen->open(client); + } + catch (...) { + delete m_screen; + throw; + } +} + +CClient::CScreenCleaner::~CScreenCleaner() +{ + m_screen->close(); + delete m_screen; +} diff --git a/synergy/CClient.h b/synergy/CClient.h index 7ad0b7f7..825e973f 100644 --- a/synergy/CClient.h +++ b/synergy/CClient.h @@ -7,6 +7,7 @@ class CNetworkAddress; class IInputStream; class IOutputStream; +class ISecondaryScreen; class CClient { public: @@ -37,10 +38,21 @@ class CClient { void onMouseMove(); void onMouseWheel(); + private: + class CScreenCleaner { + public: + CScreenCleaner(CClient*, ISecondaryScreen*); + ~CScreenCleaner(); + + private: + ISecondaryScreen* m_screen; + }; + private: CString m_name; - IInputStream* m_output; + IInputStream* m_input; IOutputStream* m_output; + ISecondaryScreen* m_screen; }; #endif diff --git a/synergy/CServer.cpp b/synergy/CServer.cpp index 28699806..94b86968 100644 --- a/synergy/CServer.cpp +++ b/synergy/CServer.cpp @@ -545,6 +545,7 @@ void CServer::mapPosition(CScreenInfo* src, } } +#include "CTCPListenSocket.h" void CServer::acceptClients(void*) { // add this thread to the list of threads to cancel. remove from @@ -554,7 +555,8 @@ void CServer::acceptClients(void*) std::auto_ptr listen; try { // create socket listener - listen.reset(m_socketFactory->createListen()); +// listen.reset(m_socketFactory->createListen()); + listen.reset(new CTCPListenSocket); // FIXME // bind to the desired port. keep retrying if we can't bind // the address immediately. @@ -712,7 +714,12 @@ void CServer::openPrimaryScreen() m_primary->open(this); // add connection - m_active = addConnection(CString("primary"/* FIXME */), NULL); + m_active = addConnection(CString("primary"/* FIXME */), NULL); + + // update info + m_primary->getSize(&m_active->m_width, &m_active->m_height); + m_active->m_zoneSize = m_primary->getJumpZoneSize(); + // FIXME -- need way for primary screen to call us back } void CServer::closePrimaryScreen() throw() diff --git a/synergy/CXWindowsPrimaryScreen.cpp b/synergy/CXWindowsPrimaryScreen.cpp index 1c24b332..9fbc5647 100644 --- a/synergy/CXWindowsPrimaryScreen.cpp +++ b/synergy/CXWindowsPrimaryScreen.cpp @@ -4,7 +4,6 @@ #include "TMethodJob.h" #include #include -#include // // CXWindowsPrimaryScreen diff --git a/synergy/CXWindowsSecondaryScreen.cpp b/synergy/CXWindowsSecondaryScreen.cpp new file mode 100644 index 00000000..d7f1cc4e --- /dev/null +++ b/synergy/CXWindowsSecondaryScreen.cpp @@ -0,0 +1,231 @@ +#include "CXWindowsSecondaryScreen.h" +#include "CClient.h" +#include "CThread.h" +#include "TMethodJob.h" +#include +#include +#include + +// +// CXWindowsSecondaryScreen +// + +CXWindowsSecondaryScreen::CXWindowsSecondaryScreen() : + m_client(NULL), + m_display(NULL), + m_window(None), + m_w(0), m_h(0) +{ + // do nothing +} + +CXWindowsSecondaryScreen::~CXWindowsSecondaryScreen() +{ + assert(m_display == NULL); +} + +void CXWindowsSecondaryScreen::open(CClient* client) +{ + assert(m_client == NULL); + assert(client != NULL); + + // set the client + m_client = client; + + // open the display + m_display = ::XOpenDisplay(NULL); // FIXME -- allow non-default + if (m_display == NULL) + throw int(5); // FIXME -- make exception for this + + // get default screen + m_screen = DefaultScreen(m_display); + Screen* screen = ScreenOfDisplay(m_display, m_screen); + + // get screen size + m_w = WidthOfScreen(screen); + m_h = HeightOfScreen(screen); + + // verify the availability of the XTest extension + int majorOpcode, firstEvent, firstError; + if (!::XQueryExtension(m_display, XTestExtensionName, + &majorOpcode, &firstEvent, &firstError)) + throw int(6); // FIXME -- make exception for this + + // become impervious to server grabs + ::XTestGrabControl(m_display, True); + + // start processing events + m_eventThread = new CThread(new TMethodJob( + this, &CXWindowsSecondaryScreen::eventThread)); +} + +void CXWindowsSecondaryScreen::close() +{ + assert(m_client != NULL); + assert(m_eventThread != NULL); + + // stop event thread + m_eventThread->cancel(); + m_eventThread->wait(); + delete m_eventThread; + m_eventThread = NULL; + + // no longer impervious to server grabs + ::XTestGrabControl(m_display, False); + + // close the display + ::XCloseDisplay(m_display); + m_display = NULL; +} + +void CXWindowsSecondaryScreen::enter(SInt32 x, SInt32 y) +{ + assert(m_display != NULL); + + // warp to requested location + warpCursor(x, y); + + // show cursor + // FIXME +} + +void CXWindowsSecondaryScreen::leave() +{ + assert(m_display != NULL); + + // hide cursor + // FIXME +} + +void CXWindowsSecondaryScreen::warpCursor(SInt32 x, SInt32 y) +{ + assert(m_display != NULL); + + ::XTestFakeMotionEvent(m_display, m_screen, x, y, CurrentTime); + ::XSync(m_display, False); +} + +void CXWindowsSecondaryScreen::onKeyDown( + KeyID key, KeyModifierMask mask) +{ + assert(m_display != NULL); + + ::XTestFakeKeyEvent(m_display, mapKey(key, mask), True, CurrentTime); + ::XSync(m_display, False); +} + +void CXWindowsSecondaryScreen::onKeyRepeat( + KeyID, KeyModifierMask, SInt32) +{ + assert(m_display != NULL); + + // FIXME +} + +void CXWindowsSecondaryScreen::onKeyUp( + KeyID key, KeyModifierMask mask) +{ + assert(m_display != NULL); + + ::XTestFakeKeyEvent(m_display, mapKey(key, mask), False, CurrentTime); + ::XSync(m_display, False); +} + +void CXWindowsSecondaryScreen::onMouseDown(ButtonID button) +{ + assert(m_display != NULL); + + ::XTestFakeButtonEvent(m_display, mapButton(button), True, CurrentTime); + ::XSync(m_display, False); +} + +void CXWindowsSecondaryScreen::onMouseUp(ButtonID button) +{ + assert(m_display != NULL); + + ::XTestFakeButtonEvent(m_display, mapButton(button), False, CurrentTime); + ::XSync(m_display, False); +} + +void CXWindowsSecondaryScreen::onMouseMove( + SInt32 x, SInt32 y) +{ + assert(m_display != NULL); + + ::XTestFakeMotionEvent(m_display, m_screen, x, y, CurrentTime); + ::XSync(m_display, False); +} + +void CXWindowsSecondaryScreen::onMouseWheel(SInt32) +{ + assert(m_display != NULL); + + // FIXME +} + +void CXWindowsSecondaryScreen::getSize( + SInt32* width, SInt32* height) const +{ + assert(m_display != NULL); + assert(width != NULL && height != NULL); + + *width = m_w; + *height = m_h; +} + +SInt32 CXWindowsSecondaryScreen::getJumpZoneSize() const +{ + assert(m_display != NULL); + + return 0; +} + +void CXWindowsSecondaryScreen::eventThread(void*) +{ + for (;;) { + // wait for and then get the next event + while (XPending(m_display) == 0) { + CThread::sleep(0.05); + } + XEvent xevent; + XNextEvent(m_display, &xevent); + + // handle event + switch (xevent.type) { + case LeaveNotify: + // mouse moved out of window somehow. hide the window. +// ::XUnmapWindow(m_display, m_window); + break; + +/* + // FIXME -- handle screen resolution changes + + case SelectionClear: + target->XXX(xevent.xselectionclear.); + break; + + case SelectionNotify: + target->XXX(xevent.xselection.); + break; + + case SelectionRequest: + target->XXX(xevent.xselectionrequest.); + break; +*/ + } + } +} + +KeyCode CXWindowsSecondaryScreen::mapKey( + KeyID id, KeyModifierMask /*mask*/) const +{ + // FIXME -- use mask + return ::XKeysymToKeycode(m_display, static_cast(id)); +} + +unsigned int CXWindowsSecondaryScreen::mapButton( + ButtonID id) const +{ + // FIXME -- should use button mapping? + return static_cast(id); +} diff --git a/synergy/CXWindowsSecondaryScreen.h b/synergy/CXWindowsSecondaryScreen.h new file mode 100644 index 00000000..06cf0abe --- /dev/null +++ b/synergy/CXWindowsSecondaryScreen.h @@ -0,0 +1,44 @@ +#ifndef CXWINDOWSSECONDARYSCREEN_H +#define CXWINDOWSSECONDARYSCREEN_H + +#include "ISecondaryScreen.h" +#include + +class CThread; + +class CXWindowsSecondaryScreen : public ISecondaryScreen { + public: + CXWindowsSecondaryScreen(); + virtual ~CXWindowsSecondaryScreen(); + + // ISecondaryScreen overrides + virtual void open(CClient*); + virtual void close(); + virtual void enter(SInt32 xAbsolute, SInt32 yAbsolute); + virtual void leave(); + virtual void warpCursor(SInt32 xAbsolute, SInt32 yAbsolute); + virtual void onKeyDown(KeyID, KeyModifierMask); + virtual void onKeyRepeat(KeyID, KeyModifierMask, SInt32 count); + virtual void onKeyUp(KeyID, KeyModifierMask); + virtual void onMouseDown(ButtonID); + virtual void onMouseUp(ButtonID); + virtual void onMouseMove(SInt32 xAbsolute, SInt32 yAbsolute); + virtual void onMouseWheel(SInt32 delta); + virtual void getSize(SInt32* width, SInt32* height) const; + virtual SInt32 getJumpZoneSize() const; + + private: + void eventThread(void*); + KeyCode mapKey(KeyID, KeyModifierMask) const; + unsigned int mapButton(ButtonID button) const; + + private: + CClient* m_client; + CThread* m_eventThread; + Display* m_display; + int m_screen; + Window m_window; + SInt32 m_w, m_h; +}; + +#endif diff --git a/synergy/ISecondaryScreen.h b/synergy/ISecondaryScreen.h index 1deb45f9..8d24a64c 100644 --- a/synergy/ISecondaryScreen.h +++ b/synergy/ISecondaryScreen.h @@ -3,6 +3,8 @@ #include "IInterface.h" #include "BasicTypes.h" +#include "KeyTypes.h" +#include "MouseTypes.h" class CClient; //class IClipboard; diff --git a/synergy/Makefile b/synergy/Makefile index c16c90e7..5305a5c5 100644 --- a/synergy/Makefile +++ b/synergy/Makefile @@ -15,11 +15,13 @@ CXXFILES = \ COutputPacketStream.cpp \ CTCPSocketFactory.cpp \ CProtocolUtil.cpp \ + CClient.cpp \ CServerProtocol.cpp \ CServerProtocol1_0.cpp \ CScreenMap.cpp \ CServer.cpp \ CXWindowsPrimaryScreen.cpp \ + CXWindowsSecondaryScreen.cpp \ XSynergy.cpp \ $(NULL) @@ -37,8 +39,11 @@ LLDLIBS = \ -lpthread \ $(NULL) -targets: server +targets: server client -server: $(OBJECTS) $(DEPLIBS) - $(CXX) $(CXXFLAGS) -o $@ $(OBJECTS) $(LDFLAGS) +server: server.o $(OBJECTS) $(DEPLIBS) + $(CXX) $(CXXFLAGS) -o $@ server.o $(OBJECTS) $(LDFLAGS) + +client: client.o $(OBJECTS) $(DEPLIBS) + $(CXX) $(CXXFLAGS) -o $@ client.o $(OBJECTS) $(LDFLAGS) diff --git a/synergy/client.cpp b/synergy/client.cpp new file mode 100644 index 00000000..b1c3c16b --- /dev/null +++ b/synergy/client.cpp @@ -0,0 +1,21 @@ +#include "CClient.h" +#include "CNetworkAddress.h" +#include + +int main(int argc, char** argv) +{ + if (argc != 2) { + fprintf(stderr, "usage: %s \n", argv[0]); + return 1; + } + + try { + CClient* client = new CClient("ingrid"); + client->run(CNetworkAddress(argv[1], 50001)); + } + catch (XBase& e) { + fprintf(stderr, "failed: %s\n", e.what()); + return 1; + } + return 0; +} diff --git a/synergy/server.cpp b/synergy/server.cpp new file mode 100644 index 00000000..29c8466b --- /dev/null +++ b/synergy/server.cpp @@ -0,0 +1,29 @@ +#include "CServer.h" +#include "CScreenMap.h" +#include + +int main(int argc, char** argv) +{ + if (argc != 1) { + fprintf(stderr, "usage: %s\n", argv[0]); + return 1; + } + + CScreenMap screenMap; + screenMap.addScreen("primary"); + screenMap.addScreen("ingrid"); + screenMap.connect("primary", CScreenMap::kRight, "ingrid"); + screenMap.connect("ingrid", CScreenMap::kLeft, "primary"); + + try { + CServer* server = new CServer(); + server->setScreenMap(screenMap); + server->run(); + } + catch (XBase& e) { + fprintf(stderr, "failed: %s\n", e.what()); + return 1; + } + + return 0; +}