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