/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012 Synergy Si Ltd. * Copyright (C) 2002 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file COPYING that should have accompanied this file. * * This package is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergy/App.h" #include "base/Log.h" #include "common/Version.h" #include "synergy/protocol_types.h" #include "arch/Arch.h" #include "base/XBase.h" #include "arch/XArch.h" #include "base/log_outputters.h" #include "synergy/XSynergy.h" #include "synergy/ArgsBase.h" #include "ipc/IpcServerProxy.h" #include "base/TMethodEventJob.h" #include "ipc/IpcMessage.h" #include "ipc/Ipc.h" #include "base/EventQueue.h" #if SYSAPI_WIN32 #include "arch/win32/ArchMiscWindows.h" #include "base/IEventQueue.h" #include "base/TMethodJob.h" #endif #include #include #if WINAPI_CARBON #include #endif #if defined(__APPLE__) #include "platform/OSXDragSimulator.h" #endif App* App::s_instance = nullptr; // // App // App::App(IEventQueue* events, CreateTaskBarReceiverFunc createTaskBarReceiver, ArgsBase* args) : m_bye(&exit), m_taskBarReceiver(NULL), m_suspended(false), m_events(events), m_args(args), m_createTaskBarReceiver(createTaskBarReceiver), m_appUtil(events), m_ipcClient(nullptr) { assert(s_instance == nullptr); s_instance = this; } App::~App() { s_instance = nullptr; delete m_args; } void App::version() { char buffer[500]; sprintf( buffer, "%s %s, protocol version %d.%d\n%s", argsBase().m_pname, kVersion, kProtocolMajorVersion, kProtocolMinorVersion, kCopyright ); std::cout << buffer << std::endl; } int App::run(int argc, char** argv) { #if MAC_OS_X_VERSION_10_7 // dock hide only supported on lion :( ProcessSerialNumber psn = { 0, kCurrentProcess }; #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" GetCurrentProcess(&psn); #pragma GCC diagnostic pop TransformProcessType(&psn, kProcessTransformToBackgroundApplication); #endif // install application in to arch appUtil().adoptApp(this); // HACK: fail by default (saves us setting result in each catch) int result = kExitFailed; try { result = appUtil().run(argc, argv); } catch (XExitApp& e) { // instead of showing a nasty error, just exit with the error code. // not sure if i like this behaviour, but it's probably better than // using the exit(int) function! result = e.getCode(); } catch (std::exception& e) { LOG((CLOG_CRIT "An error occurred: %s\n", e.what())); } catch (...) { LOG((CLOG_CRIT "An unknown error occurred.\n")); } appUtil().beforeAppExit(); return result; } int App::daemonMainLoop(int, const char**) { #if SYSAPI_WIN32 SystemLogger sysLogger(daemonName(), false); #else SystemLogger sysLogger(daemonName(), true); #endif return mainLoop(); } void App::setupFileLogging() { if (argsBase().m_logFile != NULL) { m_fileLog = new FileLogOutputter(argsBase().m_logFile); CLOG->insert(m_fileLog); LOG((CLOG_DEBUG1 "logging to file (%s) enabled", argsBase().m_logFile)); } } void App::loggingFilterWarning() { if (CLOG->getFilter() > CLOG->getConsoleMaxLevel()) { if (argsBase().m_logFile == NULL) { LOG((CLOG_WARN "log messages above %s are NOT sent to console (use file logging)", CLOG->getFilterName(CLOG->getConsoleMaxLevel()))); } } } void App::initApp(int argc, const char** argv) { // parse command line parseArgs(argc, argv); // set log filter if (!CLOG->setFilter(argsBase().m_logFilter)) { LOG((CLOG_PRINT "%s: unrecognized log level `%s'" BYE, argsBase().m_pname, argsBase().m_logFilter, argsBase().m_pname)); m_bye(kExitArgs); } loggingFilterWarning(); if (argsBase().m_enableDragDrop) { LOG((CLOG_INFO "drag and drop enabled")); } // setup file logging after parsing args setupFileLogging(); // load configuration loadConfig(); if (!argsBase().m_disableTray) { // create a log buffer so we can show the latest message // as a tray icon tooltip BufferedLogOutputter* logBuffer = new BufferedLogOutputter(1000); CLOG->insert(logBuffer, true); // make the task bar receiver. the user can control this app // through the task bar. m_taskBarReceiver = m_createTaskBarReceiver(logBuffer, m_events); } } void App::initIpcClient() { m_ipcClient = new IpcClient(m_events, m_socketMultiplexer); m_ipcClient->connect(); m_events->adoptHandler( m_events->forIpcClient().messageReceived(), m_ipcClient, new TMethodEventJob(this, &App::handleIpcMessage)); } void App::cleanupIpcClient() { m_ipcClient->disconnect(); m_events->removeHandler(m_events->forIpcClient().messageReceived(), m_ipcClient); delete m_ipcClient; } void App::handleIpcMessage(const Event& e, void*) { IpcMessage* m = static_cast(e.getDataObject()); if (m->type() == kIpcShutdown) { LOG((CLOG_INFO "got ipc shutdown message")); m_events->addEvent(Event(Event::kQuit)); } } void App::runEventsLoop(void*) { m_events->loop(); #if defined(MAC_OS_X_VERSION_10_7) stopCocoaLoop(); #endif } // // MinimalApp // MinimalApp::MinimalApp() : App(NULL, NULL, new ArgsBase()) { setEvents(m_events); } MinimalApp::~MinimalApp() { } int MinimalApp::standardStartup(int argc, char** argv) { return 0; } int MinimalApp::runInner(int argc, char** argv, ILogOutputter* outputter, StartupFunc startup) { return 0; } void MinimalApp::startNode() { } int MinimalApp::mainLoop() { return 0; } int MinimalApp::foregroundStartup(int argc, char** argv) { return 0; } Screen* MinimalApp::createScreen() { return NULL; } void MinimalApp::loadConfig() { } bool MinimalApp::loadConfig(const String& pathname) { return false; } const char* MinimalApp::daemonInfo() const { return ""; } const char* MinimalApp::daemonName() const { return ""; } void MinimalApp::parseArgs(int argc, const char* const* argv) { }