00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "CConfig.h"
00020 #include "CServer.h"
00021 #include "CKeyMap.h"
00022 #include "KeyTypes.h"
00023 #include "XSocket.h"
00024 #include "stdistream.h"
00025 #include "stdostream.h"
00026 #include <cstdlib>
00027
00028
00029
00030
00031
00032 CConfig::CConfig() : m_hasLockToScreenAction(false)
00033 {
00034
00035 }
00036
00037 CConfig::~CConfig()
00038 {
00039
00040 }
00041
00042 bool
00043 CConfig::addScreen(const CString& name)
00044 {
00045
00046 if (m_nameToCanonicalName.find(name) != m_nameToCanonicalName.end()) {
00047 return false;
00048 }
00049
00050
00051 m_map.insert(std::make_pair(name, CCell()));
00052
00053
00054 m_nameToCanonicalName.insert(std::make_pair(name, name));
00055
00056 return true;
00057 }
00058
00059 bool
00060 CConfig::renameScreen(const CString& oldName,
00061 const CString& newName)
00062 {
00063
00064 CString oldCanonical = getCanonicalName(oldName);
00065 CCellMap::iterator index = m_map.find(oldCanonical);
00066 if (index == m_map.end()) {
00067 return false;
00068 }
00069
00070
00071
00072 if (!CStringUtil::CaselessCmp::equal(oldName, newName) &&
00073 m_nameToCanonicalName.find(newName) != m_nameToCanonicalName.end()) {
00074 return false;
00075 }
00076
00077
00078 CCell tmpCell = index->second;
00079 m_map.erase(index);
00080 m_map.insert(std::make_pair(newName, tmpCell));
00081
00082
00083 m_nameToCanonicalName.erase(oldCanonical);
00084 m_nameToCanonicalName.insert(std::make_pair(newName, newName));
00085
00086
00087 CName oldNameObj(this, oldName);
00088 for (index = m_map.begin(); index != m_map.end(); ++index) {
00089 index->second.rename(oldNameObj, newName);
00090 }
00091
00092
00093 if (CStringUtil::CaselessCmp::equal(oldName, oldCanonical)) {
00094 for (CNameMap::iterator iter = m_nameToCanonicalName.begin();
00095 iter != m_nameToCanonicalName.end(); ++iter) {
00096 if (CStringUtil::CaselessCmp::equal(
00097 iter->second, oldCanonical)) {
00098 iter->second = newName;
00099 }
00100 }
00101 }
00102
00103 return true;
00104 }
00105
00106 void
00107 CConfig::removeScreen(const CString& name)
00108 {
00109
00110 CString canonical = getCanonicalName(name);
00111 CCellMap::iterator index = m_map.find(canonical);
00112 if (index == m_map.end()) {
00113 return;
00114 }
00115
00116
00117 m_map.erase(index);
00118
00119
00120 CName nameObj(this, name);
00121 for (index = m_map.begin(); index != m_map.end(); ++index) {
00122 index->second.remove(nameObj);
00123 }
00124
00125
00126 for (CNameMap::iterator iter = m_nameToCanonicalName.begin();
00127 iter != m_nameToCanonicalName.end(); ) {
00128 if (iter->second == canonical) {
00129 m_nameToCanonicalName.erase(iter++);
00130 }
00131 else {
00132 ++index;
00133 }
00134 }
00135 }
00136
00137 void
00138 CConfig::removeAllScreens()
00139 {
00140 m_map.clear();
00141 m_nameToCanonicalName.clear();
00142 }
00143
00144 bool
00145 CConfig::addAlias(const CString& canonical, const CString& alias)
00146 {
00147
00148 if (m_nameToCanonicalName.find(alias) != m_nameToCanonicalName.end()) {
00149 return false;
00150 }
00151
00152
00153 if (m_map.find(canonical) == m_map.end()) {
00154 return false;
00155 }
00156
00157
00158 m_nameToCanonicalName.insert(std::make_pair(alias, canonical));
00159
00160 return true;
00161 }
00162
00163 bool
00164 CConfig::removeAlias(const CString& alias)
00165 {
00166
00167 if (m_map.find(alias) != m_map.end()) {
00168 return false;
00169 }
00170
00171
00172 CNameMap::iterator index = m_nameToCanonicalName.find(alias);
00173 if (index == m_nameToCanonicalName.end()) {
00174 return false;
00175 }
00176
00177
00178 m_nameToCanonicalName.erase(index);
00179
00180 return true;
00181 }
00182
00183 bool
00184 CConfig::removeAliases(const CString& canonical)
00185 {
00186
00187 if (m_map.find(canonical) == m_map.end()) {
00188 return false;
00189 }
00190
00191
00192 for (CNameMap::iterator index = m_nameToCanonicalName.begin();
00193 index != m_nameToCanonicalName.end(); ) {
00194 if (index->second == canonical && index->first != canonical) {
00195 m_nameToCanonicalName.erase(index++);
00196 }
00197 else {
00198 ++index;
00199 }
00200 }
00201
00202 return true;
00203 }
00204
00205 void
00206 CConfig::removeAllAliases()
00207 {
00208
00209 m_nameToCanonicalName.clear();
00210
00211
00212 for (CCellMap::iterator index = m_map.begin();
00213 index != m_map.end(); ++index) {
00214 m_nameToCanonicalName.insert(
00215 std::make_pair(index->first, index->first));
00216 }
00217 }
00218
00219 bool
00220 CConfig::connect(const CString& srcName,
00221 EDirection srcSide,
00222 float srcStart, float srcEnd,
00223 const CString& dstName,
00224 float dstStart, float dstEnd)
00225 {
00226 assert(srcSide >= kFirstDirection && srcSide <= kLastDirection);
00227
00228
00229 CCellMap::iterator index = m_map.find(getCanonicalName(srcName));
00230 if (index == m_map.end()) {
00231 return false;
00232 }
00233
00234
00235 CCellEdge srcEdge(srcSide, CInterval(srcStart, srcEnd));
00236 CCellEdge dstEdge(dstName, srcSide, CInterval(dstStart, dstEnd));
00237 return index->second.add(srcEdge, dstEdge);
00238 }
00239
00240 bool
00241 CConfig::disconnect(const CString& srcName, EDirection srcSide)
00242 {
00243 assert(srcSide >= kFirstDirection && srcSide <= kLastDirection);
00244
00245
00246 CCellMap::iterator index = m_map.find(srcName);
00247 if (index == m_map.end()) {
00248 return false;
00249 }
00250
00251
00252 index->second.remove(srcSide);
00253
00254 return true;
00255 }
00256
00257 bool
00258 CConfig::disconnect(const CString& srcName, EDirection srcSide, float position)
00259 {
00260 assert(srcSide >= kFirstDirection && srcSide <= kLastDirection);
00261
00262
00263 CCellMap::iterator index = m_map.find(srcName);
00264 if (index == m_map.end()) {
00265 return false;
00266 }
00267
00268
00269 index->second.remove(srcSide, position);
00270
00271 return true;
00272 }
00273
00274 void
00275 CConfig::setSynergyAddress(const CNetworkAddress& addr)
00276 {
00277 m_synergyAddress = addr;
00278 }
00279
00280 bool
00281 CConfig::addOption(const CString& name, OptionID option, OptionValue value)
00282 {
00283
00284 CScreenOptions* options = NULL;
00285 if (name.empty()) {
00286 options = &m_globalOptions;
00287 }
00288 else {
00289 CCellMap::iterator index = m_map.find(name);
00290 if (index != m_map.end()) {
00291 options = &index->second.m_options;
00292 }
00293 }
00294 if (options == NULL) {
00295 return false;
00296 }
00297
00298
00299 options->insert(std::make_pair(option, value));
00300 return true;
00301 }
00302
00303 bool
00304 CConfig::removeOption(const CString& name, OptionID option)
00305 {
00306
00307 CScreenOptions* options = NULL;
00308 if (name.empty()) {
00309 options = &m_globalOptions;
00310 }
00311 else {
00312 CCellMap::iterator index = m_map.find(name);
00313 if (index != m_map.end()) {
00314 options = &index->second.m_options;
00315 }
00316 }
00317 if (options == NULL) {
00318 return false;
00319 }
00320
00321
00322 options->erase(option);
00323 return true;
00324 }
00325
00326 bool
00327 CConfig::removeOptions(const CString& name)
00328 {
00329
00330 CScreenOptions* options = NULL;
00331 if (name.empty()) {
00332 options = &m_globalOptions;
00333 }
00334 else {
00335 CCellMap::iterator index = m_map.find(name);
00336 if (index != m_map.end()) {
00337 options = &index->second.m_options;
00338 }
00339 }
00340 if (options == NULL) {
00341 return false;
00342 }
00343
00344
00345 options->clear();
00346 return true;
00347 }
00348
00349 bool
00350 CConfig::isValidScreenName(const CString& name) const
00351 {
00352
00353
00354
00355
00356
00357
00358
00359
00360 if (name.empty()) {
00361 return false;
00362 }
00363
00364
00365 CString::size_type b = 0;
00366 for (;;) {
00367
00368 if (b == name.size()) {
00369 break;
00370 }
00371
00372
00373 CString::size_type e = name.find('.', b);
00374 if (e == CString::npos) {
00375 e = name.size();
00376 }
00377
00378
00379 if (e - b < 1) {
00380 return false;
00381 }
00382
00383
00384 if (!(isalnum(name[b]) || name[b] == '_') ||
00385 !(isalnum(name[e - 1]) || name[e - 1] == '_')) {
00386 return false;
00387 }
00388
00389
00390 for (CString::size_type i = b; i < e; ++i) {
00391 if (!isalnum(name[i]) && name[i] != '_' && name[i] != '-') {
00392 return false;
00393 }
00394 }
00395
00396
00397 if (e == name.size()) {
00398
00399 break;
00400 }
00401 b = e + 1;
00402 }
00403
00404 return true;
00405 }
00406
00407 CConfig::const_iterator
00408 CConfig::begin() const
00409 {
00410 return const_iterator(m_map.begin());
00411 }
00412
00413 CConfig::const_iterator
00414 CConfig::end() const
00415 {
00416 return const_iterator(m_map.end());
00417 }
00418
00419 CConfig::all_const_iterator
00420 CConfig::beginAll() const
00421 {
00422 return m_nameToCanonicalName.begin();
00423 }
00424
00425 CConfig::all_const_iterator
00426 CConfig::endAll() const
00427 {
00428 return m_nameToCanonicalName.end();
00429 }
00430
00431 bool
00432 CConfig::isScreen(const CString& name) const
00433 {
00434 return (m_nameToCanonicalName.count(name) > 0);
00435 }
00436
00437 bool
00438 CConfig::isCanonicalName(const CString& name) const
00439 {
00440 return (!name.empty() &&
00441 CStringUtil::CaselessCmp::equal(getCanonicalName(name), name));
00442 }
00443
00444 CString
00445 CConfig::getCanonicalName(const CString& name) const
00446 {
00447 CNameMap::const_iterator index = m_nameToCanonicalName.find(name);
00448 if (index == m_nameToCanonicalName.end()) {
00449 return CString();
00450 }
00451 else {
00452 return index->second;
00453 }
00454 }
00455
00456 CString
00457 CConfig::getNeighbor(const CString& srcName, EDirection srcSide,
00458 float position, float* positionOut) const
00459 {
00460 assert(srcSide >= kFirstDirection && srcSide <= kLastDirection);
00461
00462
00463 CCellMap::const_iterator index = m_map.find(getCanonicalName(srcName));
00464 if (index == m_map.end()) {
00465 return CString();
00466 }
00467
00468
00469 const CCellEdge* srcEdge, *dstEdge;
00470 if (!index->second.getLink(srcSide, position, srcEdge, dstEdge)) {
00471
00472 return "";
00473 }
00474 else {
00475
00476 if (positionOut != NULL) {
00477 *positionOut =
00478 dstEdge->inverseTransform(srcEdge->transform(position));
00479 }
00480
00481
00482 return getCanonicalName(dstEdge->getName());
00483 }
00484 }
00485
00486 bool
00487 CConfig::hasNeighbor(const CString& srcName, EDirection srcSide) const
00488 {
00489 return hasNeighbor(srcName, srcSide, 0.0f, 1.0f);
00490 }
00491
00492 bool
00493 CConfig::hasNeighbor(const CString& srcName, EDirection srcSide,
00494 float start, float end) const
00495 {
00496 assert(srcSide >= kFirstDirection && srcSide <= kLastDirection);
00497
00498
00499 CCellMap::const_iterator index = m_map.find(getCanonicalName(srcName));
00500 if (index == m_map.end()) {
00501 return false;
00502 }
00503
00504 return index->second.overlaps(CCellEdge(srcSide, CInterval(start, end)));
00505 }
00506
00507 CConfig::link_const_iterator
00508 CConfig::beginNeighbor(const CString& srcName) const
00509 {
00510 CCellMap::const_iterator index = m_map.find(getCanonicalName(srcName));
00511 assert(index != m_map.end());
00512 return index->second.begin();
00513 }
00514
00515 CConfig::link_const_iterator
00516 CConfig::endNeighbor(const CString& srcName) const
00517 {
00518 CCellMap::const_iterator index = m_map.find(getCanonicalName(srcName));
00519 assert(index != m_map.end());
00520 return index->second.end();
00521 }
00522
00523 const CNetworkAddress&
00524 CConfig::getSynergyAddress() const
00525 {
00526 return m_synergyAddress;
00527 }
00528
00529 const CConfig::CScreenOptions*
00530 CConfig::getOptions(const CString& name) const
00531 {
00532
00533 const CScreenOptions* options = NULL;
00534 if (name.empty()) {
00535 options = &m_globalOptions;
00536 }
00537 else {
00538 CCellMap::const_iterator index = m_map.find(name);
00539 if (index != m_map.end()) {
00540 options = &index->second.m_options;
00541 }
00542 }
00543
00544
00545 return options;
00546 }
00547
00548 bool
00549 CConfig::hasLockToScreenAction() const
00550 {
00551 return m_hasLockToScreenAction;
00552 }
00553
00554 bool
00555 CConfig::operator==(const CConfig& x) const
00556 {
00557 if (m_synergyAddress != x.m_synergyAddress) {
00558 return false;
00559 }
00560 if (m_map.size() != x.m_map.size()) {
00561 return false;
00562 }
00563 if (m_nameToCanonicalName.size() != x.m_nameToCanonicalName.size()) {
00564 return false;
00565 }
00566
00567
00568 if (m_globalOptions != x.m_globalOptions) {
00569 return false;
00570 }
00571
00572 for (CCellMap::const_iterator index1 = m_map.begin(),
00573 index2 = x.m_map.begin();
00574 index1 != m_map.end(); ++index1, ++index2) {
00575
00576 if (!CStringUtil::CaselessCmp::equal(index1->first, index2->first)) {
00577 return false;
00578 }
00579
00580
00581 if (index1->second != index2->second) {
00582 return false;
00583 }
00584 }
00585
00586 for (CNameMap::const_iterator index1 = m_nameToCanonicalName.begin(),
00587 index2 = x.m_nameToCanonicalName.begin();
00588 index1 != m_nameToCanonicalName.end();
00589 ++index1, ++index2) {
00590 if (!CStringUtil::CaselessCmp::equal(index1->first, index2->first) ||
00591 !CStringUtil::CaselessCmp::equal(index1->second, index2->second)) {
00592 return false;
00593 }
00594 }
00595
00596
00597 if (m_inputFilter != x.m_inputFilter) {
00598 return false;
00599 }
00600
00601 return true;
00602 }
00603
00604 bool
00605 CConfig::operator!=(const CConfig& x) const
00606 {
00607 return !operator==(x);
00608 }
00609
00610 void
00611 CConfig::read(CConfigReadContext& context)
00612 {
00613 CConfig tmp;
00614 while (context) {
00615 tmp.readSection(context);
00616 }
00617 *this = tmp;
00618 }
00619
00620 const char*
00621 CConfig::dirName(EDirection dir)
00622 {
00623 static const char* s_name[] = { "left", "right", "up", "down" };
00624
00625 assert(dir >= kFirstDirection && dir <= kLastDirection);
00626
00627 return s_name[dir - kFirstDirection];
00628 }
00629
00630 CInputFilter*
00631 CConfig::getInputFilter()
00632 {
00633 return &m_inputFilter;
00634 }
00635
00636 CString
00637 CConfig::formatInterval(const CInterval& x)
00638 {
00639 if (x.first == 0.0f && x.second == 1.0f) {
00640 return "";
00641 }
00642 return CStringUtil::print("(%d,%d)", (int)(x.first * 100.0f + 0.5f),
00643 (int)(x.second * 100.0f + 0.5f));
00644 }
00645
00646 void
00647 CConfig::readSection(CConfigReadContext& s)
00648 {
00649 static const char s_section[] = "section:";
00650 static const char s_options[] = "options";
00651 static const char s_screens[] = "screens";
00652 static const char s_links[] = "links";
00653 static const char s_aliases[] = "aliases";
00654
00655 CString line;
00656 if (!s.readLine(line)) {
00657
00658 return;
00659 }
00660
00661
00662 if (line.find(s_section) != 0) {
00663 throw XConfigRead(s, "found data outside section");
00664 }
00665
00666
00667 CString::size_type i = line.find_first_not_of(" \t", sizeof(s_section) - 1);
00668 if (i == CString::npos) {
00669 throw XConfigRead(s, "section name is missing");
00670 }
00671 CString name = line.substr(i);
00672 i = name.find_first_of(" \t");
00673 if (i != CString::npos) {
00674 throw XConfigRead(s, "unexpected data after section name");
00675 }
00676
00677
00678 if (name == s_options) {
00679 readSectionOptions(s);
00680 }
00681 else if (name == s_screens) {
00682 readSectionScreens(s);
00683 }
00684 else if (name == s_links) {
00685 readSectionLinks(s);
00686 }
00687 else if (name == s_aliases) {
00688 readSectionAliases(s);
00689 }
00690 else {
00691 throw XConfigRead(s, "unknown section name \"%{1}\"", name);
00692 }
00693 }
00694
00695 void
00696 CConfig::readSectionOptions(CConfigReadContext& s)
00697 {
00698 CString line;
00699 while (s.readLine(line)) {
00700
00701 if (line == "end") {
00702 return;
00703 }
00704
00705
00706
00707
00708
00709 CString::size_type i = 0;
00710 CString name, value;
00711 CConfigReadContext::ArgList nameArgs, valueArgs;
00712 s.parseNameWithArgs("name", line, "=", i, name, nameArgs);
00713 ++i;
00714 s.parseNameWithArgs("value", line, ",;\n", i, value, valueArgs);
00715
00716 bool handled = true;
00717 if (name == "address") {
00718 try {
00719 m_synergyAddress = CNetworkAddress(value, kDefaultPort);
00720 m_synergyAddress.resolve();
00721 }
00722 catch (XSocketAddress& e) {
00723 throw XConfigRead(s,
00724 CString("invalid address argument ") + e.what());
00725 }
00726 }
00727 else if (name == "heartbeat") {
00728 addOption("", kOptionHeartbeat, s.parseInt(value));
00729 }
00730 else if (name == "switchCorners") {
00731 addOption("", kOptionScreenSwitchCorners, s.parseCorners(value));
00732 }
00733 else if (name == "switchCornerSize") {
00734 addOption("", kOptionScreenSwitchCornerSize, s.parseInt(value));
00735 }
00736 else if (name == "switchDelay") {
00737 addOption("", kOptionScreenSwitchDelay, s.parseInt(value));
00738 }
00739 else if (name == "switchDoubleTap") {
00740 addOption("", kOptionScreenSwitchTwoTap, s.parseInt(value));
00741 }
00742 else if (name == "switchNeedsShift") {
00743 addOption("", kOptionScreenSwitchNeedsShift, s.parseBoolean(value));
00744 }
00745 else if (name == "switchNeedsControl") {
00746 addOption("", kOptionScreenSwitchNeedsControl, s.parseBoolean(value));
00747 }
00748 else if (name == "switchNeedsAlt") {
00749 addOption("", kOptionScreenSwitchNeedsAlt, s.parseBoolean(value));
00750 }
00751 else if (name == "screenSaverSync") {
00752 addOption("", kOptionScreenSaverSync, s.parseBoolean(value));
00753 }
00754 else if (name == "relativeMouseMoves") {
00755 addOption("", kOptionRelativeMouseMoves, s.parseBoolean(value));
00756 }
00757 else if (name == "win32KeepForeground") {
00758 addOption("", kOptionWin32KeepForeground, s.parseBoolean(value));
00759 }
00760 else {
00761 handled = false;
00762 }
00763
00764 if (handled) {
00765
00766 if (i < line.size() && (line[i] == ',' || line[i] == ';')) {
00767 throw XConfigRead(s, "to many arguments to %s", name.c_str());
00768 }
00769 }
00770 else {
00771
00772 CInputFilter::CRule rule(parseCondition(s, name, nameArgs));
00773
00774
00775 if (!value.empty() || line[i] != ';') {
00776 parseAction(s, value, valueArgs, rule, true);
00777 }
00778
00779
00780 while (i < line.length() && line[i] != ';') {
00781 ++i;
00782 s.parseNameWithArgs("value", line, ",;\n", i, value, valueArgs);
00783 parseAction(s, value, valueArgs, rule, true);
00784 }
00785
00786
00787 if (i < line.length() && line[i] == ';') {
00788
00789 i = line.find_first_not_of(" \t", i + 1);
00790 if (i == CString::npos) {
00791 i = line.length();
00792 }
00793 else {
00794 --i;
00795 }
00796
00797
00798 while (i < line.length()) {
00799 ++i;
00800 s.parseNameWithArgs("value", line, ",\n",
00801 i, value, valueArgs);
00802 parseAction(s, value, valueArgs, rule, false);
00803 }
00804 }
00805
00806
00807 m_inputFilter.addFilterRule(rule);
00808 }
00809 }
00810 throw XConfigRead(s, "unexpected end of options section");
00811 }
00812
00813 void
00814 CConfig::readSectionScreens(CConfigReadContext& s)
00815 {
00816 CString line;
00817 CString screen;
00818 while (s.readLine(line)) {
00819
00820 if (line == "end") {
00821 return;
00822 }
00823
00824
00825 if (line[line.size() - 1] == ':') {
00826
00827 screen = line.substr(0, line.size() - 1);
00828
00829
00830 if (!isValidScreenName(screen)) {
00831 throw XConfigRead(s, "invalid screen name \"%{1}\"", screen);
00832 }
00833
00834
00835 if (!addScreen(screen)) {
00836 throw XConfigRead(s, "duplicate screen name \"%{1}\"", screen);
00837 }
00838 }
00839 else if (screen.empty()) {
00840 throw XConfigRead(s, "argument before first screen");
00841 }
00842 else {
00843
00844 CString::size_type i = line.find_first_of(" \t=");
00845 if (i == 0) {
00846 throw XConfigRead(s, "missing argument name");
00847 }
00848 if (i == CString::npos) {
00849 throw XConfigRead(s, "missing =");
00850 }
00851 CString name = line.substr(0, i);
00852 i = line.find_first_not_of(" \t", i);
00853 if (i == CString::npos || line[i] != '=') {
00854 throw XConfigRead(s, "missing =");
00855 }
00856 i = line.find_first_not_of(" \t", i + 1);
00857 CString value;
00858 if (i != CString::npos) {
00859 value = line.substr(i);
00860 }
00861
00862
00863 if (name == "halfDuplexCapsLock") {
00864 addOption(screen, kOptionHalfDuplexCapsLock,
00865 s.parseBoolean(value));
00866 }
00867 else if (name == "halfDuplexNumLock") {
00868 addOption(screen, kOptionHalfDuplexNumLock,
00869 s.parseBoolean(value));
00870 }
00871 else if (name == "halfDuplexScrollLock") {
00872 addOption(screen, kOptionHalfDuplexScrollLock,
00873 s.parseBoolean(value));
00874 }
00875 else if (name == "shift") {
00876 addOption(screen, kOptionModifierMapForShift,
00877 s.parseModifierKey(value));
00878 }
00879 else if (name == "ctrl") {
00880 addOption(screen, kOptionModifierMapForControl,
00881 s.parseModifierKey(value));
00882 }
00883 else if (name == "alt") {
00884 addOption(screen, kOptionModifierMapForAlt,
00885 s.parseModifierKey(value));
00886 }
00887 else if (name == "altgr") {
00888 addOption(screen, kOptionModifierMapForAltGr,
00889 s.parseModifierKey(value));
00890 }
00891 else if (name == "meta") {
00892 addOption(screen, kOptionModifierMapForMeta,
00893 s.parseModifierKey(value));
00894 }
00895 else if (name == "super") {
00896 addOption(screen, kOptionModifierMapForSuper,
00897 s.parseModifierKey(value));
00898 }
00899 else if (name == "xtestIsXineramaUnaware") {
00900 addOption(screen, kOptionXTestXineramaUnaware,
00901 s.parseBoolean(value));
00902 }
00903 else if (name == "switchCorners") {
00904 addOption(screen, kOptionScreenSwitchCorners,
00905 s.parseCorners(value));
00906 }
00907 else if (name == "switchCornerSize") {
00908 addOption(screen, kOptionScreenSwitchCornerSize,
00909 s.parseInt(value));
00910 }
00911 else if (name == "preserveFocus") {
00912 addOption(screen, kOptionScreenPreserveFocus,
00913 s.parseBoolean(value));
00914 }
00915 else {
00916
00917 throw XConfigRead(s, "unknown argument \"%{1}\"", name);
00918 }
00919 }
00920 }
00921 throw XConfigRead(s, "unexpected end of screens section");
00922 }
00923
00924 void
00925 CConfig::readSectionLinks(CConfigReadContext& s)
00926 {
00927 CString line;
00928 CString screen;
00929 while (s.readLine(line)) {
00930
00931 if (line == "end") {
00932 return;
00933 }
00934
00935
00936 if (line[line.size() - 1] == ':') {
00937
00938 screen = line.substr(0, line.size() - 1);
00939
00940
00941 if (!isScreen(screen)) {
00942 throw XConfigRead(s, "unknown screen name \"%{1}\"", screen);
00943 }
00944 if (!isCanonicalName(screen)) {
00945 throw XConfigRead(s, "cannot use screen name alias here");
00946 }
00947 }
00948 else if (screen.empty()) {
00949 throw XConfigRead(s, "argument before first screen");
00950 }
00951 else {
00952
00953
00954
00955
00956 CString::size_type i = 0;
00957 CString side, dstScreen, srcArgString, dstArgString;
00958 CConfigReadContext::ArgList srcArgs, dstArgs;
00959 s.parseNameWithArgs("link", line, "=", i, side, srcArgs);
00960 ++i;
00961 s.parseNameWithArgs("screen", line, "", i, dstScreen, dstArgs);
00962 CInterval srcInterval(s.parseInterval(srcArgs));
00963 CInterval dstInterval(s.parseInterval(dstArgs));
00964
00965
00966 EDirection dir;
00967 if (side == "left") {
00968 dir = kLeft;
00969 }
00970 else if (side == "right") {
00971 dir = kRight;
00972 }
00973 else if (side == "up") {
00974 dir = kTop;
00975 }
00976 else if (side == "down") {
00977 dir = kBottom;
00978 }
00979 else {
00980
00981 throw XConfigRead(s, "unknown side \"%{1}\" in link", side);
00982 }
00983 if (!isScreen(dstScreen)) {
00984 throw XConfigRead(s, "unknown screen name \"%{1}\"", dstScreen);
00985 }
00986 if (!connect(screen, dir,
00987 srcInterval.first, srcInterval.second,
00988 dstScreen,
00989 dstInterval.first, dstInterval.second)) {
00990 throw XConfigRead(s, "overlapping range");
00991 }
00992 }
00993 }
00994 throw XConfigRead(s, "unexpected end of links section");
00995 }
00996
00997 void
00998 CConfig::readSectionAliases(CConfigReadContext& s)
00999 {
01000 CString line;
01001 CString screen;
01002 while (s.readLine(line)) {
01003
01004 if (line == "end") {
01005 return;
01006 }
01007
01008
01009 if (line[line.size() - 1] == ':') {
01010
01011 screen = line.substr(0, line.size() - 1);
01012
01013
01014 if (!isScreen(screen)) {
01015 throw XConfigRead(s, "unknown screen name \"%{1}\"", screen);
01016 }
01017 if (!isCanonicalName(screen)) {
01018 throw XConfigRead(s, "cannot use screen name alias here");
01019 }
01020 }
01021 else if (screen.empty()) {
01022 throw XConfigRead(s, "argument before first screen");
01023 }
01024 else {
01025
01026 if (!isValidScreenName(line)) {
01027 throw XConfigRead(s, "invalid screen alias \"%{1}\"", line);
01028 }
01029
01030
01031 if (!addAlias(screen, line)) {
01032 throw XConfigRead(s, "alias \"%{1}\" is already used", line);
01033 }
01034 }
01035 }
01036 throw XConfigRead(s, "unexpected end of aliases section");
01037 }
01038
01039
01040 CInputFilter::CCondition*
01041 CConfig::parseCondition(CConfigReadContext& s,
01042 const CString& name, const std::vector<CString>& args)
01043 {
01044 if (name == "keystroke") {
01045 if (args.size() != 1) {
01046 throw XConfigRead(s, "syntax for condition: keystroke(modifiers+key)");
01047 }
01048
01049 IPlatformScreen::CKeyInfo* keyInfo = s.parseKeystroke(args[0]);
01050
01051 return new CInputFilter::CKeystrokeCondition(keyInfo);
01052 }
01053
01054 if (name == "mousebutton") {
01055 if (args.size() != 1) {
01056 throw XConfigRead(s, "syntax for condition: mousebutton(modifiers+button)");
01057 }
01058
01059 IPlatformScreen::CButtonInfo* mouseInfo = s.parseMouse(args[0]);
01060
01061 return new CInputFilter::CMouseButtonCondition(mouseInfo);
01062 }
01063
01064 if (name == "connect") {
01065 if (args.size() != 1) {
01066 throw XConfigRead(s, "syntax for condition: connect([screen])");
01067 }
01068
01069 CString screen = args[0];
01070 if (isScreen(screen)) {
01071 screen = getCanonicalName(screen);
01072 }
01073 else if (!screen.empty()) {
01074 throw XConfigRead(s, "unknown screen name \"%{1}\" in connect", screen);
01075 }
01076
01077 return new CInputFilter::CScreenConnectedCondition(screen);
01078 }
01079
01080 throw XConfigRead(s, "unknown argument \"%{1}\"", name);
01081 }
01082
01083 void
01084 CConfig::parseAction(CConfigReadContext& s,
01085 const CString& name, const std::vector<CString>& args,
01086 CInputFilter::CRule& rule, bool activate)
01087 {
01088 CInputFilter::CAction* action;
01089
01090 if (name == "keystroke" || name == "keyDown" || name == "keyUp") {
01091 if (args.size() < 1 || args.size() > 2) {
01092 throw XConfigRead(s, "syntax for action: keystroke(modifiers+key[,screens])");
01093 }
01094
01095 IPlatformScreen::CKeyInfo* keyInfo;
01096 if (args.size() == 1) {
01097 keyInfo = s.parseKeystroke(args[0]);
01098 }
01099 else {
01100 std::set<CString> screens;
01101 parseScreens(s, args[1], screens);
01102 keyInfo = s.parseKeystroke(args[0], screens);
01103 }
01104
01105 if (name == "keystroke") {
01106 IPlatformScreen::CKeyInfo* keyInfo2 =
01107 IKeyState::CKeyInfo::alloc(*keyInfo);
01108 action = new CInputFilter::CKeystrokeAction(keyInfo2, true);
01109 rule.adoptAction(action, true);
01110 action = new CInputFilter::CKeystrokeAction(keyInfo, false);
01111 activate = false;
01112 }
01113 else if (name == "keyDown") {
01114 action = new CInputFilter::CKeystrokeAction(keyInfo, true);
01115 }
01116 else {
01117 action = new CInputFilter::CKeystrokeAction(keyInfo, false);
01118 }
01119 }
01120
01121 else if (name == "mousebutton" ||
01122 name == "mouseDown" || name == "mouseUp") {
01123 if (args.size() != 1) {
01124 throw XConfigRead(s, "syntax for action: mousebutton(modifiers+button)");
01125 }
01126
01127 IPlatformScreen::CButtonInfo* mouseInfo = s.parseMouse(args[0]);
01128
01129 if (name == "mousebutton") {
01130 IPlatformScreen::CButtonInfo* mouseInfo2 =
01131 IPlatformScreen::CButtonInfo::alloc(*mouseInfo);
01132 action = new CInputFilter::CMouseButtonAction(mouseInfo2, true);
01133 rule.adoptAction(action, true);
01134 action = new CInputFilter::CMouseButtonAction(mouseInfo, false);
01135 activate = false;
01136 }
01137 else if (name == "mouseDown") {
01138 action = new CInputFilter::CMouseButtonAction(mouseInfo, true);
01139 }
01140 else {
01141 action = new CInputFilter::CMouseButtonAction(mouseInfo, false);
01142 }
01143 }
01144
01145
01146
01147
01148
01149
01150
01151
01152
01153
01154
01155
01156
01157 else if (name == "switchToScreen") {
01158 if (args.size() != 1) {
01159 throw XConfigRead(s, "syntax for action: switchToScreen(name)");
01160 }
01161
01162 CString screen = args[0];
01163 if (isScreen(screen)) {
01164 screen = getCanonicalName(screen);
01165 }
01166 else if (!screen.empty()) {
01167 throw XConfigRead(s, "unknown screen name in switchToScreen");
01168 }
01169
01170 action = new CInputFilter::CSwitchToScreenAction(screen);
01171 }
01172
01173 else if (name == "switchInDirection") {
01174 if (args.size() != 1) {
01175 throw XConfigRead(s, "syntax for action: switchInDirection(<left|right|up|down>)");
01176 }
01177
01178 EDirection direction;
01179 if (args[0] == "left") {
01180 direction = kLeft;
01181 }
01182 else if (args[0] == "right") {
01183 direction = kRight;
01184 }
01185 else if (args[0] == "up") {
01186 direction = kTop;
01187 }
01188 else if (args[0] == "down") {
01189 direction = kBottom;
01190 }
01191 else {
01192 throw XConfigRead(s, "unknown direction \"%{1}\" in switchToScreen", args[0]);
01193 }
01194
01195 action = new CInputFilter::CSwitchInDirectionAction(direction);
01196 }
01197
01198 else if (name == "lockCursorToScreen") {
01199 if (args.size() > 1) {
01200 throw XConfigRead(s, "syntax for action: lockCursorToScreen([{off|on|toggle}])");
01201 }
01202
01203 CInputFilter::CLockCursorToScreenAction::Mode mode =
01204 CInputFilter::CLockCursorToScreenAction::kToggle;
01205 if (args.size() == 1) {
01206 if (args[0] == "off") {
01207 mode = CInputFilter::CLockCursorToScreenAction::kOff;
01208 }
01209 else if (args[0] == "on") {
01210 mode = CInputFilter::CLockCursorToScreenAction::kOn;
01211 }
01212 else if (args[0] == "toggle") {
01213 mode = CInputFilter::CLockCursorToScreenAction::kToggle;
01214 }
01215 else {
01216 throw XConfigRead(s, "syntax for action: lockCursorToScreen([{off|on|toggle}])");
01217 }
01218 }
01219
01220 if (mode != CInputFilter::CLockCursorToScreenAction::kOff) {
01221 m_hasLockToScreenAction = true;
01222 }
01223
01224 action = new CInputFilter::CLockCursorToScreenAction(mode);
01225 }
01226
01227 else if (name == "keyboardBroadcast") {
01228 if (args.size() > 2) {
01229 throw XConfigRead(s, "syntax for action: keyboardBroadcast([{off|on|toggle}[,screens]])");
01230 }
01231
01232 CInputFilter::CKeyboardBroadcastAction::Mode mode =
01233 CInputFilter::CKeyboardBroadcastAction::kToggle;
01234 if (args.size() >= 1) {
01235 if (args[0] == "off") {
01236 mode = CInputFilter::CKeyboardBroadcastAction::kOff;
01237 }
01238 else if (args[0] == "on") {
01239 mode = CInputFilter::CKeyboardBroadcastAction::kOn;
01240 }
01241 else if (args[0] == "toggle") {
01242 mode = CInputFilter::CKeyboardBroadcastAction::kToggle;
01243 }
01244 else {
01245 throw XConfigRead(s, "syntax for action: keyboardBroadcast([{off|on|toggle}[,screens]])");
01246 }
01247 }
01248
01249 std::set<CString> screens;
01250 if (args.size() >= 2) {
01251 parseScreens(s, args[1], screens);
01252 }
01253
01254 action = new CInputFilter::CKeyboardBroadcastAction(mode, screens);
01255 }
01256
01257 else {
01258 throw XConfigRead(s, "unknown action argument \"%{1}\"", name);
01259 }
01260
01261 rule.adoptAction(action, activate);
01262 }
01263
01264 void
01265 CConfig::parseScreens(CConfigReadContext& c,
01266 const CString& s, std::set<CString>& screens) const
01267 {
01268 screens.clear();
01269
01270 CString::size_type i = 0;
01271 while (i < s.size()) {
01272
01273 CString::size_type j = s.find(':', i);
01274 if (j == CString::npos) {
01275 j = s.size();
01276 }
01277
01278
01279 CString rawName;
01280 i = s.find_first_not_of(" \t", i);
01281 if (i < j) {
01282 rawName = s.substr(i, s.find_last_not_of(" \t", j - 1) - i + 1);
01283 }
01284
01285
01286 if (rawName == "*") {
01287 screens.insert("*");
01288 }
01289 else if (!rawName.empty()) {
01290 CString name = getCanonicalName(rawName);
01291 if (name.empty()) {
01292 throw XConfigRead(c, "unknown screen name \"%{1}\"", rawName);
01293 }
01294 screens.insert(name);
01295 }
01296
01297
01298 i = j + 1;
01299 }
01300 }
01301
01302 const char*
01303 CConfig::getOptionName(OptionID id)
01304 {
01305 if (id == kOptionHalfDuplexCapsLock) {
01306 return "halfDuplexCapsLock";
01307 }
01308 if (id == kOptionHalfDuplexNumLock) {
01309 return "halfDuplexNumLock";
01310 }
01311 if (id == kOptionHalfDuplexScrollLock) {
01312 return "halfDuplexScrollLock";
01313 }
01314 if (id == kOptionModifierMapForShift) {
01315 return "shift";
01316 }
01317 if (id == kOptionModifierMapForControl) {
01318 return "ctrl";
01319 }
01320 if (id == kOptionModifierMapForAlt) {
01321 return "alt";
01322 }
01323 if (id == kOptionModifierMapForAltGr) {
01324 return "altgr";
01325 }
01326 if (id == kOptionModifierMapForMeta) {
01327 return "meta";
01328 }
01329 if (id == kOptionModifierMapForSuper) {
01330 return "super";
01331 }
01332 if (id == kOptionHeartbeat) {
01333 return "heartbeat";
01334 }
01335 if (id == kOptionScreenSwitchCorners) {
01336 return "switchCorners";
01337 }
01338 if (id == kOptionScreenSwitchCornerSize) {
01339 return "switchCornerSize";
01340 }
01341 if (id == kOptionScreenSwitchDelay) {
01342 return "switchDelay";
01343 }
01344 if (id == kOptionScreenSwitchTwoTap) {
01345 return "switchDoubleTap";
01346 }
01347 if (id == kOptionScreenSwitchNeedsShift) {
01348 return "switchNeedsShift";
01349 }
01350 if (id == kOptionScreenSwitchNeedsControl) {
01351 return "switchNeedsControl";
01352 }
01353 if (id == kOptionScreenSwitchNeedsAlt) {
01354 return "switchNeedsAlt";
01355 }
01356 if (id == kOptionScreenSaverSync) {
01357 return "screenSaverSync";
01358 }
01359 if (id == kOptionXTestXineramaUnaware) {
01360 return "xtestIsXineramaUnaware";
01361 }
01362 if (id == kOptionRelativeMouseMoves) {
01363 return "relativeMouseMoves";
01364 }
01365 if (id == kOptionWin32KeepForeground) {
01366 return "win32KeepForeground";
01367 }
01368 if (id == kOptionScreenPreserveFocus) {
01369 return "preserveFocus";
01370 }
01371 return NULL;
01372 }
01373
01374 CString
01375 CConfig::getOptionValue(OptionID id, OptionValue value)
01376 {
01377 if (id == kOptionHalfDuplexCapsLock ||
01378 id == kOptionHalfDuplexNumLock ||
01379 id == kOptionHalfDuplexScrollLock ||
01380 id == kOptionScreenSwitchNeedsShift ||
01381 id == kOptionScreenSwitchNeedsControl ||
01382 id == kOptionScreenSwitchNeedsAlt ||
01383 id == kOptionScreenSaverSync ||
01384 id == kOptionXTestXineramaUnaware ||
01385 id == kOptionRelativeMouseMoves ||
01386 id == kOptionWin32KeepForeground ||
01387 id == kOptionScreenPreserveFocus) {
01388 return (value != 0) ? "true" : "false";
01389 }
01390 if (id == kOptionModifierMapForShift ||
01391 id == kOptionModifierMapForControl ||
01392 id == kOptionModifierMapForAlt ||
01393 id == kOptionModifierMapForAltGr ||
01394 id == kOptionModifierMapForMeta ||
01395 id == kOptionModifierMapForSuper) {
01396 switch (value) {
01397 case kKeyModifierIDShift:
01398 return "shift";
01399
01400 case kKeyModifierIDControl:
01401 return "ctrl";
01402
01403 case kKeyModifierIDAlt:
01404 return "alt";
01405
01406 case kKeyModifierIDAltGr:
01407 return "altgr";
01408
01409 case kKeyModifierIDMeta:
01410 return "meta";
01411
01412 case kKeyModifierIDSuper:
01413 return "super";
01414
01415 default:
01416 return "none";
01417 }
01418 }
01419 if (id == kOptionHeartbeat ||
01420 id == kOptionScreenSwitchCornerSize ||
01421 id == kOptionScreenSwitchDelay ||
01422 id == kOptionScreenSwitchTwoTap) {
01423 return CStringUtil::print("%d", value);
01424 }
01425 if (id == kOptionScreenSwitchCorners) {
01426 std::string result("none");
01427 if ((value & kTopLeftMask) != 0) {
01428 result += " +top-left";
01429 }
01430 if ((value & kTopRightMask) != 0) {
01431 result += " +top-right";
01432 }
01433 if ((value & kBottomLeftMask) != 0) {
01434 result += " +bottom-left";
01435 }
01436 if ((value & kBottomRightMask) != 0) {
01437 result += " +bottom-right";
01438 }
01439 return result;
01440 }
01441
01442 return "";
01443 }
01444
01445
01446
01447
01448
01449
01450 CConfig::CName::CName(CConfig* config, const CString& name) :
01451 m_config(config),
01452 m_name(config->getCanonicalName(name))
01453 {
01454
01455 }
01456
01457 bool
01458 CConfig::CName::operator==(const CString& name) const
01459 {
01460 CString canonical = m_config->getCanonicalName(name);
01461 return CStringUtil::CaselessCmp::equal(canonical, m_name);
01462 }
01463
01464
01465
01466
01467
01468
01469 CConfig::CCellEdge::CCellEdge(EDirection side, float position)
01470 {
01471 init("", side, CInterval(position, position));
01472 }
01473
01474 CConfig::CCellEdge::CCellEdge(EDirection side, const CInterval& interval)
01475 {
01476 assert(interval.first >= 0.0f);
01477 assert(interval.second <= 1.0f);
01478 assert(interval.first < interval.second);
01479
01480 init("", side, interval);
01481 }
01482
01483 CConfig::CCellEdge::CCellEdge(const CString& name,
01484 EDirection side, const CInterval& interval)
01485 {
01486 assert(interval.first >= 0.0f);
01487 assert(interval.second <= 1.0f);
01488 assert(interval.first < interval.second);
01489
01490 init(name, side, interval);
01491 }
01492
01493 CConfig::CCellEdge::~CCellEdge()
01494 {
01495
01496 }
01497
01498 void
01499 CConfig::CCellEdge::init(const CString& name, EDirection side,
01500 const CInterval& interval)
01501 {
01502 assert(side != kNoDirection);
01503
01504 m_name = name;
01505 m_side = side;
01506 m_interval = interval;
01507 }
01508
01509 CConfig::CInterval
01510 CConfig::CCellEdge::getInterval() const
01511 {
01512 return m_interval;
01513 }
01514
01515 void
01516 CConfig::CCellEdge::setName(const CString& newName)
01517 {
01518 m_name = newName;
01519 }
01520
01521 CString
01522 CConfig::CCellEdge::getName() const
01523 {
01524 return m_name;
01525 }
01526
01527 EDirection
01528 CConfig::CCellEdge::getSide() const
01529 {
01530 return m_side;
01531 }
01532
01533 bool
01534 CConfig::CCellEdge::overlaps(const CCellEdge& edge) const
01535 {
01536 const CInterval& x = m_interval;
01537 const CInterval& y = edge.m_interval;
01538 if (m_side != edge.m_side) {
01539 return false;
01540 }
01541 return (x.first >= y.first && x.first < y.second) ||
01542 (x.second > y.first && x.second <= y.second) ||
01543 (y.first >= x.first && y.first < x.second) ||
01544 (y.second > x.first && y.second <= x.second);
01545 }
01546
01547 bool
01548 CConfig::CCellEdge::isInside(float x) const
01549 {
01550 return (x >= m_interval.first && x < m_interval.second);
01551 }
01552
01553 float
01554 CConfig::CCellEdge::transform(float x) const
01555 {
01556 return (x - m_interval.first) / (m_interval.second - m_interval.first);
01557 }
01558
01559
01560 float
01561 CConfig::CCellEdge::inverseTransform(float x) const
01562 {
01563 return x * (m_interval.second - m_interval.first) + m_interval.first;
01564 }
01565
01566 bool
01567 CConfig::CCellEdge::operator<(const CCellEdge& o) const
01568 {
01569 if (static_cast<int>(m_side) < static_cast<int>(o.m_side)) {
01570 return true;
01571 }
01572 else if (static_cast<int>(m_side) > static_cast<int>(o.m_side)) {
01573 return false;
01574 }
01575
01576 return (m_interval.first < o.m_interval.first);
01577 }
01578
01579 bool
01580 CConfig::CCellEdge::operator==(const CCellEdge& x) const
01581 {
01582 return (m_side == x.m_side && m_interval == x.m_interval);
01583 }
01584
01585 bool
01586 CConfig::CCellEdge::operator!=(const CCellEdge& x) const
01587 {
01588 return !operator==(x);
01589 }
01590
01591
01592
01593
01594
01595
01596 bool
01597 CConfig::CCell::add(const CCellEdge& src, const CCellEdge& dst)
01598 {
01599
01600
01601 if (!hasEdge(src) && overlaps(src)) {
01602 return false;
01603 }
01604
01605 m_neighbors.erase(src);
01606 m_neighbors.insert(std::make_pair(src, dst));
01607 return true;
01608 }
01609
01610 void
01611 CConfig::CCell::remove(EDirection side)
01612 {
01613 for (CEdgeLinks::iterator j = m_neighbors.begin();
01614 j != m_neighbors.end(); ) {
01615 if (j->first.getSide() == side) {
01616 m_neighbors.erase(j++);
01617 }
01618 else {
01619 ++j;
01620 }
01621 }
01622 }
01623
01624 void
01625 CConfig::CCell::remove(EDirection side, float position)
01626 {
01627 for (CEdgeLinks::iterator j = m_neighbors.begin();
01628 j != m_neighbors.end(); ++j) {
01629 if (j->first.getSide() == side && j->first.isInside(position)) {
01630 m_neighbors.erase(j);
01631 break;
01632 }
01633 }
01634 }
01635 void
01636 CConfig::CCell::remove(const CName& name)
01637 {
01638 for (CEdgeLinks::iterator j = m_neighbors.begin();
01639 j != m_neighbors.end(); ) {
01640 if (name == j->second.getName()) {
01641 m_neighbors.erase(j++);
01642 }
01643 else {
01644 ++j;
01645 }
01646 }
01647 }
01648
01649 void
01650 CConfig::CCell::rename(const CName& oldName, const CString& newName)
01651 {
01652 for (CEdgeLinks::iterator j = m_neighbors.begin();
01653 j != m_neighbors.end(); ++j) {
01654 if (oldName == j->second.getName()) {
01655 j->second.setName(newName);
01656 }
01657 }
01658 }
01659
01660 bool
01661 CConfig::CCell::hasEdge(const CCellEdge& edge) const
01662 {
01663 CEdgeLinks::const_iterator i = m_neighbors.find(edge);
01664 return (i != m_neighbors.end() && i->first == edge);
01665 }
01666
01667 bool
01668 CConfig::CCell::overlaps(const CCellEdge& edge) const
01669 {
01670 CEdgeLinks::const_iterator i = m_neighbors.upper_bound(edge);
01671 if (i != m_neighbors.end() && i->first.overlaps(edge)) {
01672 return true;
01673 }
01674 if (i != m_neighbors.begin() && (--i)->first.overlaps(edge)) {
01675 return true;
01676 }
01677 return false;
01678 }
01679
01680 bool
01681 CConfig::CCell::getLink(EDirection side, float position,
01682 const CCellEdge*& src, const CCellEdge*& dst) const
01683 {
01684 CCellEdge edge(side, position);
01685 CEdgeLinks::const_iterator i = m_neighbors.upper_bound(edge);
01686 if (i == m_neighbors.begin()) {
01687 return false;
01688 }
01689 --i;
01690 if (i->first.getSide() == side && i->first.isInside(position)) {
01691 src = &i->first;
01692 dst = &i->second;
01693 return true;
01694 }
01695 return false;
01696 }
01697
01698 bool
01699 CConfig::CCell::operator==(const CCell& x) const
01700 {
01701
01702 if (m_options != x.m_options) {
01703 return false;
01704 }
01705
01706
01707 if (m_neighbors.size() != x.m_neighbors.size()) {
01708 return false;
01709 }
01710 for (CEdgeLinks::const_iterator index1 = m_neighbors.begin(),
01711 index2 = x.m_neighbors.begin();
01712 index1 != m_neighbors.end();
01713 ++index1, ++index2) {
01714 if (index1->first != index2->first) {
01715 return false;
01716 }
01717 if (index1->second != index2->second) {
01718 return false;
01719 }
01720
01721
01722
01723 if (!CStringUtil::CaselessCmp::equal(index1->second.getName(),
01724 index2->second.getName())) {
01725 return false;
01726 }
01727 }
01728 return true;
01729 }
01730
01731 bool
01732 CConfig::CCell::operator!=(const CCell& x) const
01733 {
01734 return !operator==(x);
01735 }
01736
01737 CConfig::CCell::const_iterator
01738 CConfig::CCell::begin() const
01739 {
01740 return m_neighbors.begin();
01741 }
01742
01743 CConfig::CCell::const_iterator
01744 CConfig::CCell::end() const
01745 {
01746 return m_neighbors.end();
01747 }
01748
01749
01750
01751
01752
01753
01754 std::istream&
01755 operator>>(std::istream& s, CConfig& config)
01756 {
01757 CConfigReadContext context(s);
01758 config.read(context);
01759 return s;
01760 }
01761
01762 std::ostream&
01763 operator<<(std::ostream& s, const CConfig& config)
01764 {
01765
01766 s << "section: screens" << std::endl;
01767 for (CConfig::const_iterator screen = config.begin();
01768 screen != config.end(); ++screen) {
01769 s << "\t" << screen->c_str() << ":" << std::endl;
01770 const CConfig::CScreenOptions* options = config.getOptions(*screen);
01771 if (options != NULL && options->size() > 0) {
01772 for (CConfig::CScreenOptions::const_iterator
01773 option = options->begin();
01774 option != options->end(); ++option) {
01775 const char* name = CConfig::getOptionName(option->first);
01776 CString value = CConfig::getOptionValue(option->first,
01777 option->second);
01778 if (name != NULL && !value.empty()) {
01779 s << "\t\t" << name << " = " << value << std::endl;
01780 }
01781 }
01782 }
01783 }
01784 s << "end" << std::endl;
01785
01786
01787 CString neighbor;
01788 s << "section: links" << std::endl;
01789 for (CConfig::const_iterator screen = config.begin();
01790 screen != config.end(); ++screen) {
01791 s << "\t" << screen->c_str() << ":" << std::endl;
01792
01793 for (CConfig::link_const_iterator
01794 link = config.beginNeighbor(*screen),
01795 nend = config.endNeighbor(*screen); link != nend; ++link) {
01796 s << "\t\t" << CConfig::dirName(link->first.getSide()) <<
01797 CConfig::formatInterval(link->first.getInterval()) <<
01798 " = " << link->second.getName().c_str() <<
01799 CConfig::formatInterval(link->second.getInterval()) <<
01800 std::endl;
01801 }
01802 }
01803 s << "end" << std::endl;
01804
01805
01806 if (config.m_map.size() != config.m_nameToCanonicalName.size()) {
01807
01808 typedef std::multimap<CString, CString,
01809 CStringUtil::CaselessCmp> CMNameMap;
01810 CMNameMap aliases;
01811 for (CConfig::CNameMap::const_iterator
01812 index = config.m_nameToCanonicalName.begin();
01813 index != config.m_nameToCanonicalName.end();
01814 ++index) {
01815 if (index->first != index->second) {
01816 aliases.insert(std::make_pair(index->second, index->first));
01817 }
01818 }
01819
01820
01821 CString screen;
01822 s << "section: aliases" << std::endl;
01823 for (CMNameMap::const_iterator index = aliases.begin();
01824 index != aliases.end(); ++index) {
01825 if (index->first != screen) {
01826 screen = index->first;
01827 s << "\t" << screen.c_str() << ":" << std::endl;
01828 }
01829 s << "\t\t" << index->second.c_str() << std::endl;
01830 }
01831 s << "end" << std::endl;
01832 }
01833
01834
01835 s << "section: options" << std::endl;
01836 const CConfig::CScreenOptions* options = config.getOptions("");
01837 if (options != NULL && options->size() > 0) {
01838 for (CConfig::CScreenOptions::const_iterator
01839 option = options->begin();
01840 option != options->end(); ++option) {
01841 const char* name = CConfig::getOptionName(option->first);
01842 CString value = CConfig::getOptionValue(option->first,
01843 option->second);
01844 if (name != NULL && !value.empty()) {
01845 s << "\t" << name << " = " << value << std::endl;
01846 }
01847 }
01848 }
01849 if (config.m_synergyAddress.isValid()) {
01850 s << "\taddress = " <<
01851 config.m_synergyAddress.getHostname().c_str() << std::endl;
01852 }
01853 s << config.m_inputFilter.format("\t");
01854 s << "end" << std::endl;
01855
01856 return s;
01857 }
01858
01859
01860
01861
01862
01863
01864 CConfigReadContext::CConfigReadContext(std::istream& s, SInt32 firstLine) :
01865 m_stream(s),
01866 m_line(firstLine - 1)
01867 {
01868
01869 }
01870
01871 CConfigReadContext::~CConfigReadContext()
01872 {
01873
01874 }
01875
01876 bool
01877 CConfigReadContext::readLine(CString& line)
01878 {
01879 ++m_line;
01880 while (std::getline(m_stream, line)) {
01881
01882 CString::size_type i = line.find_first_not_of(" \t");
01883 if (i != CString::npos) {
01884 line.erase(0, i);
01885 }
01886
01887
01888 i = line.find('#');
01889 if (i != CString::npos) {
01890 line.erase(i);
01891 }
01892 i = line.find_last_not_of(" \r\t");
01893 if (i != CString::npos) {
01894 line.erase(i + 1);
01895 }
01896
01897
01898 if (!line.empty()) {
01899
01900 for (i = 0; i < line.length(); ++i) {
01901 if (!isgraph(line[i]) && line[i] != ' ' && line[i] != '\t') {
01902 throw XConfigRead(*this,
01903 "invalid character %{1}",
01904 CStringUtil::print("%#2x", line[i]));
01905 }
01906 }
01907
01908 return true;
01909 }
01910
01911
01912 ++m_line;
01913 }
01914 return false;
01915 }
01916
01917 UInt32
01918 CConfigReadContext::getLineNumber() const
01919 {
01920 return m_line;
01921 }
01922
01923 CConfigReadContext::operator void*() const
01924 {
01925 return m_stream;
01926 }
01927
01928 bool
01929 CConfigReadContext::operator!() const
01930 {
01931 return !m_stream;
01932 }
01933
01934 OptionValue
01935 CConfigReadContext::parseBoolean(const CString& arg) const
01936 {
01937 if (CStringUtil::CaselessCmp::equal(arg, "true")) {
01938 return static_cast<OptionValue>(true);
01939 }
01940 if (CStringUtil::CaselessCmp::equal(arg, "false")) {
01941 return static_cast<OptionValue>(false);
01942 }
01943 throw XConfigRead(*this, "invalid boolean argument \"%{1}\"", arg);
01944 }
01945
01946 OptionValue
01947 CConfigReadContext::parseInt(const CString& arg) const
01948 {
01949 const char* s = arg.c_str();
01950 char* end;
01951 long tmp = strtol(s, &end, 10);
01952 if (*end != '\0') {
01953
01954 throw XConfigRead(*this, "invalid integer argument \"%{1}\"", arg);
01955 }
01956 OptionValue value = static_cast<OptionValue>(tmp);
01957 if (value != tmp) {
01958
01959 throw XConfigRead(*this, "integer argument \"%{1}\" out of range", arg);
01960 }
01961 return value;
01962 }
01963
01964 OptionValue
01965 CConfigReadContext::parseModifierKey(const CString& arg) const
01966 {
01967 if (CStringUtil::CaselessCmp::equal(arg, "shift")) {
01968 return static_cast<OptionValue>(kKeyModifierIDShift);
01969 }
01970 if (CStringUtil::CaselessCmp::equal(arg, "ctrl")) {
01971 return static_cast<OptionValue>(kKeyModifierIDControl);
01972 }
01973 if (CStringUtil::CaselessCmp::equal(arg, "alt")) {
01974 return static_cast<OptionValue>(kKeyModifierIDAlt);
01975 }
01976 if (CStringUtil::CaselessCmp::equal(arg, "altgr")) {
01977 return static_cast<OptionValue>(kKeyModifierIDAltGr);
01978 }
01979 if (CStringUtil::CaselessCmp::equal(arg, "meta")) {
01980 return static_cast<OptionValue>(kKeyModifierIDMeta);
01981 }
01982 if (CStringUtil::CaselessCmp::equal(arg, "super")) {
01983 return static_cast<OptionValue>(kKeyModifierIDSuper);
01984 }
01985 if (CStringUtil::CaselessCmp::equal(arg, "none")) {
01986 return static_cast<OptionValue>(kKeyModifierIDNull);
01987 }
01988 throw XConfigRead(*this, "invalid argument \"%{1}\"", arg);
01989 }
01990
01991 OptionValue
01992 CConfigReadContext::parseCorner(const CString& arg) const
01993 {
01994 if (CStringUtil::CaselessCmp::equal(arg, "left")) {
01995 return kTopLeftMask | kBottomLeftMask;
01996 }
01997 else if (CStringUtil::CaselessCmp::equal(arg, "right")) {
01998 return kTopRightMask | kBottomRightMask;
01999 }
02000 else if (CStringUtil::CaselessCmp::equal(arg, "top")) {
02001 return kTopLeftMask | kTopRightMask;
02002 }
02003 else if (CStringUtil::CaselessCmp::equal(arg, "bottom")) {
02004 return kBottomLeftMask | kBottomRightMask;
02005 }
02006 else if (CStringUtil::CaselessCmp::equal(arg, "top-left")) {
02007 return kTopLeftMask;
02008 }
02009 else if (CStringUtil::CaselessCmp::equal(arg, "top-right")) {
02010 return kTopRightMask;
02011 }
02012 else if (CStringUtil::CaselessCmp::equal(arg, "bottom-left")) {
02013 return kBottomLeftMask;
02014 }
02015 else if (CStringUtil::CaselessCmp::equal(arg, "bottom-right")) {
02016 return kBottomRightMask;
02017 }
02018 else if (CStringUtil::CaselessCmp::equal(arg, "none")) {
02019 return kNoCornerMask;
02020 }
02021 else if (CStringUtil::CaselessCmp::equal(arg, "all")) {
02022 return kAllCornersMask;
02023 }
02024 throw XConfigRead(*this, "invalid argument \"%{1}\"", arg);
02025 }
02026
02027 OptionValue
02028 CConfigReadContext::parseCorners(const CString& args) const
02029 {
02030
02031 CString::size_type i = args.find_first_not_of(" \t", 0);
02032 if (i == CString::npos) {
02033 throw XConfigRead(*this, "missing corner argument");
02034 }
02035 CString::size_type j = args.find_first_of(" \t", i);
02036
02037
02038 OptionValue corners = parseCorner(args.substr(i, j - i));
02039
02040
02041 i = args.find_first_not_of(" \t", j);
02042 while (i != CString::npos) {
02043
02044 bool add;
02045 if (args[i] == '-') {
02046 add = false;
02047 }
02048 else if (args[i] == '+') {
02049 add = true;
02050 }
02051 else {
02052 throw XConfigRead(*this,
02053 "invalid corner operator \"%{1}\"",
02054 CString(args.c_str() + i, 1));
02055 }
02056
02057
02058 i = args.find_first_not_of(" \t", i + 1);
02059 j = args.find_first_of(" \t", i);
02060 if (i == CString::npos) {
02061 throw XConfigRead(*this, "missing corner argument");
02062 }
02063
02064
02065 if (add) {
02066 corners |= parseCorner(args.substr(i, j - i));
02067 }
02068 else {
02069 corners &= ~parseCorner(args.substr(i, j - i));
02070 }
02071 i = args.find_first_not_of(" \t", j);
02072 }
02073
02074 return corners;
02075 }
02076
02077 CConfig::CInterval
02078 CConfigReadContext::parseInterval(const ArgList& args) const
02079 {
02080 if (args.size() == 0) {
02081 return CConfig::CInterval(0.0f, 1.0f);
02082 }
02083 if (args.size() != 2 || args[0].empty() || args[1].empty()) {
02084 throw XConfigRead(*this, "invalid interval \"%{1}\"", concatArgs(args));
02085 }
02086
02087 char* end;
02088 long startValue = strtol(args[0].c_str(), &end, 10);
02089 if (end[0] != '\0') {
02090 throw XConfigRead(*this, "invalid interval \"%{1}\"", concatArgs(args));
02091 }
02092 long endValue = strtol(args[1].c_str(), &end, 10);
02093 if (end[0] != '\0') {
02094 throw XConfigRead(*this, "invalid interval \"%{1}\"", concatArgs(args));
02095 }
02096
02097 if (startValue < 0 || startValue > 100 ||
02098 endValue < 0 || endValue > 100 ||
02099 startValue >= endValue) {
02100 throw XConfigRead(*this, "invalid interval \"%{1}\"", concatArgs(args));
02101 }
02102
02103 return CConfig::CInterval(startValue / 100.0f, endValue / 100.0f);
02104 }
02105
02106 void
02107 CConfigReadContext::parseNameWithArgs(
02108 const CString& type, const CString& line,
02109 const CString& delim, CString::size_type& index,
02110 CString& name, ArgList& args) const
02111 {
02112
02113 CString::size_type i = line.find_first_not_of(" \t", index);
02114 if (i == CString::npos) {
02115 throw XConfigRead(*this, CString("missing ") + type);
02116 }
02117
02118
02119 CString::size_type j = line.find_first_of(" \t(" + delim, i);
02120 if (j == CString::npos) {
02121 j = line.length();
02122 }
02123
02124
02125 name = line.substr(i, j - i);
02126 args.clear();
02127
02128
02129 bool needDelim = (!delim.empty() && delim.find('\n') == CString::npos);
02130
02131
02132 i = line.find_first_not_of(" \t", j);
02133 if (i == CString::npos && needDelim) {
02134
02135 throw XConfigRead(*this, CString("missing ") + delim[0]);
02136 }
02137 if (i == CString::npos) {
02138
02139 index = line.length();
02140 return;
02141 }
02142 if (line[i] != '(') {
02143
02144 index = i;
02145 return;
02146 }
02147
02148
02149 ++i;
02150
02151
02152 j = line.find_first_of(",)", i);
02153 while (j != CString::npos) {
02154
02155 CString arg(line.substr(i, j - i));
02156 i = j;
02157
02158
02159 j = arg.find_first_not_of(" \t");
02160 if (j != CString::npos) {
02161 arg.erase(0, j);
02162 }
02163 j = arg.find_last_not_of(" \t");
02164 if (j != CString::npos) {
02165 arg.erase(j + 1);
02166 }
02167
02168
02169 args.push_back(arg);
02170
02171
02172 if (line[i] == ')') {
02173 break;
02174 }
02175
02176
02177 ++i;
02178
02179
02180 j = line.find_first_of(",)", i);
02181 }
02182
02183
02184 if (j == CString::npos) {
02185
02186 throw XConfigRead(*this, "missing )");
02187 }
02188
02189
02190 ++i;
02191
02192
02193 j = line.find_first_not_of(" \t", i);
02194 if (j == CString::npos && needDelim) {
02195
02196 throw XConfigRead(*this, CString("missing ") + delim[0]);
02197 }
02198
02199
02200 if (needDelim && delim.find(line[j]) == CString::npos) {
02201 throw XConfigRead(*this, CString("expected ") + delim[0]);
02202 }
02203
02204 if (j == CString::npos) {
02205 j = line.length();
02206 }
02207
02208 index = j;
02209 return;
02210 }
02211
02212 IPlatformScreen::CKeyInfo*
02213 CConfigReadContext::parseKeystroke(const CString& keystroke) const
02214 {
02215 return parseKeystroke(keystroke, std::set<CString>());
02216 }
02217
02218 IPlatformScreen::CKeyInfo*
02219 CConfigReadContext::parseKeystroke(const CString& keystroke,
02220 const std::set<CString>& screens) const
02221 {
02222 CString s = keystroke;
02223
02224 KeyModifierMask mask;
02225 if (!CKeyMap::parseModifiers(s, mask)) {
02226 throw XConfigRead(*this, "unable to parse key modifiers");
02227 }
02228
02229 KeyID key;
02230 if (!CKeyMap::parseKey(s, key)) {
02231 throw XConfigRead(*this, "unable to parse key");
02232 }
02233
02234 if (key == kKeyNone && mask == 0) {
02235 throw XConfigRead(*this, "missing key and/or modifiers in keystroke");
02236 }
02237
02238 return IPlatformScreen::CKeyInfo::alloc(key, mask, 0, 0, screens);
02239 }
02240
02241 IPlatformScreen::CButtonInfo*
02242 CConfigReadContext::parseMouse(const CString& mouse) const
02243 {
02244 CString s = mouse;
02245
02246 KeyModifierMask mask;
02247 if (!CKeyMap::parseModifiers(s, mask)) {
02248 throw XConfigRead(*this, "unable to parse button modifiers");
02249 }
02250
02251 char* end;
02252 ButtonID button = (ButtonID)strtol(s.c_str(), &end, 10);
02253 if (*end != '\0') {
02254 throw XConfigRead(*this, "unable to parse button");
02255 }
02256 if (s.empty() || button <= 0) {
02257 throw XConfigRead(*this, "invalid button");
02258 }
02259
02260 return IPlatformScreen::CButtonInfo::alloc(button, mask);
02261 }
02262
02263 KeyModifierMask
02264 CConfigReadContext::parseModifier(const CString& modifiers) const
02265 {
02266 CString s = modifiers;
02267
02268 KeyModifierMask mask;
02269 if (!CKeyMap::parseModifiers(s, mask)) {
02270 throw XConfigRead(*this, "unable to parse modifiers");
02271 }
02272
02273 if (mask == 0) {
02274 throw XConfigRead(*this, "no modifiers specified");
02275 }
02276
02277 return mask;
02278 }
02279
02280 CString
02281 CConfigReadContext::concatArgs(const ArgList& args)
02282 {
02283 CString s("(");
02284 for (size_t i = 0; i < args.size(); ++i) {
02285 if (i != 0) {
02286 s += ",";
02287 }
02288 s += args[i];
02289 }
02290 s += ")";
02291 return s;
02292 }
02293
02294
02295
02296
02297
02298
02299 XConfigRead::XConfigRead(const CConfigReadContext& context,
02300 const CString& error) :
02301 m_error(CStringUtil::print("line %d: %s",
02302 context.getLineNumber(), error.c_str()))
02303 {
02304
02305 }
02306
02307 XConfigRead::XConfigRead(const CConfigReadContext& context,
02308 const char* errorFmt, const CString& arg) :
02309 m_error(CStringUtil::print("line %d: ", context.getLineNumber()) +
02310 CStringUtil::format(errorFmt, arg.c_str()))
02311 {
02312
02313 }
02314
02315 XConfigRead::~XConfigRead()
02316 {
02317
02318 }
02319
02320 CString
02321 XConfigRead::getWhat() const throw()
02322 {
02323 return format("XConfigRead", "read error: %{1}", m_error.c_str());
02324 }