00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "CServer.h"
00016 #include "CClientProxy.h"
00017 #include "CClientProxyUnknown.h"
00018 #include "CPrimaryClient.h"
00019 #include "IPlatformScreen.h"
00020 #include "OptionTypes.h"
00021 #include "ProtocolTypes.h"
00022 #include "XScreen.h"
00023 #include "XSynergy.h"
00024 #include "IDataSocket.h"
00025 #include "IListenSocket.h"
00026 #include "XSocket.h"
00027 #include "IEventQueue.h"
00028 #include "CLog.h"
00029 #include "TMethodEventJob.h"
00030 #include "CArch.h"
00031 #include <cstring>
00032 #include <cstdlib>
00033
00034
00035
00036
00037
00038 CEvent::Type CServer::s_errorEvent = CEvent::kUnknown;
00039 CEvent::Type CServer::s_connectedEvent = CEvent::kUnknown;
00040 CEvent::Type CServer::s_disconnectedEvent = CEvent::kUnknown;
00041 CEvent::Type CServer::s_switchToScreen = CEvent::kUnknown;
00042 CEvent::Type CServer::s_switchInDirection = CEvent::kUnknown;
00043 CEvent::Type CServer::s_keyboardBroadcast = CEvent::kUnknown;
00044 CEvent::Type CServer::s_lockCursorToScreen = CEvent::kUnknown;
00045
00046 CServer::CServer(const CConfig& config, CPrimaryClient* primaryClient) :
00047 m_primaryClient(primaryClient),
00048 m_active(primaryClient),
00049 m_seqNum(0),
00050 m_xDelta(0),
00051 m_yDelta(0),
00052 m_xDelta2(0),
00053 m_yDelta2(0),
00054 m_config(),
00055 m_inputFilter(m_config.getInputFilter()),
00056 m_activeSaver(NULL),
00057 m_switchDir(kNoDirection),
00058 m_switchScreen(NULL),
00059 m_switchWaitDelay(0.0),
00060 m_switchWaitTimer(NULL),
00061 m_switchTwoTapDelay(0.0),
00062 m_switchTwoTapEngaged(false),
00063 m_switchTwoTapArmed(false),
00064 m_switchTwoTapZone(3),
00065 m_relativeMoves(false),
00066 m_keyboardBroadcasting(false),
00067 m_lockedToScreen(false)
00068 {
00069
00070 assert(m_primaryClient != NULL);
00071 assert(config.isScreen(primaryClient->getName()));
00072
00073 CString primaryName = getName(primaryClient);
00074
00075
00076 for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
00077 CClipboardInfo& clipboard = m_clipboards[id];
00078 clipboard.m_clipboardOwner = primaryName;
00079 clipboard.m_clipboardSeqNum = m_seqNum;
00080 if (clipboard.m_clipboard.open(0)) {
00081 clipboard.m_clipboard.empty();
00082 clipboard.m_clipboard.close();
00083 }
00084 clipboard.m_clipboardData = clipboard.m_clipboard.marshall();
00085 }
00086
00087
00088 EVENTQUEUE->adoptHandler(CEvent::kTimer, this,
00089 new TMethodEventJob<CServer>(this,
00090 &CServer::handleSwitchWaitTimeout));
00091 EVENTQUEUE->adoptHandler(IPlatformScreen::getKeyDownEvent(),
00092 m_inputFilter,
00093 new TMethodEventJob<CServer>(this,
00094 &CServer::handleKeyDownEvent));
00095 EVENTQUEUE->adoptHandler(IPlatformScreen::getKeyUpEvent(),
00096 m_inputFilter,
00097 new TMethodEventJob<CServer>(this,
00098 &CServer::handleKeyUpEvent));
00099 EVENTQUEUE->adoptHandler(IPlatformScreen::getKeyRepeatEvent(),
00100 m_inputFilter,
00101 new TMethodEventJob<CServer>(this,
00102 &CServer::handleKeyRepeatEvent));
00103 EVENTQUEUE->adoptHandler(IPlatformScreen::getButtonDownEvent(),
00104 m_inputFilter,
00105 new TMethodEventJob<CServer>(this,
00106 &CServer::handleButtonDownEvent));
00107 EVENTQUEUE->adoptHandler(IPlatformScreen::getButtonUpEvent(),
00108 m_inputFilter,
00109 new TMethodEventJob<CServer>(this,
00110 &CServer::handleButtonUpEvent));
00111 EVENTQUEUE->adoptHandler(IPlatformScreen::getMotionOnPrimaryEvent(),
00112 m_primaryClient->getEventTarget(),
00113 new TMethodEventJob<CServer>(this,
00114 &CServer::handleMotionPrimaryEvent));
00115 EVENTQUEUE->adoptHandler(IPlatformScreen::getMotionOnSecondaryEvent(),
00116 m_primaryClient->getEventTarget(),
00117 new TMethodEventJob<CServer>(this,
00118 &CServer::handleMotionSecondaryEvent));
00119 EVENTQUEUE->adoptHandler(IPlatformScreen::getWheelEvent(),
00120 m_primaryClient->getEventTarget(),
00121 new TMethodEventJob<CServer>(this,
00122 &CServer::handleWheelEvent));
00123 EVENTQUEUE->adoptHandler(IPlatformScreen::getScreensaverActivatedEvent(),
00124 m_primaryClient->getEventTarget(),
00125 new TMethodEventJob<CServer>(this,
00126 &CServer::handleScreensaverActivatedEvent));
00127 EVENTQUEUE->adoptHandler(IPlatformScreen::getScreensaverDeactivatedEvent(),
00128 m_primaryClient->getEventTarget(),
00129 new TMethodEventJob<CServer>(this,
00130 &CServer::handleScreensaverDeactivatedEvent));
00131 EVENTQUEUE->adoptHandler(getSwitchToScreenEvent(),
00132 m_inputFilter,
00133 new TMethodEventJob<CServer>(this,
00134 &CServer::handleSwitchToScreenEvent));
00135 EVENTQUEUE->adoptHandler(getSwitchInDirectionEvent(),
00136 m_inputFilter,
00137 new TMethodEventJob<CServer>(this,
00138 &CServer::handleSwitchInDirectionEvent));
00139 EVENTQUEUE->adoptHandler(getKeyboardBroadcastEvent(),
00140 m_inputFilter,
00141 new TMethodEventJob<CServer>(this,
00142 &CServer::handleKeyboardBroadcastEvent));
00143 EVENTQUEUE->adoptHandler(getLockCursorToScreenEvent(),
00144 m_inputFilter,
00145 new TMethodEventJob<CServer>(this,
00146 &CServer::handleLockCursorToScreenEvent));
00147 EVENTQUEUE->adoptHandler(IPlatformScreen::getFakeInputBeginEvent(),
00148 m_inputFilter,
00149 new TMethodEventJob<CServer>(this,
00150 &CServer::handleFakeInputBeginEvent));
00151 EVENTQUEUE->adoptHandler(IPlatformScreen::getFakeInputEndEvent(),
00152 m_inputFilter,
00153 new TMethodEventJob<CServer>(this,
00154 &CServer::handleFakeInputEndEvent));
00155
00156
00157 addClient(m_primaryClient);
00158
00159
00160 setConfig(config);
00161
00162
00163 m_primaryClient->enable();
00164 m_inputFilter->setPrimaryClient(m_primaryClient);
00165 }
00166
00167 CServer::~CServer()
00168 {
00169
00170 EVENTQUEUE->removeHandler(IPlatformScreen::getKeyDownEvent(),
00171 m_inputFilter);
00172 EVENTQUEUE->removeHandler(IPlatformScreen::getKeyUpEvent(),
00173 m_inputFilter);
00174 EVENTQUEUE->removeHandler(IPlatformScreen::getKeyRepeatEvent(),
00175 m_inputFilter);
00176 EVENTQUEUE->removeHandler(IPlatformScreen::getButtonDownEvent(),
00177 m_inputFilter);
00178 EVENTQUEUE->removeHandler(IPlatformScreen::getButtonUpEvent(),
00179 m_inputFilter);
00180 EVENTQUEUE->removeHandler(IPlatformScreen::getMotionOnPrimaryEvent(),
00181 m_primaryClient->getEventTarget());
00182 EVENTQUEUE->removeHandler(IPlatformScreen::getMotionOnSecondaryEvent(),
00183 m_primaryClient->getEventTarget());
00184 EVENTQUEUE->removeHandler(IPlatformScreen::getWheelEvent(),
00185 m_primaryClient->getEventTarget());
00186 EVENTQUEUE->removeHandler(IPlatformScreen::getScreensaverActivatedEvent(),
00187 m_primaryClient->getEventTarget());
00188 EVENTQUEUE->removeHandler(IPlatformScreen::getScreensaverDeactivatedEvent(),
00189 m_primaryClient->getEventTarget());
00190 EVENTQUEUE->removeHandler(IPlatformScreen::getFakeInputBeginEvent(),
00191 m_inputFilter);
00192 EVENTQUEUE->removeHandler(IPlatformScreen::getFakeInputEndEvent(),
00193 m_inputFilter);
00194 EVENTQUEUE->removeHandler(CEvent::kTimer, this);
00195 stopSwitch();
00196
00197
00198 disconnect();
00199 for (COldClients::iterator index = m_oldClients.begin();
00200 index != m_oldClients.begin(); ++index) {
00201 CBaseClientProxy* client = index->first;
00202 EVENTQUEUE->deleteTimer(index->second);
00203 EVENTQUEUE->removeHandler(CEvent::kTimer, client);
00204 EVENTQUEUE->removeHandler(CClientProxy::getDisconnectedEvent(), client);
00205 delete client;
00206 }
00207
00208
00209 m_inputFilter->setPrimaryClient(NULL);
00210
00211
00212 m_primaryClient->disable();
00213 removeClient(m_primaryClient);
00214 }
00215
00216 bool
00217 CServer::setConfig(const CConfig& config)
00218 {
00219
00220 if (!config.isScreen(m_primaryClient->getName())) {
00221 return false;
00222 }
00223
00224
00225
00226 closeClients(config);
00227
00228
00229 m_config = config;
00230 processOptions();
00231
00232
00233
00234
00235
00236
00237
00238
00239 if (!m_config.hasLockToScreenAction()) {
00240 IPlatformScreen::CKeyInfo* key =
00241 IPlatformScreen::CKeyInfo::alloc(kKeyScrollLock, 0, 0, 0);
00242 CInputFilter::CRule rule(new CInputFilter::CKeystrokeCondition(key));
00243 rule.adoptAction(new CInputFilter::CLockCursorToScreenAction, true);
00244 m_inputFilter->addFilterRule(rule);
00245 }
00246
00247
00248 m_primaryClient->reconfigure(getActivePrimarySides());
00249
00250
00251 for (CClientList::const_iterator index = m_clients.begin();
00252 index != m_clients.end(); ++index) {
00253 CBaseClientProxy* client = index->second;
00254 sendOptions(client);
00255 }
00256
00257 return true;
00258 }
00259
00260 void
00261 CServer::adoptClient(CBaseClientProxy* client)
00262 {
00263 assert(client != NULL);
00264
00265
00266 EVENTQUEUE->adoptHandler(CClientProxy::getDisconnectedEvent(), client,
00267 new TMethodEventJob<CServer>(this,
00268 &CServer::handleClientDisconnected, client));
00269
00270
00271 if (!m_config.isScreen(client->getName())) {
00272 LOG((CLOG_WARN "a client with name \"%s\" is not in the map", client->getName().c_str()));
00273 closeClient(client, kMsgEUnknown);
00274 return;
00275 }
00276
00277
00278 if (!addClient(client)) {
00279
00280 LOG((CLOG_WARN "a client with name \"%s\" is already connected", getName(client).c_str()));
00281 closeClient(client, kMsgEBusy);
00282 return;
00283 }
00284 LOG((CLOG_NOTE "client \"%s\" has connected", getName(client).c_str()));
00285
00286
00287 sendOptions(client);
00288
00289
00290 if (m_activeSaver != NULL) {
00291 client->screensaver(true);
00292 }
00293
00294
00295 CServer::CScreenConnectedInfo* info =
00296 CServer::CScreenConnectedInfo::alloc(getName(client));
00297 EVENTQUEUE->addEvent(CEvent(CServer::getConnectedEvent(),
00298 m_primaryClient->getEventTarget(), info));
00299 }
00300
00301 void
00302 CServer::disconnect()
00303 {
00304
00305 if (m_clients.size() > 1 || !m_oldClients.empty()) {
00306 CConfig emptyConfig;
00307 closeClients(emptyConfig);
00308 }
00309 else {
00310 EVENTQUEUE->addEvent(CEvent(getDisconnectedEvent(), this));
00311 }
00312 }
00313
00314 UInt32
00315 CServer::getNumClients() const
00316 {
00317 return m_clients.size();
00318 }
00319
00320 void
00321 CServer::getClients(std::vector<CString>& list) const
00322 {
00323 list.clear();
00324 for (CClientList::const_iterator index = m_clients.begin();
00325 index != m_clients.end(); ++index) {
00326 list.push_back(index->first);
00327 }
00328 }
00329
00330 CEvent::Type
00331 CServer::getErrorEvent()
00332 {
00333 return CEvent::registerTypeOnce(s_errorEvent,
00334 "CServer::error");
00335 }
00336
00337 CEvent::Type
00338 CServer::getConnectedEvent()
00339 {
00340 return CEvent::registerTypeOnce(s_connectedEvent,
00341 "CServer::connected");
00342 }
00343
00344 CEvent::Type
00345 CServer::getDisconnectedEvent()
00346 {
00347 return CEvent::registerTypeOnce(s_disconnectedEvent,
00348 "CServer::disconnected");
00349 }
00350
00351 CEvent::Type
00352 CServer::getSwitchToScreenEvent()
00353 {
00354 return CEvent::registerTypeOnce(s_switchToScreen,
00355 "CServer::switchToScreen");
00356 }
00357
00358 CEvent::Type
00359 CServer::getSwitchInDirectionEvent()
00360 {
00361 return CEvent::registerTypeOnce(s_switchInDirection,
00362 "CServer::switchInDirection");
00363 }
00364
00365 CEvent::Type
00366 CServer::getKeyboardBroadcastEvent()
00367 {
00368 return CEvent::registerTypeOnce(s_keyboardBroadcast,
00369 "CServer:keyboardBroadcast");
00370 }
00371
00372 CEvent::Type
00373 CServer::getLockCursorToScreenEvent()
00374 {
00375 return CEvent::registerTypeOnce(s_lockCursorToScreen,
00376 "CServer::lockCursorToScreen");
00377 }
00378
00379 CString
00380 CServer::getName(const CBaseClientProxy* client) const
00381 {
00382 CString name = m_config.getCanonicalName(client->getName());
00383 if (name.empty()) {
00384 name = client->getName();
00385 }
00386 return name;
00387 }
00388
00389 UInt32
00390 CServer::getActivePrimarySides() const
00391 {
00392 UInt32 sides = 0;
00393 if (!isLockedToScreenServer()) {
00394 if (hasAnyNeighbor(m_primaryClient, kLeft)) {
00395 sides |= kLeftMask;
00396 }
00397 if (hasAnyNeighbor(m_primaryClient, kRight)) {
00398 sides |= kRightMask;
00399 }
00400 if (hasAnyNeighbor(m_primaryClient, kTop)) {
00401 sides |= kTopMask;
00402 }
00403 if (hasAnyNeighbor(m_primaryClient, kBottom)) {
00404 sides |= kBottomMask;
00405 }
00406 }
00407 return sides;
00408 }
00409
00410 bool
00411 CServer::isLockedToScreenServer() const
00412 {
00413
00414 return m_lockedToScreen;
00415 }
00416
00417 bool
00418 CServer::isLockedToScreen() const
00419 {
00420
00421 if (isLockedToScreenServer()) {
00422 LOG((CLOG_DEBUG "locked to screen"));
00423 return true;
00424 }
00425
00426
00427 if (m_primaryClient->isLockedToScreen()) {
00428 return true;
00429 }
00430
00431
00432 return false;
00433 }
00434
00435 SInt32
00436 CServer::getJumpZoneSize(CBaseClientProxy* client) const
00437 {
00438 if (client == m_primaryClient) {
00439 return m_primaryClient->getJumpZoneSize();
00440 }
00441 else {
00442 return 0;
00443 }
00444 }
00445
00446 void
00447 CServer::switchScreen(CBaseClientProxy* dst,
00448 SInt32 x, SInt32 y, bool forScreensaver)
00449 {
00450 assert(dst != NULL);
00451 #ifndef NDEBUG
00452 {
00453 SInt32 dx, dy, dw, dh;
00454 dst->getShape(dx, dy, dw, dh);
00455 assert(x >= dx && y >= dy && x < dx + dw && y < dy + dh);
00456 }
00457 #endif
00458 assert(m_active != NULL);
00459
00460 LOG((CLOG_INFO "switch from \"%s\" to \"%s\" at %d,%d", getName(m_active).c_str(), getName(dst).c_str(), x, y));
00461
00462
00463 stopSwitch();
00464
00465
00466 m_x = x;
00467 m_y = y;
00468 m_xDelta = 0;
00469 m_yDelta = 0;
00470 m_xDelta2 = 0;
00471 m_yDelta2 = 0;
00472
00473
00474
00475
00476 if (m_active != dst) {
00477
00478 if (!m_active->leave()) {
00479
00480 LOG((CLOG_WARN "can't leave screen"));
00481 return;
00482 }
00483
00484
00485
00486 if (m_active == m_primaryClient) {
00487 for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
00488 CClipboardInfo& clipboard = m_clipboards[id];
00489 if (clipboard.m_clipboardOwner == getName(m_primaryClient)) {
00490 onClipboardChanged(m_primaryClient,
00491 id, clipboard.m_clipboardSeqNum);
00492 }
00493 }
00494 }
00495
00496
00497 m_active = dst;
00498
00499
00500 ++m_seqNum;
00501
00502
00503 m_active->enter(x, y, m_seqNum,
00504 m_primaryClient->getToggleMask(),
00505 forScreensaver);
00506
00507
00508 for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
00509 m_active->setClipboard(id, &m_clipboards[id].m_clipboard);
00510 }
00511 }
00512 else {
00513 m_active->mouseMove(x, y);
00514 }
00515 }
00516
00517 void
00518 CServer::jumpToScreen(CBaseClientProxy* newScreen)
00519 {
00520 assert(newScreen != NULL);
00521
00522
00523 m_active->setJumpCursorPos(m_x, m_y);
00524
00525
00526 SInt32 x, y;
00527 newScreen->getJumpCursorPos(x, y);
00528
00529 switchScreen(newScreen, x, y, false);
00530 }
00531
00532 float
00533 CServer::mapToFraction(CBaseClientProxy* client,
00534 EDirection dir, SInt32 x, SInt32 y) const
00535 {
00536 SInt32 sx, sy, sw, sh;
00537 client->getShape(sx, sy, sw, sh);
00538 switch (dir) {
00539 case kLeft:
00540 case kRight:
00541 return static_cast<float>(y - sy + 0.5f) / static_cast<float>(sh);
00542
00543 case kTop:
00544 case kBottom:
00545 return static_cast<float>(x - sx + 0.5f) / static_cast<float>(sw);
00546
00547 case kNoDirection:
00548 assert(0 && "bad direction");
00549 break;
00550 }
00551 return 0.0f;
00552 }
00553
00554 void
00555 CServer::mapToPixel(CBaseClientProxy* client,
00556 EDirection dir, float f, SInt32& x, SInt32& y) const
00557 {
00558 SInt32 sx, sy, sw, sh;
00559 client->getShape(sx, sy, sw, sh);
00560 switch (dir) {
00561 case kLeft:
00562 case kRight:
00563 y = static_cast<SInt32>(f * sh) + sy;
00564 break;
00565
00566 case kTop:
00567 case kBottom:
00568 x = static_cast<SInt32>(f * sw) + sx;
00569 break;
00570
00571 case kNoDirection:
00572 assert(0 && "bad direction");
00573 break;
00574 }
00575 }
00576
00577 bool
00578 CServer::hasAnyNeighbor(CBaseClientProxy* client, EDirection dir) const
00579 {
00580 assert(client != NULL);
00581
00582 return m_config.hasNeighbor(getName(client), dir);
00583 }
00584
00585 CBaseClientProxy*
00586 CServer::getNeighbor(CBaseClientProxy* src,
00587 EDirection dir, SInt32& x, SInt32& y) const
00588 {
00589
00590
00591 assert(src != NULL);
00592
00593
00594 CString srcName = getName(src);
00595 assert(!srcName.empty());
00596 LOG((CLOG_DEBUG2 "find neighbor on %s of \"%s\"", CConfig::dirName(dir), srcName.c_str()));
00597
00598
00599 float t = mapToFraction(src, dir, x, y);
00600
00601
00602 float tTmp;
00603 for (;;) {
00604 CString dstName(m_config.getNeighbor(srcName, dir, t, &tTmp));
00605
00606
00607
00608
00609
00610 if (dstName.empty()) {
00611 LOG((CLOG_DEBUG2 "no neighbor on %s of \"%s\"", CConfig::dirName(dir), srcName.c_str()));
00612 return NULL;
00613 }
00614
00615
00616
00617 CClientList::const_iterator index = m_clients.find(dstName);
00618 if (index != m_clients.end()) {
00619 LOG((CLOG_DEBUG2 "\"%s\" is on %s of \"%s\" at %f", dstName.c_str(), CConfig::dirName(dir), srcName.c_str(), t));
00620 mapToPixel(index->second, dir, tTmp, x, y);
00621 return index->second;
00622 }
00623
00624
00625 LOG((CLOG_DEBUG2 "ignored \"%s\" on %s of \"%s\"", dstName.c_str(), CConfig::dirName(dir), srcName.c_str()));
00626 srcName = dstName;
00627
00628
00629 t = tTmp;
00630 }
00631 }
00632
00633 CBaseClientProxy*
00634 CServer::mapToNeighbor(CBaseClientProxy* src,
00635 EDirection srcSide, SInt32& x, SInt32& y) const
00636 {
00637
00638
00639 assert(src != NULL);
00640
00641
00642 CBaseClientProxy* dst = getNeighbor(src, srcSide, x, y);
00643 if (dst == NULL) {
00644 return NULL;
00645 }
00646
00647
00648 SInt32 dx, dy, dw, dh;
00649 CBaseClientProxy* lastGoodScreen = src;
00650 lastGoodScreen->getShape(dx, dy, dw, dh);
00651
00652
00653
00654
00655
00656
00657 switch (srcSide) {
00658 case kLeft:
00659 x -= dx;
00660 while (dst != NULL) {
00661 lastGoodScreen = dst;
00662 lastGoodScreen->getShape(dx, dy, dw, dh);
00663 x += dw;
00664 if (x >= 0) {
00665 break;
00666 }
00667 LOG((CLOG_DEBUG2 "skipping over screen %s", getName(dst).c_str()));
00668 dst = getNeighbor(lastGoodScreen, srcSide, x, y);
00669 }
00670 assert(lastGoodScreen != NULL);
00671 x += dx;
00672 break;
00673
00674 case kRight:
00675 x -= dx;
00676 while (dst != NULL) {
00677 x -= dw;
00678 lastGoodScreen = dst;
00679 lastGoodScreen->getShape(dx, dy, dw, dh);
00680 if (x < dw) {
00681 break;
00682 }
00683 LOG((CLOG_DEBUG2 "skipping over screen %s", getName(dst).c_str()));
00684 dst = getNeighbor(lastGoodScreen, srcSide, x, y);
00685 }
00686 assert(lastGoodScreen != NULL);
00687 x += dx;
00688 break;
00689
00690 case kTop:
00691 y -= dy;
00692 while (dst != NULL) {
00693 lastGoodScreen = dst;
00694 lastGoodScreen->getShape(dx, dy, dw, dh);
00695 y += dh;
00696 if (y >= 0) {
00697 break;
00698 }
00699 LOG((CLOG_DEBUG2 "skipping over screen %s", getName(dst).c_str()));
00700 dst = getNeighbor(lastGoodScreen, srcSide, x, y);
00701 }
00702 assert(lastGoodScreen != NULL);
00703 y += dy;
00704 break;
00705
00706 case kBottom:
00707 y -= dy;
00708 while (dst != NULL) {
00709 y -= dh;
00710 lastGoodScreen = dst;
00711 lastGoodScreen->getShape(dx, dy, dw, dh);
00712 if (y < dh) {
00713 break;
00714 }
00715 LOG((CLOG_DEBUG2 "skipping over screen %s", getName(dst).c_str()));
00716 dst = getNeighbor(lastGoodScreen, srcSide, x, y);
00717 }
00718 assert(lastGoodScreen != NULL);
00719 y += dy;
00720 break;
00721
00722 case kNoDirection:
00723 assert(0 && "bad direction");
00724 return NULL;
00725 }
00726
00727
00728 assert(lastGoodScreen != NULL);
00729 dst = lastGoodScreen;
00730
00731
00732
00733
00734
00735 avoidJumpZone(dst, srcSide, x, y);
00736
00737 return dst;
00738 }
00739
00740 void
00741 CServer::avoidJumpZone(CBaseClientProxy* dst,
00742 EDirection dir, SInt32& x, SInt32& y) const
00743 {
00744
00745 if (dst != m_primaryClient) {
00746 return;
00747 }
00748
00749 const CString dstName(getName(dst));
00750 SInt32 dx, dy, dw, dh;
00751 dst->getShape(dx, dy, dw, dh);
00752 float t = mapToFraction(dst, dir, x, y);
00753 SInt32 z = getJumpZoneSize(dst);
00754
00755
00756
00757
00758 switch (dir) {
00759 case kLeft:
00760 if (!m_config.getNeighbor(dstName, kRight, t, NULL).empty() &&
00761 x > dx + dw - 1 - z)
00762 x = dx + dw - 1 - z;
00763 break;
00764
00765 case kRight:
00766 if (!m_config.getNeighbor(dstName, kLeft, t, NULL).empty() &&
00767 x < dx + z)
00768 x = dx + z;
00769 break;
00770
00771 case kTop:
00772 if (!m_config.getNeighbor(dstName, kBottom, t, NULL).empty() &&
00773 y > dy + dh - 1 - z)
00774 y = dy + dh - 1 - z;
00775 break;
00776
00777 case kBottom:
00778 if (!m_config.getNeighbor(dstName, kTop, t, NULL).empty() &&
00779 y < dy + z)
00780 y = dy + z;
00781 break;
00782
00783 case kNoDirection:
00784 assert(0 && "bad direction");
00785 }
00786 }
00787
00788 bool
00789 CServer::isSwitchOkay(CBaseClientProxy* newScreen,
00790 EDirection dir, SInt32 x, SInt32 y,
00791 SInt32 xActive, SInt32 yActive)
00792 {
00793 LOG((CLOG_DEBUG1 "try to leave \"%s\" on %s", getName(m_active).c_str(), CConfig::dirName(dir)));
00794
00795
00796 if (newScreen == NULL) {
00797
00798
00799 LOG((CLOG_DEBUG1 "no neighbor %s", CConfig::dirName(dir)));
00800 stopSwitch();
00801 return false;
00802 }
00803
00804
00805 bool preventSwitch = false;
00806 bool allowSwitch = false;
00807
00808
00809
00810 bool isNewDirection = (dir != m_switchDir);
00811 if (isNewDirection || m_switchScreen == NULL) {
00812 m_switchDir = dir;
00813 m_switchScreen = newScreen;
00814 }
00815
00816
00817 if (!allowSwitch && m_switchTwoTapDelay > 0.0) {
00818 if (isNewDirection ||
00819 !isSwitchTwoTapStarted() || !shouldSwitchTwoTap()) {
00820
00821
00822 preventSwitch = true;
00823 startSwitchTwoTap();
00824 }
00825 else {
00826
00827 allowSwitch = true;
00828 }
00829 }
00830
00831
00832 if (!allowSwitch && m_switchWaitDelay > 0.0) {
00833 if (isNewDirection || !isSwitchWaitStarted()) {
00834 startSwitchWait(x, y);
00835 }
00836 preventSwitch = true;
00837 }
00838
00839
00840
00841 const CConfig::CScreenOptions* options =
00842 m_config.getOptions(getName(m_active));
00843 if (options == NULL || options->count(kOptionScreenSwitchCorners) == 0) {
00844 options = m_config.getOptions("");
00845 }
00846 if (options != NULL && options->count(kOptionScreenSwitchCorners) > 0) {
00847
00848 CConfig::CScreenOptions::const_iterator i =
00849 options->find(kOptionScreenSwitchCorners);
00850 UInt32 corners = static_cast<UInt32>(i->second);
00851 i = options->find(kOptionScreenSwitchCornerSize);
00852 SInt32 size = 0;
00853 if (i != options->end()) {
00854 size = i->second;
00855 }
00856
00857
00858 if ((getCorner(m_active, xActive, yActive, size) & corners) != 0) {
00859
00860 LOG((CLOG_DEBUG1 "locked in corner"));
00861 preventSwitch = true;
00862 stopSwitch();
00863 }
00864 }
00865
00866
00867 if (!preventSwitch && isLockedToScreen()) {
00868 LOG((CLOG_DEBUG1 "locked to screen"));
00869 preventSwitch = true;
00870 stopSwitch();
00871 }
00872
00873 return !preventSwitch;
00874 }
00875
00876 void
00877 CServer::noSwitch(SInt32 x, SInt32 y)
00878 {
00879 armSwitchTwoTap(x, y);
00880 stopSwitchWait();
00881 }
00882
00883 void
00884 CServer::stopSwitch()
00885 {
00886 if (m_switchScreen != NULL) {
00887 m_switchScreen = NULL;
00888 m_switchDir = kNoDirection;
00889 stopSwitchTwoTap();
00890 stopSwitchWait();
00891 }
00892 }
00893
00894 void
00895 CServer::startSwitchTwoTap()
00896 {
00897 m_switchTwoTapEngaged = true;
00898 m_switchTwoTapArmed = false;
00899 m_switchTwoTapTimer.reset();
00900 LOG((CLOG_DEBUG1 "waiting for second tap"));
00901 }
00902
00903 void
00904 CServer::armSwitchTwoTap(SInt32 x, SInt32 y)
00905 {
00906 if (m_switchTwoTapEngaged) {
00907 if (m_switchTwoTapTimer.getTime() > m_switchTwoTapDelay) {
00908
00909 stopSwitchTwoTap();
00910 }
00911 else if (!m_switchTwoTapArmed) {
00912
00913
00914 SInt32 ax, ay, aw, ah;
00915 m_active->getShape(ax, ay, aw, ah);
00916 SInt32 tapZone = m_primaryClient->getJumpZoneSize();
00917 if (tapZone < m_switchTwoTapZone) {
00918 tapZone = m_switchTwoTapZone;
00919 }
00920 if (x >= ax + tapZone && x < ax + aw - tapZone &&
00921 y >= ay + tapZone && y < ay + ah - tapZone) {
00922
00923
00924
00925 switch (m_switchDir) {
00926 case kLeft:
00927 m_switchTwoTapArmed = (m_xDelta > 0 && m_xDelta2 > 0);
00928 break;
00929
00930 case kRight:
00931 m_switchTwoTapArmed = (m_xDelta < 0 && m_xDelta2 < 0);
00932 break;
00933
00934 case kTop:
00935 m_switchTwoTapArmed = (m_yDelta > 0 && m_yDelta2 > 0);
00936 break;
00937
00938 case kBottom:
00939 m_switchTwoTapArmed = (m_yDelta < 0 && m_yDelta2 < 0);
00940 break;
00941
00942 default:
00943 break;
00944 }
00945 }
00946 }
00947 }
00948 }
00949
00950 void
00951 CServer::stopSwitchTwoTap()
00952 {
00953 m_switchTwoTapEngaged = false;
00954 m_switchTwoTapArmed = false;
00955 }
00956
00957 bool
00958 CServer::isSwitchTwoTapStarted() const
00959 {
00960 return m_switchTwoTapEngaged;
00961 }
00962
00963 bool
00964 CServer::shouldSwitchTwoTap() const
00965 {
00966
00967
00968 return (m_switchTwoTapArmed &&
00969 m_switchTwoTapTimer.getTime() <= m_switchTwoTapDelay);
00970 }
00971
00972 void
00973 CServer::startSwitchWait(SInt32 x, SInt32 y)
00974 {
00975 stopSwitchWait();
00976 m_switchWaitX = x;
00977 m_switchWaitY = y;
00978 m_switchWaitTimer = EVENTQUEUE->newOneShotTimer(m_switchWaitDelay, this);
00979 LOG((CLOG_DEBUG1 "waiting to switch"));
00980 }
00981
00982 void
00983 CServer::stopSwitchWait()
00984 {
00985 if (m_switchWaitTimer != NULL) {
00986 EVENTQUEUE->deleteTimer(m_switchWaitTimer);
00987 m_switchWaitTimer = NULL;
00988 }
00989 }
00990
00991 bool
00992 CServer::isSwitchWaitStarted() const
00993 {
00994 return (m_switchWaitTimer != NULL);
00995 }
00996
00997 UInt32
00998 CServer::getCorner(CBaseClientProxy* client,
00999 SInt32 x, SInt32 y, SInt32 size) const
01000 {
01001 assert(client != NULL);
01002
01003
01004 SInt32 ax, ay, aw, ah;
01005 client->getShape(ax, ay, aw, ah);
01006
01007
01008 SInt32 xSide;
01009 if (x <= ax) {
01010 xSide = -1;
01011 }
01012 else if (x >= ax + aw - 1) {
01013 xSide = 1;
01014 }
01015 else {
01016 xSide = 0;
01017 }
01018
01019
01020 SInt32 ySide;
01021 if (y <= ay) {
01022 ySide = -1;
01023 }
01024 else if (y >= ay + ah - 1) {
01025 ySide = 1;
01026 }
01027 else {
01028 ySide = 0;
01029 }
01030
01031
01032 if (xSide != 0) {
01033 if (y < ay + size) {
01034 return (xSide < 0) ? kTopLeftMask : kTopRightMask;
01035 }
01036 else if (y >= ay + ah - size) {
01037 return (xSide < 0) ? kBottomLeftMask : kBottomRightMask;
01038 }
01039 }
01040
01041
01042 if (ySide != 0) {
01043 if (x < ax + size) {
01044 return (ySide < 0) ? kTopLeftMask : kBottomLeftMask;
01045 }
01046 else if (x >= ax + aw - size) {
01047 return (ySide < 0) ? kTopRightMask : kBottomRightMask;
01048 }
01049 }
01050
01051 return kNoCornerMask;
01052 }
01053
01054 void
01055 CServer::stopRelativeMoves()
01056 {
01057 if (m_relativeMoves && m_active != m_primaryClient) {
01058
01059 SInt32 ax, ay, aw, ah;
01060 m_active->getShape(ax, ay, aw, ah);
01061 m_x = ax + (aw >> 1);
01062 m_y = ay + (ah >> 1);
01063 m_xDelta = 0;
01064 m_yDelta = 0;
01065 m_xDelta2 = 0;
01066 m_yDelta2 = 0;
01067 LOG((CLOG_DEBUG2 "synchronize move on %s by %d,%d", getName(m_active).c_str(), m_x, m_y));
01068 m_active->mouseMove(m_x, m_y);
01069 }
01070 }
01071
01072 void
01073 CServer::sendOptions(CBaseClientProxy* client) const
01074 {
01075 COptionsList optionsList;
01076
01077
01078 const CConfig::CScreenOptions* options =
01079 m_config.getOptions(getName(client));
01080 if (options != NULL) {
01081
01082 optionsList.reserve(2 * options->size());
01083 for (CConfig::CScreenOptions::const_iterator index = options->begin();
01084 index != options->end(); ++index) {
01085 optionsList.push_back(index->first);
01086 optionsList.push_back(static_cast<UInt32>(index->second));
01087 }
01088 }
01089
01090
01091 options = m_config.getOptions("");
01092 if (options != NULL) {
01093
01094 optionsList.reserve(optionsList.size() + 2 * options->size());
01095 for (CConfig::CScreenOptions::const_iterator index = options->begin();
01096 index != options->end(); ++index) {
01097 optionsList.push_back(index->first);
01098 optionsList.push_back(static_cast<UInt32>(index->second));
01099 }
01100 }
01101
01102
01103 client->resetOptions();
01104 client->setOptions(optionsList);
01105 }
01106
01107 void
01108 CServer::processOptions()
01109 {
01110 const CConfig::CScreenOptions* options = m_config.getOptions("");
01111 if (options == NULL) {
01112 return;
01113 }
01114
01115 bool newRelativeMoves = m_relativeMoves;
01116 for (CConfig::CScreenOptions::const_iterator index = options->begin();
01117 index != options->end(); ++index) {
01118 const OptionID id = index->first;
01119 const OptionValue value = index->second;
01120 if (id == kOptionScreenSwitchDelay) {
01121 m_switchWaitDelay = 1.0e-3 * static_cast<double>(value);
01122 if (m_switchWaitDelay < 0.0) {
01123 m_switchWaitDelay = 0.0;
01124 }
01125 stopSwitchWait();
01126 }
01127 else if (id == kOptionScreenSwitchTwoTap) {
01128 m_switchTwoTapDelay = 1.0e-3 * static_cast<double>(value);
01129 if (m_switchTwoTapDelay < 0.0) {
01130 m_switchTwoTapDelay = 0.0;
01131 }
01132 stopSwitchTwoTap();
01133 }
01134 else if (id == kOptionRelativeMouseMoves) {
01135 newRelativeMoves = (value != 0);
01136 }
01137 }
01138
01139 if (m_relativeMoves && !newRelativeMoves) {
01140 stopRelativeMoves();
01141 }
01142 m_relativeMoves = newRelativeMoves;
01143 }
01144
01145 void
01146 CServer::handleShapeChanged(const CEvent&, void* vclient)
01147 {
01148
01149 CBaseClientProxy* client = reinterpret_cast<CBaseClientProxy*>(vclient);
01150 if (m_clientSet.count(client) == 0) {
01151 return;
01152 }
01153
01154 LOG((CLOG_INFO "screen \"%s\" shape changed", getName(client).c_str()));
01155
01156
01157 SInt32 x, y;
01158 client->getCursorPos(x, y);
01159 client->setJumpCursorPos(x, y);
01160
01161
01162 if (client == m_active) {
01163 m_x = x;
01164 m_y = y;
01165 }
01166
01167
01168 if (client == m_primaryClient) {
01169 if (client == m_active) {
01170 onMouseMovePrimary(m_x, m_y);
01171 }
01172 else {
01173 onMouseMoveSecondary(0, 0);
01174 }
01175 }
01176 }
01177
01178 void
01179 CServer::handleClipboardGrabbed(const CEvent& event, void* vclient)
01180 {
01181
01182 CBaseClientProxy* grabber = reinterpret_cast<CBaseClientProxy*>(vclient);
01183 if (m_clientSet.count(grabber) == 0) {
01184 return;
01185 }
01186 const IScreen::CClipboardInfo* info =
01187 reinterpret_cast<const IScreen::CClipboardInfo*>(event.getData());
01188
01189
01190
01191 CClipboardInfo& clipboard = m_clipboards[info->m_id];
01192 if (grabber != m_primaryClient &&
01193 info->m_sequenceNumber < clipboard.m_clipboardSeqNum) {
01194 LOG((CLOG_INFO "ignored screen \"%s\" grab of clipboard %d", getName(grabber).c_str(), info->m_id));
01195 return;
01196 }
01197
01198
01199 LOG((CLOG_INFO "screen \"%s\" grabbed clipboard %d from \"%s\"", getName(grabber).c_str(), info->m_id, clipboard.m_clipboardOwner.c_str()));
01200 clipboard.m_clipboardOwner = getName(grabber);
01201 clipboard.m_clipboardSeqNum = info->m_sequenceNumber;
01202
01203
01204 if (clipboard.m_clipboard.open(0)) {
01205 clipboard.m_clipboard.empty();
01206 clipboard.m_clipboard.close();
01207 }
01208 clipboard.m_clipboardData = clipboard.m_clipboard.marshall();
01209
01210
01211
01212 for (CClientList::iterator index = m_clients.begin();
01213 index != m_clients.end(); ++index) {
01214 CBaseClientProxy* client = index->second;
01215 if (client == grabber) {
01216 client->setClipboardDirty(info->m_id, false);
01217 }
01218 else {
01219 client->grabClipboard(info->m_id);
01220 }
01221 }
01222 }
01223
01224 void
01225 CServer::handleClipboardChanged(const CEvent& event, void* vclient)
01226 {
01227
01228 CBaseClientProxy* sender = reinterpret_cast<CBaseClientProxy*>(vclient);
01229 if (m_clientSet.count(sender) == 0) {
01230 return;
01231 }
01232 const IScreen::CClipboardInfo* info =
01233 reinterpret_cast<const IScreen::CClipboardInfo*>(event.getData());
01234 onClipboardChanged(sender, info->m_id, info->m_sequenceNumber);
01235 }
01236
01237 void
01238 CServer::handleKeyDownEvent(const CEvent& event, void*)
01239 {
01240 IPlatformScreen::CKeyInfo* info =
01241 reinterpret_cast<IPlatformScreen::CKeyInfo*>(event.getData());
01242 onKeyDown(info->m_key, info->m_mask, info->m_button, info->m_screens);
01243 }
01244
01245 void
01246 CServer::handleKeyUpEvent(const CEvent& event, void*)
01247 {
01248 IPlatformScreen::CKeyInfo* info =
01249 reinterpret_cast<IPlatformScreen::CKeyInfo*>(event.getData());
01250 onKeyUp(info->m_key, info->m_mask, info->m_button, info->m_screens);
01251 }
01252
01253 void
01254 CServer::handleKeyRepeatEvent(const CEvent& event, void*)
01255 {
01256 IPlatformScreen::CKeyInfo* info =
01257 reinterpret_cast<IPlatformScreen::CKeyInfo*>(event.getData());
01258 onKeyRepeat(info->m_key, info->m_mask, info->m_count, info->m_button);
01259 }
01260
01261 void
01262 CServer::handleButtonDownEvent(const CEvent& event, void*)
01263 {
01264 IPlatformScreen::CButtonInfo* info =
01265 reinterpret_cast<IPlatformScreen::CButtonInfo*>(event.getData());
01266 onMouseDown(info->m_button);
01267 }
01268
01269 void
01270 CServer::handleButtonUpEvent(const CEvent& event, void*)
01271 {
01272 IPlatformScreen::CButtonInfo* info =
01273 reinterpret_cast<IPlatformScreen::CButtonInfo*>(event.getData());
01274 onMouseUp(info->m_button);
01275 }
01276
01277 void
01278 CServer::handleMotionPrimaryEvent(const CEvent& event, void*)
01279 {
01280 IPlatformScreen::CMotionInfo* info =
01281 reinterpret_cast<IPlatformScreen::CMotionInfo*>(event.getData());
01282 onMouseMovePrimary(info->m_x, info->m_y);
01283 }
01284
01285 void
01286 CServer::handleMotionSecondaryEvent(const CEvent& event, void*)
01287 {
01288 IPlatformScreen::CMotionInfo* info =
01289 reinterpret_cast<IPlatformScreen::CMotionInfo*>(event.getData());
01290 onMouseMoveSecondary(info->m_x, info->m_y);
01291 }
01292
01293 void
01294 CServer::handleWheelEvent(const CEvent& event, void*)
01295 {
01296 IPlatformScreen::CWheelInfo* info =
01297 reinterpret_cast<IPlatformScreen::CWheelInfo*>(event.getData());
01298 onMouseWheel(info->m_xDelta, info->m_yDelta);
01299 }
01300
01301 void
01302 CServer::handleScreensaverActivatedEvent(const CEvent&, void*)
01303 {
01304 onScreensaver(true);
01305 }
01306
01307 void
01308 CServer::handleScreensaverDeactivatedEvent(const CEvent&, void*)
01309 {
01310 onScreensaver(false);
01311 }
01312
01313 void
01314 CServer::handleSwitchWaitTimeout(const CEvent&, void*)
01315 {
01316
01317 if (isLockedToScreen()) {
01318 LOG((CLOG_DEBUG1 "locked to screen"));
01319 stopSwitch();
01320 return;
01321 }
01322
01323
01324 switchScreen(m_switchScreen, m_switchWaitX, m_switchWaitY, false);
01325 }
01326
01327 void
01328 CServer::handleClientDisconnected(const CEvent&, void* vclient)
01329 {
01330
01331
01332 CBaseClientProxy* client = reinterpret_cast<CBaseClientProxy*>(vclient);
01333 removeActiveClient(client);
01334 removeOldClient(client);
01335 delete client;
01336 }
01337
01338 void
01339 CServer::handleClientCloseTimeout(const CEvent&, void* vclient)
01340 {
01341
01342 CBaseClientProxy* client = reinterpret_cast<CBaseClientProxy*>(vclient);
01343 LOG((CLOG_NOTE "forced disconnection of client \"%s\"", getName(client).c_str()));
01344 removeOldClient(client);
01345 delete client;
01346 }
01347
01348 void
01349 CServer::handleSwitchToScreenEvent(const CEvent& event, void*)
01350 {
01351 CSwitchToScreenInfo* info =
01352 reinterpret_cast<CSwitchToScreenInfo*>(event.getData());
01353
01354 CClientList::const_iterator index = m_clients.find(info->m_screen);
01355 if (index == m_clients.end()) {
01356 LOG((CLOG_DEBUG1 "screen \"%s\" not active", info->m_screen));
01357 }
01358 else {
01359 jumpToScreen(index->second);
01360 }
01361 }
01362
01363 void
01364 CServer::handleSwitchInDirectionEvent(const CEvent& event, void*)
01365 {
01366 CSwitchInDirectionInfo* info =
01367 reinterpret_cast<CSwitchInDirectionInfo*>(event.getData());
01368
01369
01370 SInt32 x = m_x, y = m_y;
01371 CBaseClientProxy* newScreen =
01372 getNeighbor(m_active, info->m_direction, x, y);
01373 if (newScreen == NULL) {
01374 LOG((CLOG_DEBUG1 "no neighbor %s", CConfig::dirName(info->m_direction)));
01375 }
01376 else {
01377 jumpToScreen(newScreen);
01378 }
01379 }
01380
01381 void
01382 CServer::handleKeyboardBroadcastEvent(const CEvent& event, void*)
01383 {
01384 CKeyboardBroadcastInfo* info = (CKeyboardBroadcastInfo*)event.getData();
01385
01386
01387 bool newState;
01388 switch (info->m_state) {
01389 case CKeyboardBroadcastInfo::kOff:
01390 newState = false;
01391 break;
01392
01393 default:
01394 case CKeyboardBroadcastInfo::kOn:
01395 newState = true;
01396 break;
01397
01398 case CKeyboardBroadcastInfo::kToggle:
01399 newState = !m_keyboardBroadcasting;
01400 break;
01401 }
01402
01403
01404 if (newState != m_keyboardBroadcasting ||
01405 info->m_screens != m_keyboardBroadcastingScreens) {
01406 m_keyboardBroadcasting = newState;
01407 m_keyboardBroadcastingScreens = info->m_screens;
01408 LOG((CLOG_DEBUG "keyboard broadcasting %s: %s", m_keyboardBroadcasting ? "on" : "off", m_keyboardBroadcastingScreens.c_str()));
01409 }
01410 }
01411
01412 void
01413 CServer::handleLockCursorToScreenEvent(const CEvent& event, void*)
01414 {
01415 CLockCursorToScreenInfo* info = (CLockCursorToScreenInfo*)event.getData();
01416
01417
01418 bool newState;
01419 switch (info->m_state) {
01420 case CLockCursorToScreenInfo::kOff:
01421 newState = false;
01422 break;
01423
01424 default:
01425 case CLockCursorToScreenInfo::kOn:
01426 newState = true;
01427 break;
01428
01429 case CLockCursorToScreenInfo::kToggle:
01430 newState = !m_lockedToScreen;
01431 break;
01432 }
01433
01434
01435 if (newState != m_lockedToScreen) {
01436 m_lockedToScreen = newState;
01437 LOG((CLOG_DEBUG "cursor %s current screen", m_lockedToScreen ? "locked to" : "unlocked from"));
01438
01439 m_primaryClient->reconfigure(getActivePrimarySides());
01440 if (!isLockedToScreenServer()) {
01441 stopRelativeMoves();
01442 }
01443 }
01444 }
01445
01446 void
01447 CServer::handleFakeInputBeginEvent(const CEvent&, void*)
01448 {
01449 m_primaryClient->fakeInputBegin();
01450 }
01451
01452 void
01453 CServer::handleFakeInputEndEvent(const CEvent&, void*)
01454 {
01455 m_primaryClient->fakeInputEnd();
01456 }
01457
01458 void
01459 CServer::onClipboardChanged(CBaseClientProxy* sender,
01460 ClipboardID id, UInt32 seqNum)
01461 {
01462 CClipboardInfo& clipboard = m_clipboards[id];
01463
01464
01465 if (seqNum < clipboard.m_clipboardSeqNum) {
01466 LOG((CLOG_INFO "ignored screen \"%s\" update of clipboard %d (missequenced)", getName(sender).c_str(), id));
01467 return;
01468 }
01469
01470
01471 assert(sender == m_clients.find(clipboard.m_clipboardOwner)->second);
01472
01473
01474 sender->getClipboard(id, &clipboard.m_clipboard);
01475
01476
01477 CString data = clipboard.m_clipboard.marshall();
01478 if (data == clipboard.m_clipboardData) {
01479 LOG((CLOG_DEBUG "ignored screen \"%s\" update of clipboard %d (unchanged)", clipboard.m_clipboardOwner.c_str(), id));
01480 return;
01481 }
01482
01483
01484 LOG((CLOG_INFO "screen \"%s\" updated clipboard %d", clipboard.m_clipboardOwner.c_str(), id));
01485 clipboard.m_clipboardData = data;
01486
01487
01488 for (CClientList::const_iterator index = m_clients.begin();
01489 index != m_clients.end(); ++index) {
01490 CBaseClientProxy* client = index->second;
01491 client->setClipboardDirty(id, client != sender);
01492 }
01493
01494
01495 m_active->setClipboard(id, &clipboard.m_clipboard);
01496 }
01497
01498 void
01499 CServer::onScreensaver(bool activated)
01500 {
01501 LOG((CLOG_DEBUG "onScreenSaver %s", activated ? "activated" : "deactivated"));
01502
01503 if (activated) {
01504
01505 m_activeSaver = m_active;
01506 m_xSaver = m_x;
01507 m_ySaver = m_y;
01508
01509
01510 if (m_active != m_primaryClient) {
01511 switchScreen(m_primaryClient, 0, 0, true);
01512 }
01513 }
01514 else {
01515
01516
01517
01518 if (m_activeSaver != NULL && m_activeSaver != m_primaryClient) {
01519
01520 CBaseClientProxy* screen = m_activeSaver;
01521 SInt32 x, y, w, h;
01522 screen->getShape(x, y, w, h);
01523 SInt32 zoneSize = getJumpZoneSize(screen);
01524 if (m_xSaver < x + zoneSize) {
01525 m_xSaver = x + zoneSize;
01526 }
01527 else if (m_xSaver >= x + w - zoneSize) {
01528 m_xSaver = x + w - zoneSize - 1;
01529 }
01530 if (m_ySaver < y + zoneSize) {
01531 m_ySaver = y + zoneSize;
01532 }
01533 else if (m_ySaver >= y + h - zoneSize) {
01534 m_ySaver = y + h - zoneSize - 1;
01535 }
01536
01537
01538 switchScreen(screen, m_xSaver, m_ySaver, false);
01539 }
01540
01541
01542 m_activeSaver = NULL;
01543 }
01544
01545
01546 for (CClientList::const_iterator index = m_clients.begin();
01547 index != m_clients.end(); ++index) {
01548 CBaseClientProxy* client = index->second;
01549 client->screensaver(activated);
01550 }
01551 }
01552
01553 void
01554 CServer::onKeyDown(KeyID id, KeyModifierMask mask, KeyButton button,
01555 const char* screens)
01556 {
01557 LOG((CLOG_DEBUG1 "onKeyDown id=%d mask=0x%04x button=0x%04x", id, mask, button));
01558 assert(m_active != NULL);
01559
01560
01561 if (!m_keyboardBroadcasting ||
01562 (screens && IKeyState::CKeyInfo::isDefault(screens))) {
01563 m_active->keyDown(id, mask, button);
01564 }
01565 else {
01566 if (!screens && m_keyboardBroadcasting) {
01567 screens = m_keyboardBroadcastingScreens.c_str();
01568 if (IKeyState::CKeyInfo::isDefault(screens)) {
01569 screens = "*";
01570 }
01571 }
01572 for (CClientList::const_iterator index = m_clients.begin();
01573 index != m_clients.end(); ++index) {
01574 if (IKeyState::CKeyInfo::contains(screens, index->first)) {
01575 index->second->keyDown(id, mask, button);
01576 }
01577 }
01578 }
01579 }
01580
01581 void
01582 CServer::onKeyUp(KeyID id, KeyModifierMask mask, KeyButton button,
01583 const char* screens)
01584 {
01585 LOG((CLOG_DEBUG1 "onKeyUp id=%d mask=0x%04x button=0x%04x", id, mask, button));
01586 assert(m_active != NULL);
01587
01588
01589 if (!m_keyboardBroadcasting ||
01590 (screens && IKeyState::CKeyInfo::isDefault(screens))) {
01591 m_active->keyUp(id, mask, button);
01592 }
01593 else {
01594 if (!screens && m_keyboardBroadcasting) {
01595 screens = m_keyboardBroadcastingScreens.c_str();
01596 if (IKeyState::CKeyInfo::isDefault(screens)) {
01597 screens = "*";
01598 }
01599 }
01600 for (CClientList::const_iterator index = m_clients.begin();
01601 index != m_clients.end(); ++index) {
01602 if (IKeyState::CKeyInfo::contains(screens, index->first)) {
01603 index->second->keyUp(id, mask, button);
01604 }
01605 }
01606 }
01607 }
01608
01609 void
01610 CServer::onKeyRepeat(KeyID id, KeyModifierMask mask,
01611 SInt32 count, KeyButton button)
01612 {
01613 LOG((CLOG_DEBUG1 "onKeyRepeat id=%d mask=0x%04x count=%d button=0x%04x", id, mask, count, button));
01614 assert(m_active != NULL);
01615
01616
01617 m_active->keyRepeat(id, mask, count, button);
01618 }
01619
01620 void
01621 CServer::onMouseDown(ButtonID id)
01622 {
01623 LOG((CLOG_DEBUG1 "onMouseDown id=%d", id));
01624 assert(m_active != NULL);
01625
01626
01627 m_active->mouseDown(id);
01628 }
01629
01630 void
01631 CServer::onMouseUp(ButtonID id)
01632 {
01633 LOG((CLOG_DEBUG1 "onMouseUp id=%d", id));
01634 assert(m_active != NULL);
01635
01636
01637 m_active->mouseUp(id);
01638 }
01639
01640 bool
01641 CServer::onMouseMovePrimary(SInt32 x, SInt32 y)
01642 {
01643 LOG((CLOG_DEBUG2 "onMouseMovePrimary %d,%d", x, y));
01644
01645
01646 if (m_active != m_primaryClient) {
01647
01648 return false;
01649 }
01650
01651
01652 m_xDelta2 = m_xDelta;
01653 m_yDelta2 = m_yDelta;
01654
01655
01656 m_xDelta = x - m_x;
01657 m_yDelta = y - m_y;
01658
01659
01660 m_x = x;
01661 m_y = y;
01662
01663
01664 SInt32 ax, ay, aw, ah;
01665 m_active->getShape(ax, ay, aw, ah);
01666 SInt32 zoneSize = getJumpZoneSize(m_active);
01667
01668
01669 SInt32 xc = x, yc = y;
01670 if (xc < ax + zoneSize) {
01671 xc = ax;
01672 }
01673 else if (xc >= ax + aw - zoneSize) {
01674 xc = ax + aw - 1;
01675 }
01676 if (yc < ay + zoneSize) {
01677 yc = ay;
01678 }
01679 else if (yc >= ay + ah - zoneSize) {
01680 yc = ay + ah - 1;
01681 }
01682
01683
01684 EDirection dir;
01685 if (x < ax + zoneSize) {
01686 x -= zoneSize;
01687 dir = kLeft;
01688 }
01689 else if (x >= ax + aw - zoneSize) {
01690 x += zoneSize;
01691 dir = kRight;
01692 }
01693 else if (y < ay + zoneSize) {
01694 y -= zoneSize;
01695 dir = kTop;
01696 }
01697 else if (y >= ay + ah - zoneSize) {
01698 y += zoneSize;
01699 dir = kBottom;
01700 }
01701 else {
01702
01703 noSwitch(x, y);
01704 return false;
01705 }
01706
01707
01708 CBaseClientProxy* newScreen = mapToNeighbor(m_active, dir, x, y);
01709
01710
01711 if (isSwitchOkay(newScreen, dir, x, y, xc, yc)) {
01712
01713 switchScreen(newScreen, x, y, false);
01714 return true;
01715 }
01716 else {
01717 return false;
01718 }
01719 }
01720
01721 void
01722 CServer::onMouseMoveSecondary(SInt32 dx, SInt32 dy)
01723 {
01724 LOG((CLOG_DEBUG2 "onMouseMoveSecondary %+d,%+d", dx, dy));
01725
01726
01727 assert(m_active != NULL);
01728 if (m_active == m_primaryClient) {
01729
01730 return;
01731 }
01732
01733
01734
01735
01736
01737
01738
01739 if (m_relativeMoves && isLockedToScreenServer()) {
01740 LOG((CLOG_DEBUG2 "relative move on %s by %d,%d", getName(m_active).c_str(), dx, dy));
01741 m_active->mouseRelativeMove(dx, dy);
01742 return;
01743 }
01744
01745
01746 const SInt32 xOld = m_x;
01747 const SInt32 yOld = m_y;
01748
01749
01750 m_xDelta2 = m_xDelta;
01751 m_yDelta2 = m_yDelta;
01752
01753
01754 m_xDelta = dx;
01755 m_yDelta = dy;
01756
01757
01758 m_x += dx;
01759 m_y += dy;
01760
01761
01762 SInt32 ax, ay, aw, ah;
01763 m_active->getShape(ax, ay, aw, ah);
01764
01765
01766 bool jump = true;
01767 CBaseClientProxy* newScreen;
01768 do {
01769
01770 SInt32 xc = m_x, yc = m_y;
01771 if (xc < ax) {
01772 xc = ax;
01773 }
01774 else if (xc >= ax + aw) {
01775 xc = ax + aw - 1;
01776 }
01777 if (yc < ay) {
01778 yc = ay;
01779 }
01780 else if (yc >= ay + ah) {
01781 yc = ay + ah - 1;
01782 }
01783
01784 EDirection dir;
01785 if (m_x < ax) {
01786 dir = kLeft;
01787 }
01788 else if (m_x > ax + aw - 1) {
01789 dir = kRight;
01790 }
01791 else if (m_y < ay) {
01792 dir = kTop;
01793 }
01794 else if (m_y > ay + ah - 1) {
01795 dir = kBottom;
01796 }
01797 else {
01798
01799 newScreen = m_active;
01800 jump = false;
01801
01802
01803
01804
01805 if (m_switchScreen != NULL) {
01806 bool clearWait;
01807 SInt32 zoneSize = m_primaryClient->getJumpZoneSize();
01808 switch (m_switchDir) {
01809 case kLeft:
01810 clearWait = (m_x >= ax + zoneSize);
01811 break;
01812
01813 case kRight:
01814 clearWait = (m_x <= ax + aw - 1 - zoneSize);
01815 break;
01816
01817 case kTop:
01818 clearWait = (m_y >= ay + zoneSize);
01819 break;
01820
01821 case kBottom:
01822 clearWait = (m_y <= ay + ah - 1 + zoneSize);
01823 break;
01824
01825 default:
01826 clearWait = false;
01827 break;
01828 }
01829 if (clearWait) {
01830
01831 noSwitch(m_x, m_y);
01832 }
01833 }
01834
01835
01836 break;
01837 }
01838
01839
01840 newScreen = mapToNeighbor(m_active, dir, m_x, m_y);
01841
01842
01843 if (!isSwitchOkay(newScreen, dir, m_x, m_y, xc, yc)) {
01844 newScreen = m_active;
01845 jump = false;
01846 }
01847 } while (false);
01848
01849 if (jump) {
01850
01851 switchScreen(newScreen, m_x, m_y, false);
01852 }
01853 else {
01854
01855 m_x = xOld + dx;
01856 m_y = yOld + dy;
01857 if (m_x < ax) {
01858 m_x = ax;
01859 LOG((CLOG_DEBUG2 "clamp to left of \"%s\"", getName(m_active).c_str()));
01860 }
01861 else if (m_x > ax + aw - 1) {
01862 m_x = ax + aw - 1;
01863 LOG((CLOG_DEBUG2 "clamp to right of \"%s\"", getName(m_active).c_str()));
01864 }
01865 if (m_y < ay) {
01866 m_y = ay;
01867 LOG((CLOG_DEBUG2 "clamp to top of \"%s\"", getName(m_active).c_str()));
01868 }
01869 else if (m_y > ay + ah - 1) {
01870 m_y = ay + ah - 1;
01871 LOG((CLOG_DEBUG2 "clamp to bottom of \"%s\"", getName(m_active).c_str()));
01872 }
01873
01874
01875 if (m_x != xOld || m_y != yOld) {
01876 LOG((CLOG_DEBUG2 "move on %s to %d,%d", getName(m_active).c_str(), m_x, m_y));
01877 m_active->mouseMove(m_x, m_y);
01878 }
01879 }
01880 }
01881
01882 void
01883 CServer::onMouseWheel(SInt32 xDelta, SInt32 yDelta)
01884 {
01885 LOG((CLOG_DEBUG1 "onMouseWheel %+d,%+d", xDelta, yDelta));
01886 assert(m_active != NULL);
01887
01888
01889 m_active->mouseWheel(xDelta, yDelta);
01890 }
01891
01892 bool
01893 CServer::addClient(CBaseClientProxy* client)
01894 {
01895 CString name = getName(client);
01896 if (m_clients.count(name) != 0) {
01897 return false;
01898 }
01899
01900
01901 EVENTQUEUE->adoptHandler(IScreen::getShapeChangedEvent(),
01902 client->getEventTarget(),
01903 new TMethodEventJob<CServer>(this,
01904 &CServer::handleShapeChanged, client));
01905 EVENTQUEUE->adoptHandler(IScreen::getClipboardGrabbedEvent(),
01906 client->getEventTarget(),
01907 new TMethodEventJob<CServer>(this,
01908 &CServer::handleClipboardGrabbed, client));
01909 EVENTQUEUE->adoptHandler(CClientProxy::getClipboardChangedEvent(),
01910 client->getEventTarget(),
01911 new TMethodEventJob<CServer>(this,
01912 &CServer::handleClipboardChanged, client));
01913
01914
01915 m_clientSet.insert(client);
01916 m_clients.insert(std::make_pair(name, client));
01917
01918
01919 SInt32 x, y;
01920 client->getCursorPos(x, y);
01921 client->setJumpCursorPos(x, y);
01922
01923
01924 m_primaryClient->reconfigure(getActivePrimarySides());
01925
01926 return true;
01927 }
01928
01929 bool
01930 CServer::removeClient(CBaseClientProxy* client)
01931 {
01932
01933 CClientSet::iterator i = m_clientSet.find(client);
01934 if (i == m_clientSet.end()) {
01935 return false;
01936 }
01937
01938
01939 EVENTQUEUE->removeHandler(IScreen::getShapeChangedEvent(),
01940 client->getEventTarget());
01941 EVENTQUEUE->removeHandler(IScreen::getClipboardGrabbedEvent(),
01942 client->getEventTarget());
01943 EVENTQUEUE->removeHandler(CClientProxy::getClipboardChangedEvent(),
01944 client->getEventTarget());
01945
01946
01947 m_clients.erase(getName(client));
01948 m_clientSet.erase(i);
01949
01950 return true;
01951 }
01952
01953 void
01954 CServer::closeClient(CBaseClientProxy* client, const char* msg)
01955 {
01956 assert(client != m_primaryClient);
01957 assert(msg != NULL);
01958
01959
01960
01961
01962
01963
01964
01965
01966
01967 LOG((CLOG_NOTE "disconnecting client \"%s\"", getName(client).c_str()));
01968
01969
01970
01971 ((CClientProxy*)client)->close(msg);
01972
01973
01974 double timeout = 5.0;
01975 CEventQueueTimer* timer = EVENTQUEUE->newOneShotTimer(timeout, NULL);
01976 EVENTQUEUE->adoptHandler(CEvent::kTimer, timer,
01977 new TMethodEventJob<CServer>(this,
01978 &CServer::handleClientCloseTimeout, client));
01979
01980
01981 removeClient(client);
01982 m_oldClients.insert(std::make_pair(client, timer));
01983
01984
01985
01986 forceLeaveClient(client);
01987 }
01988
01989 void
01990 CServer::closeClients(const CConfig& config)
01991 {
01992
01993
01994 typedef std::set<CBaseClientProxy*> CRemovedClients;
01995 CRemovedClients removed;
01996 for (CClientList::iterator index = m_clients.begin();
01997 index != m_clients.end(); ++index) {
01998 if (!config.isCanonicalName(index->first)) {
01999 removed.insert(index->second);
02000 }
02001 }
02002
02003
02004 removed.erase(m_primaryClient);
02005
02006
02007
02008 for (CRemovedClients::iterator index = removed.begin();
02009 index != removed.end(); ++index) {
02010 closeClient(*index, kMsgCClose);
02011 }
02012 }
02013
02014 void
02015 CServer::removeActiveClient(CBaseClientProxy* client)
02016 {
02017 if (removeClient(client)) {
02018 forceLeaveClient(client);
02019 EVENTQUEUE->removeHandler(CClientProxy::getDisconnectedEvent(), client);
02020 if (m_clients.size() == 1 && m_oldClients.empty()) {
02021 EVENTQUEUE->addEvent(CEvent(getDisconnectedEvent(), this));
02022 }
02023 }
02024 }
02025
02026 void
02027 CServer::removeOldClient(CBaseClientProxy* client)
02028 {
02029 COldClients::iterator i = m_oldClients.find(client);
02030 if (i != m_oldClients.end()) {
02031 EVENTQUEUE->removeHandler(CClientProxy::getDisconnectedEvent(), client);
02032 EVENTQUEUE->removeHandler(CEvent::kTimer, i->second);
02033 EVENTQUEUE->deleteTimer(i->second);
02034 m_oldClients.erase(i);
02035 if (m_clients.size() == 1 && m_oldClients.empty()) {
02036 EVENTQUEUE->addEvent(CEvent(getDisconnectedEvent(), this));
02037 }
02038 }
02039 }
02040
02041 void
02042 CServer::forceLeaveClient(CBaseClientProxy* client)
02043 {
02044 CBaseClientProxy* active =
02045 (m_activeSaver != NULL) ? m_activeSaver : m_active;
02046 if (active == client) {
02047
02048 m_primaryClient->getCursorCenter(m_x, m_y);
02049
02050
02051 if (active == m_switchScreen) {
02052 stopSwitch();
02053 }
02054
02055
02056
02057 LOG((CLOG_INFO "jump from \"%s\" to \"%s\" at %d,%d", getName(active).c_str(), getName(m_primaryClient).c_str(), m_x, m_y));
02058
02059
02060 m_active = m_primaryClient;
02061
02062
02063
02064 if (m_activeSaver == NULL) {
02065 m_primaryClient->enter(m_x, m_y, m_seqNum,
02066 m_primaryClient->getToggleMask(), false);
02067 }
02068 }
02069
02070
02071
02072
02073 if (m_activeSaver == client) {
02074 m_activeSaver = NULL;
02075 }
02076
02077
02078 m_primaryClient->reconfigure(getActivePrimarySides());
02079 }
02080
02081
02082
02083
02084
02085
02086 CServer::CClipboardInfo::CClipboardInfo() :
02087 m_clipboard(),
02088 m_clipboardData(),
02089 m_clipboardOwner(),
02090 m_clipboardSeqNum(0)
02091 {
02092
02093 }
02094
02095
02096
02097
02098
02099
02100 CServer::CLockCursorToScreenInfo*
02101 CServer::CLockCursorToScreenInfo::alloc(State state)
02102 {
02103 CLockCursorToScreenInfo* info =
02104 (CLockCursorToScreenInfo*)malloc(sizeof(CLockCursorToScreenInfo));
02105 info->m_state = state;
02106 return info;
02107 }
02108
02109
02110
02111
02112
02113
02114 CServer::CSwitchToScreenInfo*
02115 CServer::CSwitchToScreenInfo::alloc(const CString& screen)
02116 {
02117 CSwitchToScreenInfo* info =
02118 (CSwitchToScreenInfo*)malloc(sizeof(CSwitchToScreenInfo) +
02119 screen.size());
02120 strcpy(info->m_screen, screen.c_str());
02121 return info;
02122 }
02123
02124
02125
02126
02127
02128
02129 CServer::CSwitchInDirectionInfo*
02130 CServer::CSwitchInDirectionInfo::alloc(EDirection direction)
02131 {
02132 CSwitchInDirectionInfo* info =
02133 (CSwitchInDirectionInfo*)malloc(sizeof(CSwitchInDirectionInfo));
02134 info->m_direction = direction;
02135 return info;
02136 }
02137
02138
02139
02140
02141
02142
02143 CServer::CScreenConnectedInfo*
02144 CServer::CScreenConnectedInfo::alloc(const CString& screen)
02145 {
02146 CScreenConnectedInfo* info =
02147 (CScreenConnectedInfo*)malloc(sizeof(CScreenConnectedInfo) +
02148 screen.size());
02149 strcpy(info->m_screen, screen.c_str());
02150 return info;
02151 }
02152
02153
02154
02155
02156
02157
02158 CServer::CKeyboardBroadcastInfo*
02159 CServer::CKeyboardBroadcastInfo::alloc(State state)
02160 {
02161 CKeyboardBroadcastInfo* info =
02162 (CKeyboardBroadcastInfo*)malloc(sizeof(CKeyboardBroadcastInfo));
02163 info->m_state = state;
02164 info->m_screens[0] = '\0';
02165 return info;
02166 }
02167
02168 CServer::CKeyboardBroadcastInfo*
02169 CServer::CKeyboardBroadcastInfo::alloc(State state, const CString& screens)
02170 {
02171 CKeyboardBroadcastInfo* info =
02172 (CKeyboardBroadcastInfo*)malloc(sizeof(CKeyboardBroadcastInfo) +
02173 screens.size());
02174 info->m_state = state;
02175 strcpy(info->m_screens, screens.c_str());
02176 return info;
02177 }