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