diff --git a/lib/client/CClient.cpp b/lib/client/CClient.cpp index 2238f287..d84ac270 100644 --- a/lib/client/CClient.cpp +++ b/lib/client/CClient.cpp @@ -356,6 +356,18 @@ 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 { diff --git a/lib/client/CClient.h b/lib/client/CClient.h index 664eeb2a..de0818a5 100644 --- a/lib/client/CClient.h +++ b/lib/client/CClient.h @@ -130,6 +130,8 @@ public: virtual void mouseMove(SInt32 xAbs, SInt32 yAbs); virtual void mouseWheel(SInt32 delta); virtual void screensaver(bool activate); + virtual void resetOptions(); + virtual void setOptions(const COptionsList& options); virtual CString getName() const; virtual SInt32 getJumpZoneSize() const; virtual void getShape(SInt32& x, SInt32& y, diff --git a/lib/client/CMSWindowsSecondaryScreen.cpp b/lib/client/CMSWindowsSecondaryScreen.cpp index cba2ba4e..11536616 100644 --- a/lib/client/CMSWindowsSecondaryScreen.cpp +++ b/lib/client/CMSWindowsSecondaryScreen.cpp @@ -214,6 +214,18 @@ CMSWindowsSecondaryScreen::mouseWheel(SInt32 delta) mouse_event(MOUSEEVENTF_WHEEL, 0, 0, delta, 0); } +void +CMSWindowsSecondaryScreen::resetOptions() +{ + // no options +} + +void +CMSWindowsSecondaryScreen::setOptions(const COptionsList& /*options*/) +{ + // no options +} + IScreen* CMSWindowsSecondaryScreen::getScreen() const { diff --git a/lib/client/CMSWindowsSecondaryScreen.h b/lib/client/CMSWindowsSecondaryScreen.h index 83c9db52..0681e236 100644 --- a/lib/client/CMSWindowsSecondaryScreen.h +++ b/lib/client/CMSWindowsSecondaryScreen.h @@ -45,6 +45,8 @@ public: virtual void mouseUp(ButtonID); virtual void mouseMove(SInt32 xAbsolute, SInt32 yAbsolute); virtual void mouseWheel(SInt32 delta); + virtual void resetOptions(); + virtual void setOptions(const COptionsList& options); virtual IScreen* getScreen() const; // IMSWindowsScreenEventHandler overrides diff --git a/lib/client/CSecondaryScreen.cpp b/lib/client/CSecondaryScreen.cpp index 049042f2..554e91db 100644 --- a/lib/client/CSecondaryScreen.cpp +++ b/lib/client/CSecondaryScreen.cpp @@ -87,6 +87,9 @@ CSecondaryScreen::open() // subclass hook onPostOpen(); + + // reset options + resetOptions(); } catch (...) { close(); diff --git a/lib/client/CSecondaryScreen.h b/lib/client/CSecondaryScreen.h index 53d50788..bca229b8 100644 --- a/lib/client/CSecondaryScreen.h +++ b/lib/client/CSecondaryScreen.h @@ -18,6 +18,7 @@ #include "ClipboardTypes.h" #include "KeyTypes.h" #include "MouseTypes.h" +#include "OptionTypes.h" #include "CMutex.h" class IClipboard; @@ -156,6 +157,19 @@ public: */ virtual void mouseWheel(SInt32 delta) = 0; + //! Notify of options changes + /*! + Reset all options to their default values. + */ + virtual void resetOptions() = 0; + + //! Notify of options changes + /*! + Set options to given values. Ignore unknown options and don't + modify our options that aren't given in \c options. + */ + virtual void setOptions(const COptionsList& options) = 0; + //@} //! @name accessors //@{ diff --git a/lib/client/CXWindowsSecondaryScreen.cpp b/lib/client/CXWindowsSecondaryScreen.cpp index ee1cfc0e..996fb445 100644 --- a/lib/client/CXWindowsSecondaryScreen.cpp +++ b/lib/client/CXWindowsSecondaryScreen.cpp @@ -203,6 +203,28 @@ CXWindowsSecondaryScreen::mouseWheel(SInt32 delta) XSync(display, False); } +void +CXWindowsSecondaryScreen::resetOptions() +{ + m_numLockHalfDuplex = false; + m_capsLockHalfDuplex = false; +} + +void +CXWindowsSecondaryScreen::setOptions(const COptionsList& options) +{ + for (UInt32 i = 0, n = options.size(); i < n; i += 2) { + if (options[i] == kOptionHalfDuplexCapsLock) { + m_capsLockHalfDuplex = (options[i + 1] != 0); + LOG((CLOG_DEBUG1 "half-duplex caps-lock %s", m_capsLockHalfDuplex ? "on" : "off")); + } + else if (options[i] == kOptionHalfDuplexNumLock) { + m_numLockHalfDuplex = (options[i + 1] != 0); + LOG((CLOG_DEBUG1 "half-duplex num-lock %s", m_numLockHalfDuplex ? "on" : "off")); + } + } +} + IScreen* CXWindowsSecondaryScreen::getScreen() const { @@ -262,12 +284,7 @@ CXWindowsSecondaryScreen::onPreOpen() void CXWindowsSecondaryScreen::onPostOpen() { - // check for peculiarities - // FIXME -- may have to get these from some database - m_numLockHalfDuplex = false; - m_capsLockHalfDuplex = false; -// m_numLockHalfDuplex = true; -// m_capsLockHalfDuplex = true; + assert(m_window != None); } void diff --git a/lib/client/CXWindowsSecondaryScreen.h b/lib/client/CXWindowsSecondaryScreen.h index 705f401e..ad2403c2 100644 --- a/lib/client/CXWindowsSecondaryScreen.h +++ b/lib/client/CXWindowsSecondaryScreen.h @@ -43,6 +43,8 @@ public: virtual void mouseUp(ButtonID); virtual void mouseMove(SInt32 x, SInt32 y); virtual void mouseWheel(SInt32 delta); + virtual void resetOptions(); + virtual void setOptions(const COptionsList& options); virtual IScreen* getScreen() const; // IScreenEventHandler overrides diff --git a/lib/server/CClientProxy.h b/lib/server/CClientProxy.h index 8890de18..40447a6b 100644 --- a/lib/server/CClientProxy.h +++ b/lib/server/CClientProxy.h @@ -75,6 +75,8 @@ public: virtual void mouseMove(SInt32 xAbs, SInt32 yAbs) = 0; virtual void mouseWheel(SInt32 delta) = 0; virtual void screensaver(bool activate) = 0; + virtual void resetOptions() = 0; + virtual void setOptions(const COptionsList& options) = 0; virtual CString getName() const; virtual SInt32 getJumpZoneSize() const = 0; virtual void getShape(SInt32& x, SInt32& y, diff --git a/lib/server/CClientProxy1_0.cpp b/lib/server/CClientProxy1_0.cpp index b21c8cfc..6ce07a43 100644 --- a/lib/server/CClientProxy1_0.cpp +++ b/lib/server/CClientProxy1_0.cpp @@ -252,6 +252,20 @@ CClientProxy1_0::screensaver(bool on) CProtocolUtil::writef(getOutputStream(), kMsgCScreenSaver, on ? 1 : 0); } +void +CClientProxy1_0::resetOptions() +{ + LOG((CLOG_DEBUG1 "send reset options to \"%s\"", getName().c_str())); + CProtocolUtil::writef(getOutputStream(), kMsgCResetOptions); +} + +void +CClientProxy1_0::setOptions(const COptionsList& options) +{ + LOG((CLOG_DEBUG1 "send set options to \"%s\" size=%d", getName().c_str(), options.size())); + CProtocolUtil::writef(getOutputStream(), kMsgDSetOptions, &options); +} + SInt32 CClientProxy1_0::getJumpZoneSize() const { diff --git a/lib/server/CClientProxy1_0.h b/lib/server/CClientProxy1_0.h index 0c0cb48b..ac94f0f5 100644 --- a/lib/server/CClientProxy1_0.h +++ b/lib/server/CClientProxy1_0.h @@ -46,6 +46,8 @@ public: virtual void mouseMove(SInt32 xAbs, SInt32 yAbs); virtual void mouseWheel(SInt32 delta); virtual void screensaver(bool activate); + virtual void resetOptions(); + virtual void setOptions(const COptionsList& options); virtual SInt32 getJumpZoneSize() const; virtual void getShape(SInt32& x, SInt32& y, SInt32& width, SInt32& height) const; diff --git a/lib/server/CConfig.cpp b/lib/server/CConfig.cpp index 7e706cf4..66a5e94a 100644 --- a/lib/server/CConfig.cpp +++ b/lib/server/CConfig.cpp @@ -240,6 +240,34 @@ CConfig::setHTTPAddress(const CNetworkAddress& addr) m_httpAddress = addr; } +bool +CConfig::addOption(const CString& name, UInt32 option, SInt32 value) +{ + // find cell + CCellMap::iterator index = m_map.find(name); + if (index == m_map.end()) { + return false; + } + + // add option + index->second.m_options.insert(std::make_pair(option, value)); + return true; +} + +bool +CConfig::removeOption(const CString& name, UInt32 option) +{ + // find cell + CCellMap::iterator index = m_map.find(name); + if (index == m_map.end()) { + return false; + } + + // remove option + index->second.m_options.erase(option); + return true; +} + bool CConfig::isValidScreenName(const CString& name) const { @@ -359,6 +387,19 @@ CConfig::getHTTPAddress() const return m_httpAddress; } +const CConfig::CScreenOptions* +CConfig::getOptions(const CString& name) const +{ + // find cell + CCellMap::const_iterator index = m_map.find(name); + if (index == m_map.end()) { + return NULL; + } + + // return options + return &index->second.m_options; +} + bool CConfig::operator==(const CConfig& x) const { @@ -438,6 +479,39 @@ CConfig::readLine(std::istream& s, CString& line) return false; } +bool +CConfig::parseBoolean(const CString& arg) +{ + if (CStringUtil::CaselessCmp::equal(arg, "true")) + return true; + if (CStringUtil::CaselessCmp::equal(arg, "false")) + return false; + throw XConfigRead("invalid argument"); +} + +const char* +CConfig::getOptionName(OptionID id) +{ + if (id == kOptionHalfDuplexCapsLock) { + return "halfDuplexCapsLock"; + } + if (id == kOptionHalfDuplexNumLock) { + return "halfDuplexNumLock"; + } + return NULL; +} + +const char* +CConfig::getOptionValue(OptionID id, OptionValue value) +{ + if (id == kOptionHalfDuplexCapsLock || + id == kOptionHalfDuplexNumLock) { + return (value != 0) ? "true" : "false"; + } + + return ""; +} + void CConfig::readSection(std::istream& s) { @@ -547,7 +621,7 @@ void CConfig::readSectionScreens(std::istream& s) { CString line; - CString name; + CString screen; while (readLine(s, line)) { // check for end of section if (line == "end") { @@ -557,23 +631,54 @@ CConfig::readSectionScreens(std::istream& s) // see if it's the next screen if (line[line.size() - 1] == ':') { // strip : - name = line.substr(0, line.size() - 1); + screen = line.substr(0, line.size() - 1); // verify validity of screen name - if (!isValidScreenName(name)) { + if (!isValidScreenName(screen)) { throw XConfigRead("invalid screen name"); } // add the screen to the configuration - if (!addScreen(name)) { + if (!addScreen(screen)) { throw XConfigRead("duplicate screen name"); } } - else if (name.empty()) { + else if (screen.empty()) { throw XConfigRead("argument before first screen"); } else { - throw XConfigRead("unknown argument"); + // parse argument: `=' + CString::size_type i = line.find_first_of(" \t="); + if (i == 0) { + throw XConfigRead("missing argument name"); + } + if (i == CString::npos) { + throw XConfigRead("missing = in argument"); + } + CString name = line.substr(0, i); + i = line.find_first_not_of(" \t", i); + if (i == CString::npos || line[i] != '=') { + throw XConfigRead("missing = in argument"); + } + i = line.find_first_not_of(" \t", i + 1); + CString value; + if (i != CString::npos) { + value = line.substr(i); + } + + // handle argument + if (name == "halfDuplexCapsLock") { + addOption(screen, kOptionHalfDuplexCapsLock, + parseBoolean(value)); + } + else if (name == "halfDuplexNumLock") { + addOption(screen, kOptionHalfDuplexNumLock, + parseBoolean(value)); + } + else { + // unknown argument + throw XConfigRead("unknown argument"); + } } } throw XConfigRead("unexpected end of screens section"); @@ -740,6 +845,19 @@ operator<<(std::ostream& s, const CConfig& config) for (CConfig::const_iterator screen = config.begin(); screen != config.end(); ++screen) { s << "\t" << screen->c_str() << ":" << std::endl; + const CConfig::CScreenOptions* options = config.getOptions(*screen); + if (options != NULL && options->size() > 0) { + for (CConfig::CScreenOptions::const_iterator + option = options->begin(); + option != options->end(); ++option) { + const char* name = CConfig::getOptionName(option->first); + const char* value = CConfig::getOptionValue(option->first, + option->second); + if (name != NULL && value != NULL) { + s << "\t\t" << name << " = " << value << std::endl; + } + } + } } s << "end" << std::endl; diff --git a/lib/server/CConfig.h b/lib/server/CConfig.h index c028ebf5..6fce3dda 100644 --- a/lib/server/CConfig.h +++ b/lib/server/CConfig.h @@ -15,6 +15,7 @@ #ifndef CCONFIG_H #define CCONFIG_H +#include "OptionTypes.h" #include "ProtocolTypes.h" #include "CNetworkAddress.h" #include "XBase.h" @@ -45,10 +46,14 @@ comparing names. Screen names and their aliases share a namespace and must be unique. */ class CConfig { +public: + typedef std::map CScreenOptions; + private: class CCell { public: CString m_neighbor[kLastDirection - kFirstDirection + 1]; + CScreenOptions m_options; }; typedef std::map CCellMap; typedef std::map CNameMap; @@ -175,6 +180,23 @@ public: */ void setHTTPAddress(const CNetworkAddress&); + //! Add a screen option + /*! + Adds an option and its value to the named screen. Replaces the + existing option's value if there is one. Returns true iff \c name + is a known screen. + */ + bool addOption(const CString& name, + UInt32 option, SInt32 value); + + //! Remove a screen option + /*! + Removes an option and its value from the named screen. Does + nothing if the option doesn't exist on the screen. Returns true + iff \c name is a known screen. + */ + bool removeOption(const CString& name, UInt32 option); + //@} //! @name accessors //@{ @@ -227,6 +249,14 @@ public: //! Get the HTTP server address const CNetworkAddress& getHTTPAddress() const; + //! Get the screen options + /*! + Returns all the added options for the named screen. Returns NULL + if the screen is unknown and an empty collection if there are no + options. + */ + const CScreenOptions* getOptions(const CString& name) const; + //! Compare configurations bool operator==(const CConfig&) const; //! Compare configurations @@ -254,6 +284,9 @@ public: private: static bool readLine(std::istream&, CString&); + static bool parseBoolean(const CString&); + static const char* getOptionName(OptionID); + static const char* getOptionValue(OptionID, OptionValue); void readSection(std::istream&); void readSectionNetwork(std::istream&); void readSectionScreens(std::istream&); diff --git a/lib/server/CMSWindowsPrimaryScreen.cpp b/lib/server/CMSWindowsPrimaryScreen.cpp index d6b96cc6..6a28a092 100644 --- a/lib/server/CMSWindowsPrimaryScreen.cpp +++ b/lib/server/CMSWindowsPrimaryScreen.cpp @@ -99,6 +99,18 @@ CMSWindowsPrimaryScreen::warpCursor(SInt32 x, SInt32 y) m_y = y; } +void +CMSWindowsPrimaryScreen::resetOptions() +{ + // no options +} + +void +CMSWindowsPrimaryScreen::setOptions(const COptionsList& /*options*/) +{ + // no options +} + KeyModifierMask CMSWindowsPrimaryScreen::getToggleMask() const { diff --git a/lib/server/CMSWindowsPrimaryScreen.h b/lib/server/CMSWindowsPrimaryScreen.h index f443f1e8..91dc2b11 100644 --- a/lib/server/CMSWindowsPrimaryScreen.h +++ b/lib/server/CMSWindowsPrimaryScreen.h @@ -37,6 +37,8 @@ public: // CPrimaryScreen overrides virtual void reconfigure(UInt32 activeSides); virtual void warpCursor(SInt32 x, SInt32 y); + virtual void resetOptions(); + virtual void setOptions(const COptionsList& options); virtual KeyModifierMask getToggleMask() const; virtual bool isLockedToScreen() const; virtual IScreen* getScreen() const; diff --git a/lib/server/CPrimaryClient.cpp b/lib/server/CPrimaryClient.cpp index 47279c5c..ca7d37d8 100644 --- a/lib/server/CPrimaryClient.cpp +++ b/lib/server/CPrimaryClient.cpp @@ -242,6 +242,18 @@ CPrimaryClient::screensaver(bool) // ignore } +void +CPrimaryClient::resetOptions() +{ + m_screen->resetOptions(); +} + +void +CPrimaryClient::setOptions(const COptionsList& options) +{ + m_screen->setOptions(options); +} + CString CPrimaryClient::getName() const { diff --git a/lib/server/CPrimaryClient.h b/lib/server/CPrimaryClient.h index 10f744a6..5cd0c259 100644 --- a/lib/server/CPrimaryClient.h +++ b/lib/server/CPrimaryClient.h @@ -108,6 +108,8 @@ public: virtual void mouseMove(SInt32 xAbs, SInt32 yAbs); virtual void mouseWheel(SInt32 delta); virtual void screensaver(bool activate); + virtual void resetOptions(); + virtual void setOptions(const COptionsList& options); virtual CString getName() const; virtual SInt32 getJumpZoneSize() const; virtual void getShape(SInt32& x, SInt32& y, diff --git a/lib/server/CPrimaryScreen.cpp b/lib/server/CPrimaryScreen.cpp index a9cd4297..e2b743d7 100644 --- a/lib/server/CPrimaryScreen.cpp +++ b/lib/server/CPrimaryScreen.cpp @@ -90,6 +90,9 @@ CPrimaryScreen::open() // subclass hook onPostOpen(); + + // reset options + resetOptions(); } catch (...) { close(); diff --git a/lib/server/CPrimaryScreen.h b/lib/server/CPrimaryScreen.h index 089c6eab..2e953c25 100644 --- a/lib/server/CPrimaryScreen.h +++ b/lib/server/CPrimaryScreen.h @@ -17,6 +17,7 @@ #include "ClipboardTypes.h" #include "KeyTypes.h" +#include "OptionTypes.h" #include "CMutex.h" class IClipboard; @@ -115,6 +116,19 @@ public: */ void grabClipboard(ClipboardID); + //! Notify of options changes + /*! + Reset all options to their default values. + */ + virtual void resetOptions() = 0; + + //! Notify of options changes + /*! + Set options to given values. Ignore unknown options and don't + modify our options that aren't given in \c options. + */ + virtual void setOptions(const COptionsList& options) = 0; + //@} //! @name accessors //@{ diff --git a/lib/server/CServer.cpp b/lib/server/CServer.cpp index aede8ca9..78d1c633 100644 --- a/lib/server/CServer.cpp +++ b/lib/server/CServer.cpp @@ -20,6 +20,7 @@ #include "COutputPacketStream.h" #include "CProtocolUtil.h" #include "CClientProxy1_0.h" +#include "OptionTypes.h" #include "ProtocolTypes.h" #include "XScreen.h" #include "XSynergy.h" @@ -220,6 +221,8 @@ CServer::setConfig(const CConfig& config) m_primaryClient->reconfigure(getActivePrimarySides()); } + // FIXME -- tell all (connected) clients about current options + return true; } @@ -830,6 +833,8 @@ CServer::switchScreen(IClient* dst, SInt32 x, SInt32 y, bool forScreensaver) IClient* CServer::getNeighbor(IClient* src, EDirection dir) const { + // note -- must be locked on entry + assert(src != NULL); CString srcName = src->getName(); @@ -863,6 +868,8 @@ IClient* CServer::getNeighbor(IClient* src, EDirection srcSide, SInt32& x, SInt32& y) const { + // note -- must be locked on entry + assert(src != NULL); // get the first neighbor @@ -1274,6 +1281,9 @@ CServer::runClient(void* vsocket) CLock lock(&m_mutex); m_clientThreads.insert(std::make_pair(proxy->getName(), CThread::getCurrentThread())); + + // send configuration options + sendOptions(proxy); } catch (XDuplicateClient& e) { // client has duplicate name @@ -1564,6 +1574,32 @@ CServer::processHTTPRequest(void* vsocket) } } +void +CServer::sendOptions(IClient* client) const +{ + // note -- must be locked on entry + + // look up options for client. we're done if there aren't any. + const CConfig::CScreenOptions* options = + m_config.getOptions(client->getName()); + if (options == NULL) { + return; + } + + // convert options to a more convenient form for sending + COptionsList optionsList; + optionsList.reserve(2 * options->size()); + for (CConfig::CScreenOptions::const_iterator index = options->begin(); + index != options->end(); ++index) { + optionsList.push_back(index->first); + optionsList.push_back(static_cast(index->second)); + } + + // send the options + client->resetOptions(); + client->setOptions(optionsList); +} + void CServer::openPrimaryScreen() { @@ -1605,8 +1641,13 @@ CServer::openPrimaryScreen() // tell it about the active sides m_primaryClient->reconfigure(getActivePrimarySides()); + + // tell primary client about its options + sendOptions(m_primaryClient); } catch (...) { + // if m_active is NULL then we haven't added the connection + // for the primary client so we don't try to remove it. if (m_active != NULL) { removeConnection(primaryName); } diff --git a/lib/server/CServer.h b/lib/server/CServer.h index 49583c6e..885d0e08 100644 --- a/lib/server/CServer.h +++ b/lib/server/CServer.h @@ -197,6 +197,9 @@ private: IClient* getNeighbor(IClient*, EDirection, SInt32& x, SInt32& y) const; + // send screen options to \c client + void sendOptions(IClient* client) const; + // open/close the primary screen void openPrimaryScreen(); void closePrimaryScreen(); diff --git a/lib/server/CXWindowsPrimaryScreen.cpp b/lib/server/CXWindowsPrimaryScreen.cpp index 06452696..b544235b 100644 --- a/lib/server/CXWindowsPrimaryScreen.cpp +++ b/lib/server/CXWindowsPrimaryScreen.cpp @@ -79,6 +79,28 @@ CXWindowsPrimaryScreen::warpCursor(SInt32 x, SInt32 y) m_y = y; } +void +CXWindowsPrimaryScreen::resetOptions() +{ + m_numLockHalfDuplex = false; + m_capsLockHalfDuplex = false; +} + +void +CXWindowsPrimaryScreen::setOptions(const COptionsList& options) +{ + for (UInt32 i = 0, n = options.size(); i < n; i += 2) { + if (options[i] == kOptionHalfDuplexCapsLock) { + m_capsLockHalfDuplex = (options[i + 1] != 0); + LOG((CLOG_DEBUG1 "half-duplex caps-lock %s", m_capsLockHalfDuplex ? "on" : "off")); + } + else if (options[i] == kOptionHalfDuplexNumLock) { + m_numLockHalfDuplex = (options[i + 1] != 0); + LOG((CLOG_DEBUG1 "half-duplex num-lock %s", m_numLockHalfDuplex ? "on" : "off")); + } + } +} + KeyModifierMask CXWindowsPrimaryScreen::getToggleMask() const { @@ -385,16 +407,11 @@ CXWindowsPrimaryScreen::onPreOpen() void CXWindowsPrimaryScreen::onPostOpen() { + assert(m_window != None); + // get cursor info m_screen->getCursorPos(m_x, m_y); m_screen->getCursorCenter(m_xCenter, m_yCenter); - - // check for peculiarities - // FIXME -- may have to get these from some database - m_numLockHalfDuplex = false; - m_capsLockHalfDuplex = false; -// m_numLockHalfDuplex = true; -// m_capsLockHalfDuplex = true; } void diff --git a/lib/server/CXWindowsPrimaryScreen.h b/lib/server/CXWindowsPrimaryScreen.h index b67f3009..c24464b8 100644 --- a/lib/server/CXWindowsPrimaryScreen.h +++ b/lib/server/CXWindowsPrimaryScreen.h @@ -38,6 +38,8 @@ public: // CPrimaryScreen overrides virtual void reconfigure(UInt32 activeSides); virtual void warpCursor(SInt32 x, SInt32 y); + virtual void resetOptions(); + virtual void setOptions(const COptionsList& options); virtual KeyModifierMask getToggleMask() const; virtual bool isLockedToScreen() const; virtual IScreen* getScreen() const; diff --git a/lib/synergy/CProtocolUtil.cpp b/lib/synergy/CProtocolUtil.cpp index c68b9a7e..41dff388 100644 --- a/lib/synergy/CProtocolUtil.cpp +++ b/lib/synergy/CProtocolUtil.cpp @@ -16,6 +16,7 @@ #include "IInputStream.h" #include "IOutputStream.h" #include "CLog.h" +#include "stdvector.h" #include #include @@ -116,6 +117,56 @@ CProtocolUtil::readf(IInputStream* stream, const char* fmt, ...) break; } + case 'I': { + // check for valid length + assert(len == 1 || len == 2 || len == 4); + + // read the vector length + UInt8 buffer[4]; + read(stream, buffer, 4); + UInt32 len = (static_cast(buffer[0]) << 24) | + (static_cast(buffer[1]) << 16) | + (static_cast(buffer[2]) << 8) | + static_cast(buffer[3]); + + // convert it + void* v = va_arg(args, void*); + switch (len) { + case 1: + // 1 byte integer + for (UInt32 i = 0; i < len; ++i) { + reinterpret_cast*>(v)->push_back( + buffer[0]); + LOG((CLOG_DEBUG2 "readf: read %d byte integer[%d]: %d (0x%x)", len, i, reinterpret_cast*>(v)->back(), reinterpret_cast*>(v)->back())); + } + break; + + case 2: + // 2 byte integer + for (UInt32 i = 0; i < len; ++i) { + reinterpret_cast*>(v)->push_back( + static_cast( + (static_cast(buffer[0]) << 8) | + static_cast(buffer[1]))); + LOG((CLOG_DEBUG2 "readf: read %d byte integer[%d]: %d (0x%x)", len, i, reinterpret_cast*>(v)->back(), reinterpret_cast*>(v)->back())); + } + break; + + case 4: + // 4 byte integer + for (UInt32 i = 0; i < len; ++i) { + reinterpret_cast*>(v)->push_back( + (static_cast(buffer[0]) << 24) | + (static_cast(buffer[1]) << 16) | + (static_cast(buffer[2]) << 8) | + static_cast(buffer[3])); + LOG((CLOG_DEBUG2 "readf: read %d byte integer[%d]: %d (0x%x)", len, i, reinterpret_cast*>(v)->back(), reinterpret_cast*>(v)->back())); + } + break; + } + break; + } + case 's': { assert(len == 0); @@ -207,6 +258,24 @@ CProtocolUtil::getLength(const char* fmt, va_list args) (void)va_arg(args, UInt32); break; + case 'I': + assert(len == 1 || len == 2 || len == 4); + switch (len) { + case 1: + len = (va_arg(args, std::vector*))->size() + 4; + break; + + case 2: + len = 2 * (va_arg(args, std::vector*))->size() + 4; + break; + + case 4: + len = 4 * (va_arg(args, std::vector*))->size() + 4; + break; + } + (void)va_arg(args, void*); + break; + case 's': assert(len == 0); len = (va_arg(args, CString*))->size() + 4; @@ -281,6 +350,52 @@ CProtocolUtil::writef(void* buffer, const char* fmt, va_list args) break; } + case 'I': { + const UInt32 v = va_arg(args, UInt32); + switch (len) { + case 1: { + // 1 byte integers + const std::vector* list = + va_arg(args, const std::vector*); + for (UInt32 i = 0, n = list->size(); i < n; ++i) { + *dst++ = (*list)[i]; + } + break; + } + + case 2: { + // 2 byte integers + const std::vector* list = + va_arg(args, const std::vector*); + for (UInt32 i = 0, n = list->size(); i < n; ++i) { + const UInt16 v = (*list)[i]; + *dst++ = static_cast((v >> 8) & 0xff); + *dst++ = static_cast( v & 0xff); + } + break; + } + + case 4: { + // 4 byte integers + const std::vector* list = + va_arg(args, const std::vector*); + for (UInt32 i = 0, n = list->size(); i < n; ++i) { + const UInt32 v = (*list)[i]; + *dst++ = static_cast((v >> 24) & 0xff); + *dst++ = static_cast((v >> 16) & 0xff); + *dst++ = static_cast((v >> 8) & 0xff); + *dst++ = static_cast( v & 0xff); + } + break; + } + + default: + assert(0 && "invalid integer vector format length"); + return; + } + break; + } + case 's': { assert(len == 0); const CString* src = va_arg(args, CString*); diff --git a/lib/synergy/CProtocolUtil.h b/lib/synergy/CProtocolUtil.h index 9228a132..1e0db39f 100644 --- a/lib/synergy/CProtocolUtil.h +++ b/lib/synergy/CProtocolUtil.h @@ -41,6 +41,9 @@ public: - \%1i -- converts integer argument to 1 byte integer - \%2i -- converts integer argument to 2 byte integer in NBO - \%4i -- converts integer argument to 4 byte integer in NBO + - \%1I -- converts std::vector* to 1 byte integers + - \%2I -- converts std::vector* to 2 byte integers in NBO + - \%4I -- converts std::vector* to 4 byte integers in NBO - \%s -- converts CString* to stream of bytes - \%S -- converts integer N and const UInt8* to stream of N bytes */ @@ -57,6 +60,9 @@ public: - \%1i -- reads a 1 byte integer; argument is a SInt32* or UInt32* - \%2i -- reads an NBO 2 byte integer; arg is SInt32* or UInt32* - \%4i -- reads an NBO 4 byte integer; arg is SInt32* or UInt32* + - \%1I -- reads 1 byte integers; arg is std::vector* + - \%2I -- reads NBO 2 byte integers; arg is std::vector* + - \%4I -- reads NBO 4 byte integers; arg is std::vector* - \%s -- reads bytes; argument must be a CString*, \b not a char* */ static void readf(IInputStream*, diff --git a/lib/synergy/IClient.h b/lib/synergy/IClient.h index 5031bcbc..18804bce 100644 --- a/lib/synergy/IClient.h +++ b/lib/synergy/IClient.h @@ -19,6 +19,7 @@ #include "ClipboardTypes.h" #include "KeyTypes.h" #include "MouseTypes.h" +#include "OptionTypes.h" #include "CString.h" //! Client interface @@ -151,6 +152,19 @@ public: //! Notify of screen saver change virtual void screensaver(bool activate) = 0; + //! Notify of options changes + /*! + Reset all options to their default values. + */ + virtual void resetOptions() = 0; + + //! Notify of options changes + /*! + Set options to given values. Ignore unknown options and don't + modify our options that aren't given in \c options. + */ + virtual void setOptions(const COptionsList& options) = 0; + //@} //! @name accessors //@{ diff --git a/lib/synergy/Makefile.am b/lib/synergy/Makefile.am index 2661667c..f7e5d64c 100644 --- a/lib/synergy/Makefile.am +++ b/lib/synergy/Makefile.am @@ -46,6 +46,7 @@ libsynergy_a_SOURCES = \ IServer.h \ KeyTypes.h \ MouseTypes.h \ + OptionTypes.h \ ProtocolTypes.h \ XScreen.h \ XSynergy.h \ diff --git a/lib/synergy/OptionTypes.h b/lib/synergy/OptionTypes.h new file mode 100644 index 00000000..3310ace0 --- /dev/null +++ b/lib/synergy/OptionTypes.h @@ -0,0 +1,52 @@ +/* + * 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 OPTIONTYPES_H +#define OPTIONTYPES_H + +#include "BasicTypes.h" +#include "stdvector.h" + +//! Option ID +/*! +Type to hold an option identifier. +*/ +typedef UInt32 OptionID; + +//! Option Value +/*! +Type to hold an option value. +*/ +typedef SInt32 OptionValue; + +// for now, options are just pairs of integers +typedef std::vector COptionsList; + +// macro for packing 4 character strings into 4 byte integers +#define OPTION_CODE(_s) \ + (static_cast(static_cast(_s[0]) << 24) | \ + static_cast(static_cast(_s[1]) << 16) | \ + static_cast(static_cast(_s[2]) << 8) | \ + static_cast(static_cast(_s[3]) )) + +//! @name Option identifiers +//@{ +static const OptionID kOptionHalfDuplexCapsLock = OPTION_CODE("HDCL"); +static const OptionID kOptionHalfDuplexNumLock = OPTION_CODE("HDNL"); +static const OptionID kOptionHalfDuplexScrollLock = OPTION_CODE("HDSL"); +//@} + +#undef OPTION_CODE + +#endif diff --git a/lib/synergy/ProtocolTypes.h b/lib/synergy/ProtocolTypes.h index 53b6bd1e..52201320 100644 --- a/lib/synergy/ProtocolTypes.h +++ b/lib/synergy/ProtocolTypes.h @@ -118,6 +118,10 @@ static const char kMsgCClipboard[] = "CCLP%1i%4i"; // screensaver on primary has started ($1 == 1) or closed ($1 == 0) static const char kMsgCScreenSaver[] = "CSEC%1i"; +// reset options: primary -> secondary +// client should reset all of its options to their defaults. +static const char kMsgCResetOptions[] = "CROP"; + // resolution change acknowledgment: primary -> secondary // sent by primary in response to a secondary screen's kMsgDInfo. // this is sent for every kMsgDInfo, whether or not the primary @@ -181,6 +185,11 @@ static const char kMsgDClipboard[] = "DCLP%1i%4i%s"; // the new screen area. static const char kMsgDInfo[] = "DINF%2i%2i%2i%2i%2i%2i%2i"; +// set options: primary -> secondary +// client should set the given option/value pairs. $1 = option/value +// pairs. +static const char kMsgDSetOptions[] = "DSOP%4I"; + // // query codes