int CClientApp::mainLoop() { // create socket multiplexer. this must happen after daemonization // on unix because threads evaporate across a fork(). CSocketMultiplexer multiplexer; // create the event queue CEventQueue eventQueue; // start client, etc ARCH->util().startNode(); // run event loop. if startClient() failed we're supposed to retry // later. the timer installed by startClient() will take care of // that. CEvent event; DAEMON_RUNNING(true); EVENTQUEUE->getEvent(event); while (event.getType() != CEvent::kQuit) { EVENTQUEUE->dispatchEvent(event); CEvent::deleteData(event); EVENTQUEUE->getEvent(event); } DAEMON_RUNNING(false); // close down LOG((CLOG_DEBUG1 "stopping client")); stopClient(); updateStatus(); LOG((CLOG_NOTE "stopped client")); return kExitSuccess; }
void CEventQueue::addEvent(const CEvent& event) { // discard bogus event types switch (event.getType()) { case CEvent::kUnknown: case CEvent::kSystem: case CEvent::kTimer: return; default: break; } if ((event.getFlags() & CEvent::kDeliverImmediately) != 0) { dispatchEvent(event); CEvent::deleteData(event); } else { CArchMutexLock lock(m_mutex); // store the event's data locally UInt32 eventID = saveEvent(event); // add it if (!m_buffer->addEvent(eventID)) { // failed to send event removeEvent(eventID); CEvent::deleteData(event); } } }
CInputFilter::EFilterStatus CInputFilter::CMouseButtonCondition::match(const CEvent& event) { static const KeyModifierMask s_ignoreMask = KeyModifierAltGr | KeyModifierCapsLock | KeyModifierNumLock | KeyModifierScrollLock; EFilterStatus status; // check for hotkey events CEvent::Type type = event.getType(); if (type == IPrimaryScreen::getButtonDownEvent()) { status = kActivate; } else if (type == IPrimaryScreen::getButtonUpEvent()) { status = kDeactivate; } else { return kNoMatch; } // check if it's the right button and modifiers. ignore modifiers // that cannot be combined with a mouse button. IPlatformScreen::CButtonInfo* minfo = reinterpret_cast<IPlatformScreen::CButtonInfo*>(event.getData()); if (minfo->m_button != m_button || (minfo->m_mask & ~s_ignoreMask) != m_mask) { return kNoMatch; } return status; }
void CInputFilter::sendEvent(CEvent& event) { CEvent::Type type = event.getType(); // process keyboard modifiers here if (type == IPlatformScreen::getKeyDownEvent() || type == IPlatformScreen::getKeyUpEvent() || type == IPlatformScreen::getKeyRepeatEvent()) { // get CKeyInfo from event IPlatformScreen::CKeyInfo* kinfo = reinterpret_cast<IPlatformScreen::CKeyInfo*>(event.getData()); // save mask m_lastMask = kinfo->m_mask; // prepare new mask KeyModifierMask newMask = kinfo->m_mask; updateModifiers(); newMask &= ~m_clearMask; newMask |= m_modifierMask; // set new mask kinfo->m_mask = newMask; } // add event to eventqueue EVENTQUEUE->addEvent(event); }
void CServerApp::closeServer(CServer* server) { if (server == NULL) { return; } // tell all clients to disconnect server->disconnect(); // wait for clients to disconnect for up to timeout seconds double timeout = 3.0; CEventQueueTimer* timer = EVENTQUEUE->newOneShotTimer(timeout, NULL); EVENTQUEUE->adoptHandler(CEvent::kTimer, timer, new TMethodEventJob<CServerApp>(this, &CServerApp::handleClientsDisconnected)); EVENTQUEUE->adoptHandler(CServer::getDisconnectedEvent(), server, new TMethodEventJob<CServerApp>(this, &CServerApp::handleClientsDisconnected)); CEvent event; EVENTQUEUE->getEvent(event); while (event.getType() != CEvent::kQuit) { EVENTQUEUE->dispatchEvent(event); CEvent::deleteData(event); EVENTQUEUE->getEvent(event); } EVENTQUEUE->removeHandler(CEvent::kTimer, timer); EVENTQUEUE->deleteTimer(timer); EVENTQUEUE->removeHandler(CServer::getDisconnectedEvent(), server); // done with server delete server; }
CInputFilter::EFilterStatus CInputFilter::CKeystrokeCondition::match(CEvent& event, void*, EActionMode& outMode) { // check for hotkey events CEvent::Type type = event.getType(); if (type == IPrimaryScreen::getHotKeyDownEvent()) { outMode = kModeTurnOn; } else if (type == IPrimaryScreen::getHotKeyUpEvent()) { outMode = kModeTurnOff; } else { return kNoMatch; } // check if it's our hotkey IPrimaryScreen::CHotKeyInfo* kinfo = reinterpret_cast<IPlatformScreen::CHotKeyInfo*>(event.getData()); if (kinfo->m_id != m_id) { return kNoMatch; } // convert event type for toggled conditions if (getActionMode() != kModePass) { if (type != IPlatformScreen::getHotKeyDownEvent()) { return kDiscard; } outMode = getActionMode(); } return kMatch; }
CInputFilter::EFilterStatus CInputFilter::CKeystrokeCondition::match(const CEvent& event) { EFilterStatus status; // check for hotkey events CEvent::Type type = event.getType(); if (type == IPrimaryScreen::getHotKeyDownEvent()) { status = kActivate; } else if (type == IPrimaryScreen::getHotKeyUpEvent()) { status = kDeactivate; } else { return kNoMatch; } // check if it's our hotkey IPrimaryScreen::CHotKeyInfo* kinfo = reinterpret_cast<IPlatformScreen::CHotKeyInfo*>(event.getData()); if (kinfo->m_id != m_id) { return kNoMatch; } return status; }
static int mainLoop() { // logging to files CFileLogOutputter* fileLog = NULL; if (ARG->m_logFile != NULL) { fileLog = new CFileLogOutputter(ARG->m_logFile); CLOG->insert(fileLog); LOG((CLOG_DEBUG1 "Logging to file (%s) enabled", ARG->m_logFile)); } // create socket multiplexer. this must happen after daemonization // on unix because threads evaporate across a fork(). CSocketMultiplexer multiplexer; // create the event queue CEventQueue eventQueue; // start the client. if this return false then we've failed and // we shouldn't retry. LOG((CLOG_DEBUG1 "starting client")); if (!startClient()) { return kExitFailed; } // run event loop. if startClient() failed we're supposed to retry // later. the timer installed by startClient() will take care of // that. CEvent event; DAEMON_RUNNING(true); EVENTQUEUE->getEvent(event); while (event.getType() != CEvent::kQuit) { EVENTQUEUE->dispatchEvent(event); CEvent::deleteData(event); EVENTQUEUE->getEvent(event); } DAEMON_RUNNING(false); // close down LOG((CLOG_DEBUG1 "stopping client")); stopClient(); updateStatus(); LOG((CLOG_NOTE "stopped client")); if (fileLog) { CLOG->remove(fileLog); delete fileLog; } return kExitSuccess; }
void CEventQueue::loop() { CEvent event; getEvent(event); while (event.getType() != CEvent::kQuit) { dispatchEvent(event); CEvent::deleteData(event); getEvent(event); } }
void CPacketStreamFilter::filterEvent(const CEvent& event) { if (event.getType() == getInputReadyEvent()) { CLock lock(&m_mutex); if (!readMore()) { return; } } else if (event.getType() == getInputShutdownEvent()) { // discard this if we have buffered data CLock lock(&m_mutex); m_inputShutdown = true; if (m_size != 0) { return; } } // pass event CStreamFilter::filterEvent(event); }
CInputFilter::EFilterStatus CInputFilter::CScreenConnectedCondition::match(const CEvent& event) { if (event.getType() == CServer::getConnectedEvent()) { CServer::CScreenConnectedInfo* info = reinterpret_cast<CServer::CScreenConnectedInfo*>(event.getData()); if (m_screen == info->m_screen || m_screen.empty()) { return kActivate; } } return kNoMatch; }
void CDaemonApp::mainLoop(bool logToFile) { try { DAEMON_RUNNING(true); if (logToFile) CLOG->insert(new CFileLogOutputter(logPath().c_str())); CEventQueue eventQueue; #if SYSAPI_WIN32 // HACK: create a dummy screen, which can handle system events // (such as a stop request from the service controller). CMSWindowsScreen::init(CArchMiscWindows::instanceWin32()); CScreen dummyScreen(new CMSWindowsScreen(false, true, false)); string command = ARCH->setting("Command"); if (command != "") { LOG((CLOG_INFO "using last known command: %s", command.c_str())); m_relauncher.command(command); } m_relauncher.startAsync(); #endif CEvent event; EVENTQUEUE->getEvent(event); while (event.getType() != CEvent::kQuit) { EVENTQUEUE->dispatchEvent(event); CEvent::deleteData(event); EVENTQUEUE->getEvent(event); } #if SYSAPI_WIN32 m_relauncher.stop(); #endif DAEMON_RUNNING(false); } catch (XArch& e) { LOG((CLOG_ERR, e.what().c_str())); } catch (std::exception& e) { LOG((CLOG_ERR, e.what())); } catch (...) { LOG((CLOG_ERR, "Unrecognized error.")); } }
bool CEventQueue::dispatchEvent(const CEvent& event) { void* target = event.getTarget(); IEventJob* job = getHandler(event.getType(), target); if (job == NULL) { job = getHandler(CEvent::kUnknown, target); } if (job != NULL) { job->run(event); return true; } return false; }
void CEvent::deleteData(const CEvent& event) { switch (event.getType()) { case kUnknown: case kQuit: case kSystem: case kTimer: break; default: free(event.getData()); break; } }
void CInputFilter::handleEvent(const CEvent& event, void* arg) { // get a modifiable copy of this event. // set target to us, set kDontFreeData and kDeliverImmediately because the // original event will be destroyed after this method exits. CEvent evt(event.getType(), this, event.getData(), event.getFlags() | CEvent::kDontFreeData | CEvent::kDeliverImmediately); // clear dirty flag m_dirtyFlag = kNotDirty; EActionMode actionMode = kModePass; // match event against filter rules and perform actions for (CRuleList::iterator rule = m_ruleList.begin(); rule != m_ruleList.end(); ++rule) { EFilterStatus conditionStatus; EFilterStatus actionStatus; conditionStatus = rule->first->match(evt, arg, actionMode); if (conditionStatus == kDiscard) { return; } else if (conditionStatus == kNoMatch) { continue; } actionStatus = rule->second->perform(evt, arg, actionMode); if (actionStatus == kDiscard) { // discard event return; } else if (actionStatus == kNotHandled) { continue; } else if (actionStatus == kUpdateModifiers) { updateModifiers(); return; } // if we got here then the rule has matched and action returned // kHandled, so send the event. break; } sendEvent(evt); }
void CEvent::deleteData(const CEvent& event) { switch (event.getType()) { case kUnknown: case kQuit: case kSystem: case kTimer: break; default: if ((event.getFlags() & kDontFreeData) == 0) { free(event.getData()); delete event.getDataObject(); } break; } }
void CInputFilter::CSwitchToScreenAction::perform(const CEvent& event) { // pick screen name. if m_screen is empty then use the screen from // event if it has one. CString screen = m_screen; if (screen.empty() && event.getType() == CServer::getConnectedEvent()) { CServer::CScreenConnectedInfo* info = reinterpret_cast<CServer::CScreenConnectedInfo*>(event.getData()); screen = info->m_screen; } // send event CServer::CSwitchToScreenInfo* info = CServer::CSwitchToScreenInfo::alloc(screen); EVENTQUEUE->addEvent(CEvent(CServer::getSwitchToScreenEvent(), event.getTarget(), info, CEvent::kDeliverImmediately)); }
void CInputFilter::handleEvent(const CEvent& event, void*) { // copy event and adjust target CEvent myEvent(event.getType(), this, event.getData(), event.getFlags() | CEvent::kDontFreeData | CEvent::kDeliverImmediately); // let each rule try to match the event until one does for (CRuleList::iterator rule = m_ruleList.begin(); rule != m_ruleList.end(); ++rule) { if (rule->handleEvent(myEvent)) { // handled return; } } // not handled so pass through EVENTQUEUE->addEvent(myEvent); }
CInputFilter::EFilterStatus CInputFilter::CMouseButtonCondition::match(CEvent& event, void*, EActionMode& outMode) { // check for hotkey events bool down; CEvent::Type type = event.getType(); if (type == IPrimaryScreen::getButtonDownEvent()) { outMode = kModeTurnOn; down = true; } else if (type == IPrimaryScreen::getButtonUpEvent()) { outMode = kModeTurnOff; down = false; } else { return kNoMatch; } // check if it's the right button and modifiers IPlatformScreen::CButtonInfo* minfo = reinterpret_cast<IPlatformScreen::CButtonInfo*>(event.getData()); if (minfo->m_button != m_button || getLastMask() != m_mask) { return kNoMatch; } // convert event type for toggled conditions if (getActionMode() != kModePass) { if (type != IPlatformScreen::getButtonDownEvent()) { return kDiscard; } outMode = getActionMode(); } setClearMask(down ? m_mask : 0); return kMatch; }
void CStreamFilter::filterEvent(const CEvent& event) { EVENTQUEUE->dispatchEvent(CEvent(event.getType(), getEventTarget(), event.getData())); }
int CServerApp::mainLoop() { // create socket multiplexer. this must happen after daemonization // on unix because threads evaporate across a fork(). CSocketMultiplexer multiplexer; // create the event queue CEventQueue eventQueue; // if configuration has no screens then add this system // as the default if (args().m_config->begin() == args().m_config->end()) { args().m_config->addScreen(args().m_name); } // set the contact address, if provided, in the config. // otherwise, if the config doesn't have an address, use // the default. if (args().m_synergyAddress->isValid()) { args().m_config->setSynergyAddress(*args().m_synergyAddress); } else if (!args().m_config->getSynergyAddress().isValid()) { args().m_config->setSynergyAddress(CNetworkAddress(kDefaultPort)); } // canonicalize the primary screen name CString primaryName = args().m_config->getCanonicalName(args().m_name); if (primaryName.empty()) { LOG((CLOG_CRIT "unknown screen name `%s'", args().m_name.c_str())); return kExitFailed; } // start server, etc ARCH->util().startNode(); // handle hangup signal by reloading the server's configuration ARCH->setSignalHandler(CArch::kHANGUP, &reloadSignalHandler, NULL); EVENTQUEUE->adoptHandler(getReloadConfigEvent(), IEventQueue::getSystemTarget(), new TMethodEventJob<CServerApp>(this, &CServerApp::reloadConfig)); // handle force reconnect event by disconnecting clients. they'll // reconnect automatically. EVENTQUEUE->adoptHandler(getForceReconnectEvent(), IEventQueue::getSystemTarget(), new TMethodEventJob<CServerApp>(this, &CServerApp::forceReconnect)); // to work around the sticky meta keys problem, we'll give users // the option to reset the state of synergys EVENTQUEUE->adoptHandler(getResetServerEvent(), IEventQueue::getSystemTarget(), new TMethodEventJob<CServerApp>(this, &CServerApp::resetServer)); // run event loop. if startServer() failed we're supposed to retry // later. the timer installed by startServer() will take care of // that. CEvent event; DAEMON_RUNNING(true); EVENTQUEUE->getEvent(event); while (event.getType() != CEvent::kQuit) { EVENTQUEUE->dispatchEvent(event); CEvent::deleteData(event); EVENTQUEUE->getEvent(event); } DAEMON_RUNNING(false); // close down LOG((CLOG_DEBUG1 "stopping server")); EVENTQUEUE->removeHandler(getForceReconnectEvent(), IEventQueue::getSystemTarget()); EVENTQUEUE->removeHandler(getReloadConfigEvent(), IEventQueue::getSystemTarget()); cleanupServer(); updateStatus(); LOG((CLOG_NOTE "stopped server")); return kExitSuccess; }